Search code examples
arrayscpointersdereference

Accessing array of pointers vs accessing pointer with multiple 'elements'?


Hi I am new to C and am trying to understand the nuance between pointers and arrays. Specifically I don't understand what fundamentally distinguishes the following two objects:

int *obj1[N];
int *obj2;
obj2 = malloc(N*sizeof(int))

Both objects provide me essentially an array of pointers but I would reference them differently to retrieve the values they point to:

val1 = *obj1[i];
val2 = obj2[i];

I consider both of them in end effect 'arrays of pointers' (though I understand the use of the word 'array' for the obj2 is not technically correct), however obj2 seems to implicitly recognize that I want the value without the need to dereference with * while obj1 doesn't. Could someone clarify for me the structural difference between these two objects which leads to the above difference in referencing their values?


Solution

  • This declaration

    int *obj1[N];
    

    indeed declares an array of objects of the pointer type int *.

    This declaration

    int *obj2;
    

    declares an object of the type int * and in the next statement

    obj2 = malloc(N*sizeof(int));
    

    there is allocated memory for an array of N elements of the type int.

    So in this lines

    val1 = *obj1[i];
    val2 = obj2[i];
    

    that for clarity are better to rewrite like

    int val1 = *obj1[i];
    int val2 = obj2[i];
    

    you get objects of the type int. In the first line the expression obj1[i] yields an object of the type int * because obj1 is an array of pointer. So to get the pointed object of the type int you need to dereference the pointer expression obj1[i]. In the second line the expression obj2[i] yields an object of the type int because there was allocated an array of integers.

    If you want to allocate an array of pointers of the type int * you have to write

    int **obj2 = malloc(N*sizeof(int *));
    

    In this case to access elements of the both arrays you can write

    int val1 = *obj1[i];
    int val2 = *obj2[i];
    

    Pay attention to that in this expression obj1[i] the array designator obj1 is implicitly converted to a pointer of the type int ** to its first element. So the both expressions obj1[i] and obj2[i] are equivalently evaluated. Also the both expressions *obj1[i] and *obj2[i] are equivalent to obj1[i][0] and obj2[i][0].

    On the other hand, you could also write for example

    int **obj3 = obj1;  // the array is implicitly converted to pointer
    //...
    int val3 = *obj3[i];
    

    Bear in mind that according to the C Standard (6.5.2.1 Array subscripting)

    2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero)