0

The code below takes the address of var1, then put it to p.

int var1;
int *p;
p = &var1;

Q1: Does it mean that CPU creates a space for putting address of var1 (due to address operator), then gives it to p?


Both codes below do the same thing except for the first one creating one more variable p to store address of A.

first:

int A[3]= {2, 4, 6};

int *p = A;

printf("%d\n", p);
printf("%d\n", *p);

second:

int A[3]= {2, 4, 6};

printf("%d\n", A);
printf("%d\n", *A);

Q2: In the second one, does compiler secretly create one more variable for the same purpose? Or it can be done without variable?

Thanks

Andy Lin
  • 397
  • 1
  • 2
  • 21
  • Depending on what compiler you use (which you don't specify), there are ways to have it output the assembly it generates. My expectation is that the compiler is able to optimizes this pretty heavily. The generated assembly doesn't necessarily have to have specified locations for each C variable. They might be joined together, or optimized away completely. – David Wohlferd Apr 18 '18 at 02:41
  • pretty sure this has all the answers you are looking for: https://stackoverflow.com/a/4955297/2495283 – Claies Apr 18 '18 at 02:41
  • JFYI: `*p` and `*A` in the later examples refer to the `A[0]` element, not `A[1]`, in C the array indexing starts from zero. Which makes sense when you think about it as memory address, if `A` is memory address of the very first byte of the array content, then `A+0` is still first element, but `A+1` is adjusted by compiler to machine code `A+1*size_of_array_element`, i.e. it points at second element of array = one element after beginning. – Ped7g Apr 18 '18 at 09:06

3 Answers3

3

The CPU doesn't "create variables". You could say the compiler creates space on the stack for variables through the choice of instructions it uses, or in static storage with assembler directives to reserve space in the .data, .rodata, or .bss sections.

You'll see more or less what you expect if you put that code on http://godbolt.org/ with optimization disabled (-O0), i.e. the actual asm for x86, ARM, or whatever, will reserve space for every variable that exists in the C abstract machine, and actually store the values there.

But in real code compiled normally (-O2 or -O3) the compiler takes advantage of the "as if" rule, which lets it emit whatever asm instructions it decides will produce the same observable behaviour as the C source, including optimizing away int *p entirely and doing the equivalent of printf("%d\n", 2);. Passing the address A to an external function like printf will probably cause the compiler to actually create that array on the stack, though. But you never take the address of p itself, so there's no reason for p to exist in memory.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
2

I'm afraid you are mistaking two things here:

  • the use of address operator &.
  • the use of arrays in C.

The address of & operator allows you to construct a pointer to value from a variable of same type as value. That means that, when you write:

p = &var1;

C gets the address of variable var1 and stores that value into pointer variable p.

When you refer to an array by name, the value you get is the address of the first element, so

int *p = A;

is the same as take the address of the first element of A and assign that value to the pointer to int variable p.

When you do:

int *p = &A;

you are doing an assignment from a pointer to array of int into a variable of type array of int, which is a different type. Historically, the compiler automatically converted the type and didn't give any indication, but as it is incorrect, it can confuse more than one. It gives a warning on my compiler, although:

$ make pru2.o
cc -O -pipe -c pru2.c -o pru2.o
pru2.c:5:6: warning: incompatible pointer types initializing 'int *' with an expression of type 'int (*)[20]'
      [-Wincompatible-pointer-types]
int *q = &A;
     ^   ~~
1 warning generated.

This is manifested in the code you post later:

printf("%d\n", A); /* this is the same ass &A[0] */
printf("%d\n", *A); /* dereference that, as *(&A[0]) == A[0] */

Here, it is important (when using arrays) to differentiate clearly that

&A

and

A

Are different expressions, that give (normally, as thinking otherwise is Undefined Behaviour) the same address value, but as a pointer to different type.

&A  

is the address of array A, and as such is defined as type

int (*)[sizeof A / sizeof A[0]]

while

A

represents the address of the first element of A, and as such it is defined as type

int *

(pointer to int) This can be shown, by simply printing the sizes of the pointed to dereferences, as in:

int A[20];

...

printf("sizeof *(&A) == %z\n", sizeof *(&A));

and

printf("sizeof *A == %z\n", sizeof *A);

(the first will give you the size of the complete array, demonstrating that the address of an array A is a pointer to an array of 20 ints, while the second will give you the size of the first element of A, demonstrating that it points to a single int element)

In general, arrays are used in a very limited way in C, as they are assimilated to pointers in many situations, they cannot be passed by value ---using the array name as a parameter to a function passes a pointer to the first element, using the address of the array makes the compiler to pass the same value, but as a pointer to array of n elements--- this will be treated as a simple pointer value by the called function, as the unspecified array suffix [] will be converted into a pointer definition by the compiler.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
0

Q1: No, the address operator is not the reason why var1 has space on the stack. Whenever you declare any variable "locally", the "computer" allocates memory on the stack for that variable.

Q2: Yes. Note that in certain conditions, you can interchange an array and a pointer. That is, for int [] my_array and int * ptr, *my_array and *ptr will both give you the first element of the array

information_interchange
  • 2,538
  • 6
  • 31
  • 49
  • https://stackoverflow.com/questions/4622461/difference-between-pointer-index-and-pointer?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – information_interchange Apr 18 '18 at 02:43
  • What I want to know in Q1 is: Does the & operator need a space in memory? No matter the var1 is global or local. – Andy Lin Apr 18 '18 at 03:19
  • 1
    @AndyLin The language doesn't specify what happens. It is up to each implementation to decide when to allocate memory. The answer may even change depending on the optimization level. – Raymond Chen Apr 18 '18 at 03:33
  • @information_interchange Q1: If you have a primitive like an int and you never take the address of it, its possible that it will only ever exist in registers and never in the actual stack. – dillonh2 Apr 18 '18 at 03:57
  • 1
    The & operator doesn’t need space in memory any more than the + operator does. – prl Apr 18 '18 at 06:17