0

I was trying to initialize and print array of pointers to integers. Is this method of initialization is correct or any other method is available to initialize when we declare it as array of pointers. We can also use traditional array of arrays ar1[][] anyway.

#include <stdio.h>
#include <stdlib.h>

#define NUM_COLS 4
#define NUM_ROWS 3

int main(void)
{
    int rowCnt;
    int colCnt;

    int *ar2[NUM_ROWS]={
                    (int[]){11,12,13,14},
                    (int[]){21,22,23,24},
                    (int[]){31,32,33,34},
                    };

    for(rowCnt=0;rowCnt<NUM_ROWS;rowCnt++)
    {
        for(colCnt=0;colCnt<NUM_COLS;colCnt++)
        {
            printf("%d\t",*(*(ar2+rowCnt)+colCnt));
        }
        printf("\n");
    }
    return(0);
}
Rajesh
  • 1,085
  • 1
  • 12
  • 25
  • What makes you think it is not correct? – Scott Hunter Jun 26 '18 at 02:43
  • I can't reproduce the issue you're reporting on my system under valgrind. What specific error are you getting? – templatetypedef Jun 26 '18 at 02:43
  • 1
    NUM_COLS is 4 and you initialized only three columns. – jwdonahue Jun 26 '18 at 02:45
  • I did not have any issue and code works fine. Only my point here is typecasting to (int[]){} is needed while initializing and wanted to know if any alternate methods are available – Rajesh Jun 26 '18 at 02:49
  • @Rajesh there is no type cast, this is a compound literal. A typecast has a typename in parentheses *followed by an expression*. – M.M Jun 26 '18 at 03:27
  • @jwdonahue : Yes, it is a mistake and it should be NUM_ROWS. Thanks for correcting. Updating the post. – Rajesh Jun 26 '18 at 17:48

3 Answers3

1

Since you know the number of rows and colums, you can define a 2D array (formally an array of arrays) instead of an array of pointers:

int ar2[NUM_ROWS][NUM_COLS]={
    {11,12,13,14},
    {21,22,23,24},
    {31,32,33,34},
};
dbush
  • 205,898
  • 23
  • 218
  • 273
  • I agree and indicated in original post that we could use traditional method anyway. Mainly wanted to know if my method is correct or not. I had searched a bit, but could not see this style of initializing but found to be working in my case – Rajesh Jun 26 '18 at 17:54
1

This declaration below is incorrect.

int *ar2[NUM_COLS]={
                (int[]){11,12,13,14},
                (int[]){21,22,23,24},
                (int[]){31,32,33,34},
                };

This is an array of NUM_COLS of pointers to ints. The memory of these pointers to ints do not get properly allocated this way, and will result in undefined behavior.

If you wanted to allocate the entire array on the stack, you could do something like this:

int ar2[NUM_ROWS][NUM_COLS]= {
    {11,12,13,14},
    {21,22,23,24},
    {31,32,33,34},
    {0,0,0,0}
};

If you want the pointers to ints to be properly on the heap, you should use malloc/free respectively

int *ar2[NUM_ROWS];

for (int i = 0; i < NUM_ROWS; ++i)
{
   ar2[i] = (int*)malloc(sizeof(int) * NUM_COLS);
}

///now you can set up your arrays
memcpy(ar2[0], (int []){11,12,13,14}, 4 * sizeof(int));
memcpy(ar2[1], (int []){21,22,23,24}, 4 * sizeof(int));
memcpy(ar2[2], (int []){31,32,33,34}, 4 * sizeof(int));

///Do what you want with the array
...

///Free array once you are done
for (int i = 0; i < NUM_ROWS; ++i)
{
    free(ar2[i]);
}
Ilan Keshet
  • 514
  • 5
  • 19
  • The original code is correct (although not great style), the storage duration of compound literals at block scope is the scope of the innermost enclosing block (i.e. the same scope as `ar2` in this case). Also, don't cast malloc – M.M Jun 26 '18 at 03:26
  • @M.M Isn't the storage duration of the compound literals in the OP's code restricted to the innermost enclosing block = the initializer list where they are present? If so, this answer is correct in that regard - the allocation isn't done "properly" as the compound literals would immediately go out of scope. – Lundin Jun 26 '18 at 11:27
  • Why no warning is generated in GCC if the result is undefined? I am using MnGW32. – Rajesh Jun 26 '18 at 18:01
  • @Lundin braced initializer lists aren't blocks – M.M Jun 26 '18 at 21:07
  • @M.M: I think you should consolidate and conclude with separate answer so that it can be accepted. Looking at https://stackoverflow.com/questions/36676149/why-are-compound-literals-in-c-modifiable, it looks like compound literals can be lvalues and hence it looks like OP's code is valid. Very limited posts are there on web related to this type form of initialization and I guess this post can be a good reference interlinking array of pointer initialization and compound literal concepts. – Rajesh Jun 27 '18 at 01:41
1

This initialization is correct; compound literals have lifetime to match the block they are declared in. The literals have the same lifetime as ar2 in this case.

However I would recommend using a simple array as in dbush's answer unless you have some extra requirement (such as wanting rows of differing lengths).

M.M
  • 138,810
  • 21
  • 208
  • 365