How do square brackets work in C?

24,893

Solution 1

I have not explicitly declared int *a as a pointer to an array, but if I allocate it some memory, I can then use a like I had declared it as an array. Is declaring a pointer with square brackets just a shortcut for what I've done below?

Similar, but no. int *a declares a as pointer to int. int b[5] allocates space for 5 ints, declares b as constant pointer to int an array-of-int reference (which can in most cases be treated as a constant pointer to int), and defines b to be the pointer to the allocated space. Thus, int b[5] is doing way more than int *a, which also means int *a is more flexible than int b[5]. For example, you can increment a, but not b.

malloc allocates memory on heap. int b[5], if a global variable, will be in the program's data segment (i.e. it is literally compiled into the executable). If local, it will be allocated on stack. Again, similar, but different.

Are square brackets actually doing some pointer arithmetic?

In declaration, no. When you use pointer variables, yes: x[y] is identical to *(x + y). So a[1] is the same as *(a + 1), which is the same as *(1 + a), which is again the same as 1[a] (but please don't use this last one).

Why is the memory address assigned to a and not *a?

Cheeky answer for a cheeky question: Because you wrote a = ... and not *a = ....

EDIT: John Bode gave a useful pointer (heh): constant pointers and array references are not the same thing, although they are pretty damn similar. For one thing, sizeof(...) will give a different result.

Solution 2

Are square brackets actually doing some pointer arithmetic?

Yes. Brackets can be applied to any pointer, not just arrays. They provide a shorthand for pointer arithmetic and pointer dereferencing. Your code is essentially doing this:

int *a = malloc(5 * sizeof(int));

*(a+2) = 4;

printf("%d\n", *(a+0));
printf("%d\n", *(a+2));

Which is actually doing the equivalent of this:

int *a = malloc(5 * sizeof(int));

*((int*)(((unsigned long)a)+(2*sizeof(int)))) = 4;

printf("%d\n", *((int*)(((unsigned long)a)+(0*sizeof(int)))));
printf("%d\n", *((int*)(((unsigned long)a)+(2*sizeof(int)))));

Solution 3

Are square brackets actually doing some pointer arithmetic?

a[b] is equivalent to *(a + b). So yes, it's pointer arithmetic. It first offsets the pointer by b and then accesses that memory location, just like an array.

Why is the memory address assigned to a and not *a?

The memory address is stored in a because a is the pointer and pointers store memory addresses. *a is the data at that memory address.

Solution 4

Is declaring a pointer with square brackets just a shortcut for what I've done below?

Of course not! An array and a pointer are two completely different things. int a[5];, here a is of type int[5] while in int *b; b's type is int*. Former decays into latter in many circumstances. This is called arry decaying. Read more about it here.

Are square brackets actually doing some pointer arithmetic?

Yes, when you do a[3] what really happens is *(a + 3) i.e. a decays into int* and the rest is just pointer arithmetic i.e. to the address of the first element of a, 3 * sizeof(int) is added.

Why is the memory address assigned to a and not *a?

I think you're confusing between an identifier and an operator applied to a variable. A pointer is just another variable; all variable names should follow the rules of an identifier i.e. from the standard:

An identifier is an arbitrarily long sequence of letters and digits.

While the operator * dereferences the pointer to which it is applied and returns a result based on the pointer type. So the memory address is always assigned to a, the variable. The value at the memory address pointed-to by a would always be referred to by *a.

Share:
24,893
oorst
Author by

oorst

Always learning.

Updated on April 16, 2020

Comments

  • oorst
    oorst about 4 years

    I've just started with C and I'm trying to understand the basics. Plenty of tutorials will tell you things and have you believe it without any real explanation and there are no answers on that I can find that are human readable.

    In the following:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
      int *a;
    
      a = malloc(5 * sizeof(int));
    
      a[2] = 4;
    
      printf("%d\n", a[0]); // Prints 0
      printf("%d\n", a[2]); // Prints 4
    
      return 0;
    } 
    

    I have not explicitly declared int *a as a pointer to an array, but if I allocate it some memory, I can then use a like I had declared it as an array. Is declaring a pointer with square brackets just a shortcut for what I've done below? Are square brackets actually doing some pointer arithmetic?

    Cheeky Second question

    Why is the memory address assigned to a and not *a?