Similarities and differences between arrays and pointers in a practical example

Given the following code:

#include <stdio.h> #include <stdlib.h> int main() { int a[1]; int * b = malloc(sizeof(int)); /* 1 */ scanf("%d", &a); printf("%d\n", a[0]); /* 2 */ scanf("%d", &b); printf("%d\n", b[0]); return 0; } 

when compiled, it receives the following warnings (i686-apple-darwin9-gcc-4.0.1):

 array.c: In function 'main': array.c:9: warning: format '%d' expects type 'int *', but argument 2 has type 'int (*)[0u]' array.c:14: warning: format '%d' expects type 'int *', but argument 2 has type 'int **' 

but why does a runtime error occur in the second printf, meanwhile it works for the first printf?

Moreover, why does it get the same result if the first scanf is replaced by scanf ("% d", a) ;?

Thank you very much in advance

+7
c arrays pointers
source share
5 answers

In most contexts, an array type expression will be implicitly converted from an "array of N-elements from T" to "pointer to T", and its value will be set to the first element of the array. The exceptions to this rule are when the array is the operand of the & or sizeof operators or the array is a string literal that is used to initialize another array in the declaration.

So how does this all relate to your code?

In line

 scanf("%d", &a); 

You apply the & operator to an array. This suppresses the implicit conversion from "array T" to "pointer to T" and returns a value like "pointer to an array from T" or T (*)[N] (hence your first warning). Now it turns out that the value of the pointer to the array and the value of the pointer to the first element of the array are the same, they just have different types. Suppose a is located at 0x0001000:

 expression type value note ---------- ---- ----- ---- a int * 0x0001000 implicitly converted to pointer &a int (*)[N] 0x0001000 &a[0] int * 0x0001000 

This is why your first call to scanf() "works"; you are passing the correct pointer value, but the compiler complains because the type of the expression does not match the expected function. If you wrote

 scanf("%d", a); 

you would not receive any warnings, since type a would be considered int * , which scanf() expects. Please note that this is identical to calling

 scanf("%d", &a[0]); 

As for b ...

You explicitly declare b as a pointer to an int and assign it a block of memory. When you apply the & operator to it, what you get is the address of the variable b with type int ** (hence the second warning), and not the address pointed to by b .

 expression type value note ---------- ---- ----- ---- b int * 0x0040000 value contained in b &b int ** 0x0001000 address of b 

In this case, you simply pass unecorated b :

 scanf("%d", b); 
+10
source share

Array a is pushed onto the stack, the address for the first element is the same as address a. & a [0] and & a is the same address

Array b is allocated using malloc, the storage address is on the heap, while the address for pointer b is on the stack. & b [0] does not match address b .

This is why the first scanf and printf work, but not the second.

The C-FAQ explains this in much more detail.

+5
source share

In the first scanf, you pass an array reference. Arrays of C indicate pointers to a block of memory of the allocated type, in your case int * and an expression of type a[0] translates to *(a + 0) (which leads to the appearance of a funny variant 0[a] , which will actually be compiled.) This the array is allocated on the stack. The second array is allocated on the heap, and the stack contains a pointer variable to this array.

In both cases, you do not pass a pointer to the first record of the array, but to an array and a pointer to an array, respectively.

Your first scanf file overwrites what is an array, since it is allocated on the stack, your value ends up (luck) in the array.

The second scanf overwrites the pointer to the array, thereby changing the pointer to a memory address that probably does not exist in your data segment. This results in a runtime error.

+2
source share

This is normal ...

First, scanf requires a pointer. "a" and "b" are already pointers! So:

 /* 1 */ scanf("%d", a); printf("%d\n", a[0]); /* 2 */ scanf("%d", b); printf("%d\n", b[0]); 

Will work.

Usually / * 1 * / should not work. But gcc converts "& a" to "a" because "& a" doesn't make any sense.

 printf("&a = %p\n", &a); printf("a = %p\n", a); printf("&b = %p\n", &b); printf("b = %p\n", b); &a = 0x7ffff6be67d0 a = 0x7ffff6be67d0 &b = 0x7ffff6be67c8 b = 0xb0b010 

You cannot take address a. But b is the "normal variable" of the type pointer, and therefore you can accept its address "& b".

On / * 2 * / you enter the value entered by the user in b, and thus * b (or b [0]) will fail if the user does not enter a valid readable memory address.

+1
source share

In your case, what happens is that you pass both variables a and b using the operator and the scanf function. What this operator does is to "ask" the memory address of the variable and pass that address to the scanf function. But, since both of your variables are pointers, that they really have a memory address, so when you pass & a or b, you are passing the memory of the pointer, not the memory address that it stores.

Example:

 int x; int *ptr; x = 10; 

Suppose that memory address x is 1000. You store number 10 at memory address 1000. Now you do this:

 ptr = &x; 

You save the address 1000 in a pointer. But 1000, being the address, is the number itself, so the pointer, like x, still needs a memory address to store this information. Suppose the pointer memory is 1004. Now look at an example:

 *ptr == 10; //x content ptr == 1000 //x memory address &ptr == 1004 // ptr memory address. 

So, if you want to pass scanf to the variable x, but using the pointer, you need to pass the address x stored in it

 scanf("%d", ptr); 

Just to illustrate another example of pointers and vectors

 int main { int vet[5]; int *ptr; ptr = vet; for(int i = 0; i < 5; ++i) { scanf("%d", (ptr+i) ); } } 

Here you can read the vector using a pointer. In addition, using pointer arithmetic, you can iterate over memory addresses for a vector.

+1
source share

All Articles