el psy Congroo
el psy Congroo

Reputation: 361

Subtle Concept of pointers and array

I have a very strange example of pointers, which requires your kind help. In general, pointers are used to point to a variable (see first example below), but when it points to an array. I don't understand why it no longer requires deferencing to obtain the array (see second example below)

printf("TEST: %i\n", x[i]);// I expect this should be *x[i]

This is indeed very strange. Is it just a C convention or how do you explain this?

EDIT::Since many have provided a clear answer, I want to include another small follow up question, as all of you mentioned x[i] = *(x+i), what about x[i][j] for a 2 dimensional array? what is it equivalent to ? Does it require dereferencing?

With a normal variable

int j = 4;
int* pointerj=&j;//pointerj holds address of j or points to j
printf("%d",*pointerj); returns the value that pointer j points to 

With an array :

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

int *function(unsigned int tags) {
    int i;
    int *var;

    var = (int*)malloc(sizeof(int)*tags); // malloc is casted to int* type , allocated dynamical memory, it returns a pointer!
    //so now var holds the address to a dynamical array.

    for (i = 0; i < tags; i++) {
        var[i] = i;
    }

    return var;
}

int main() {
    int *x;
    int i;

    x = function(10);
    for (i = 0; i < 10; i++) {
        printf("TEST: %i\n", x[i]);// I expect this should be *x[i]
    }

    free(x); x = NULL;

    return 0;
}

Upvotes: 0

Views: 110

Answers (5)

Sourav Ghosh
Sourav Ghosh

Reputation: 134336

don't understand why it no longer requires dereferencing to obtain the array (element)

Well, you are dereferencing, it's just not using the dereference operator *.

The array subscripting operator [] is serving as job of dereferencing here. quoting C11, chapter §6.5.2.1

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).

It's a syntactic sugar. The expressions x[i] and *(x+i) are equivalent. The later satisfies your expectation, whereas, the first one, disguises the dereference operator, but does the exact same job you expected.


That said, also follow the data type closely. What you were expecting, something along the line of *x[i] would be plain invalid, as it boils down to something like `((x+i) ). Now,

  • x is of type int [] (integer array, which decays to a pointer to integer)
  • x+i gives you a pointer to int type result.
  • the inner dereference operator is applied to it, resulting an int.
  • The outer *, now will try to operate on an operand of type int (not a pointer), and, this operation will be a syntactical error, as, the constraint for dereference operator says,

The operand of the unary * operator shall have pointer type.

in C11, chapter §6.5.3.2.


Answering the additional question:

Let me use the quote, once again, this one's from paragraph 2, chapter §6.5.2.1

Successive subscript operators designate an element of a multidimensional array object. If E is an n-dimensional array (n ≥ 2) with dimensions i × j × . . . × k, then E (used as other than an lvalue) is converted to a pointer to an (n − 1)-dimensional array with dimensions j × . . . × k. If the unary * operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the referenced (n − 1)-dimensional array, which itself is converted into a pointer if used as other than an lvalue. It follows from this that arrays are stored in row-major order (last subscript varies fastest).

Consider the array object defined by the declaration

  int x[3][5];

Here x is a 3 × 5 array of ints; more precisely, x is an array of three element objects, each of which is an array of five ints. In the expression x[i], which is equivalent to (*((x)+(i))), x is first converted to a pointer to the initial array of five ints. Then i is adjusted according to the type of x, which conceptually entails multiplying i by the size of the object to which the pointer points, namely an array of five int objects. The results are added and indirection is applied to yield an array of five ints. When used in the expression x[i][j], that array is in turn converted to a pointer to the first of the ints, so x[i][j] yields an int.

Upvotes: 4

Nihal Saxena
Nihal Saxena

Reputation: 996

the simple answer to your question is that :

The name of array is pointer to first element of array.

Upvotes: 1

CIsForCookies
CIsForCookies

Reputation: 12817

You misunderstood how arrays work. Indeed, when using a variable such as int you should access it's address by

int x; int *p2x = &x

but when using array, it's a bit different. int y[SOME_SIZE]; is a chunk of bytes in the memory, and *y will take you to the first element in that memory location, and dereference it. y[0] will do the same. *y[0] will first take the value in y[0] and then will try to dereference it... not what you usually want :(

Upvotes: 1

Gaulois94
Gaulois94

Reputation: 159

In C, doing x[i] is equivalent (yeah I know) at i[x]. Your compiler compiles this by doing :

*(x+i), where you retrieve your favorite symbole.

x+i is a pointer where you start from x and advance by i. The result takes account of the type of the pointer (0xff is not the same address for a char* than for a int*).

Upvotes: 1

unalignedmemoryaccess
unalignedmemoryaccess

Reputation: 7441

This is ok. No * there.

If you have pointer int *a which points to array of valid data, for example:

int *a;
int arr[5] = {1, 2, 3, 4, 5];
a = arr;

By using a[0] you are already dereferencing pointer and * is not required as a[0] is the same as *(a + 0).


You can go further and even more complicate code for readers.

You may use i[x] in your example instead of x[i]. Why? x[i] is equal to *(x + i) but it is also equivalent to *(i + x) which is what arrays are in C.

It works even with numbers, such as x[3] or 3[x] will give you the same result.

Upvotes: 1

Related Questions