Look at the code given below:
#include<stdio.h>
int main()
{
int (*p)[3];
int a[3]={10,11,12};
p=&a;
printf("%d\n", *p[0]);
printf("%d\n", *p[1]);
printf("%d\n", *p[2]);
return 0;
}
printf("%d\n", *p[0]); prints 10 which is expected.
But printf("%d\n", *p[1]); doesn't print 11.
And
printf("%d\n", *p[2]); doesn't print 12.
Why? What's the reason behind this?
Operator precedence. [] has higher precedence than *, so when you write *p[0] it is the same as (*(*(p + 0))) - you do pointer arithmetic on an array pointer.
Meaning that for example p[1] gives you the address of p + 3*sizeof(int) bytes, which is accessing the array out of bounds.
Correct code should be:
printf("%d\n", (*p)[0]);
printf("%d\n", (*p)[1]);
printf("%d\n", (*p)[2]);
*p[k] is *(p[k]), not (*p)[k].
That you get the expected result for *p[0] can be explained by its being the same as p[0][0], and it doesn't matter which order you put the zeros in.
p[1][0] (*p[1]), however, is not the same as p[0][1] ((*p)[1]).
(It's even undefined, since p[1] does not exist.)
int (*p)[3]; is an array of pointers to int.
int a[3]={10,11,12}; is an array of int. Arrays and pointers share a lot of properties. You can use array notation for pointers for example.
Lets take a normal pointer int *p = a which is the same as int *p = &a[0]. Now the pointer points to the first element of the array. And you can use it the same way as the array.
printf("%d\n", p[0]); //10
printf("%d\n", p[1]); //11
printf("%d\n", p[2]); //12
What you did was getting the address of the array-"pointer" this yields the address of the first element of the array. Because &a == a
This gets written to the first element of your pointer array leaving you with
p[0] == a
p[1] == unknown
p[2] == unknown
by doing *p[0] you get the first element of p (p[0]) and dereference it *.
This is the same as *a or a[0].
But by doing *p[1] you get to an unkown memory location(p[1]) and derefence it *. This is undefined behaviour.
Related
Why does this code output: 1 ≡ arr[0] and not &arr[0]?
My assumption is that after the assignment, ptr holds the address of &arr, which is a pointer to the first element of arr or arr[0].
So dereferencing the ptr should yield the value stored at that address, which is the memory location of the first element.
#include<stdio.h>
int main(void) {
int arr[] = { 1 };
int* ptr = &arr;
printf("%d\n", *ptr);
return 0;
}
A couple of things...
First, a doesn't store the location of a[0]. There is no object a that is separate from the array element a[0]. Basically what you have in memory is
Address
------- +------+
0x1000 a: | 0x01 | a[0]
+------+
In other words, the address of an array is the same as the address of its first element.
Unless it is the operand of the sizeof or unary & operators, the expression a will be converted ("decay") from type "1-element array of int" (int [1]) to "pointer to int" (int *) and the value of the expression will be the address of the first element in the array.
This means that the expressions &a, a, and &a[0] all yield the same address value; it's just the types of the expressions are different:
Expression Type Decays to
---------- ---- ---------
&a int (*)[1]
a int [1] int *
&a[0] int *
Which brings us to this line:
int* ptr = &arr; // int * = int (*)[1] - assignment of incompatible types
The compiler should have yelled at you about that line. You may want to dial up the warning level.
I added some print statements to your code:
#include<stdio.h>
int main(void) {
int arr[] = { 1 };
int *ptr = (int *)arr;
printf("%p\n", (void *)arr);
printf("%p\n", (void *)&arr);
printf("%p\n", (void *)&arr[0]);
printf("%p\n", (void *)ptr);
printf("%p\n", (void *)&ptr);
printf("%d\n", *ptr);
return 0;
}
It prints:
0x7ffe3fe37aa4
0x7ffe3fe37aa4
0x7ffe3fe37aa4
0x7ffe3fe37aa4
0x7ffe3fe37a98
1
Which means arr and ptr are on the stack: ptr is at 0x7ffe3fe37a98 and has the value 0x7ffe3fe37aa4, which is where the arr is stored.
Note that arr and &arr have the same value. See this question: How come an array's address is equal to its value in C?
My assumption is that after the assignment, ptr holds the address of &arr, which is a pointer to the first element of arr or arr[0].
That is correct.
So dereferencing the ptr should yield the value stored at that address
Also correct.
which is the memory location of the first element.
No. Since ptr is pointing to the first element, dereferencing yields the first element, which is 1.
In Visual Studio 2019, I tried to assign value to int pointer at specified position, but it doesn't work. Is this possible?
Moreover how I can printf a pointer's value, and not the address?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p =(int*)calloc(10,1);
p[0]=1;
p[1]=0;
p[2]=1;
printf("%d\n",p);
}
Thank
calloc(10,1) allocates 10 single byte items not 10 integers. So (except 8 bits uCs where int is 2 bytes) your allocated memory area is far too short. if you want to allocate space for 10 integers you need to int *p = calloc(10, sizeof(*p));
printf("%d", p) invokes an UB as p is the reference (address) stored in the pointer p. You need to dereference the pointer to get the integer referenced (pointed) by the p pointer printf("%d\n, *p);
To print the reference stored in the pointer you need to use the correct format: printf("%p\n", (void *)p);.
It works.
To print the value you need to derreference with * or index with [].
printf("%d\n",*p); //p[0]
printf("%d\n", p[0]); //p[0]
printf("%d\n",*(p + 1)); //p[1]
printf("%d\n", p[1]); //p[1]
I know there are many similar questions, but I can't find an answer.
When passing the two-dimensional [3] [4] array to the function in my code below, how does the compiler know how far to increment the pointer, in the case of the last printf() where we are incrementing 3 x 4 memory locations, if the number 3 is missing in the function argument?
I mean, why is only arr [] [4] sufficient and not [3] [4]? Thanks
#include <stdio.h>
#include <stdlib.h>
int Fun(int arr[][4])
{
printf("%p\n", arr); // address of first element
printf("%p\n", arr[0] + 1); // address increments by 4, pointing to next "inner array"
printf("%p\n", arr + 1); // how does it know to increment address by 3 x 4 here? The complete array size
}
int main()
{
int arr[3][4] =
{
1,2,3,4,
5,6,7,8,
9,10,11,12
};
printf("%p\n", arr);
printf("%p\n", arr[0] + 1);
printf("%p\n", arr + 1);
printf("Passing to function\n");
Fun(arr);
return 0;
}
First, Fun should be defined with:
int Fun(int arr[][4])
rather than what you have, int Fun(int* arr[][4]);.
Next, when Fun(arr) is evaluated, arr is automatically converted from an array of 3 arrays of 4 int to a pointer to an array of 4 int. Similarly, in the declaration of Fun, int arr[][4] is automatically adjusted to be a pointer to an array of 4 int. So the argument type and the parameter type will match if you declare Fun correctly.
You could also declare Fun as:
int Fun(int (*arr)[4])
This is the same thing as above, due to the automatic adjustment that would be applied to the declaration above. Note that the asterisk here is grouped with the arr by the parentheses. This makes it a pointer to an array of int, rather than an array of pointers to int.
Now, as to what will be printed, in main:
printf("%p\n", arr);
In this statement, arr will be automatically converted to a pointer to its first element, so it becomes a pointer to an array of 4 int. Then the value of this pointer is printed. Note: When printing pointers, technically you should convert them to const void * or void *, as with printf("%p\n", (const void *) arr);. However, omitting this likely does not cause a problem at the moment.
printf("%p\n", arr[0] + 1);
In this statement, arr[0] is the first element of arr. That first element is an array of 4 int, and it is automatically converted to be a pointer to its first element. So arr[0] becomes a pointer to the first int. Then adding 1 advances the pointer to the next int. The result is likely an address four bytes beyond arr, depending on your C implementation. (It could be a different number of bytes, but four is the most common today.)
printf("%p\n", arr + 1);
In this statement, arr is converted to a pointer to its first element, an array of 4 int. Adding 1 advances to pointer to the next element, which is the next array of 4 int. So this likely adds 16 bytes to the address.
Then, in Fun:
printf("%p\n", arr); // address of first element
Here arr is a pointer to an array of 4 int. Its value is printed, yielding the same address as for the corresponding printf in main.
printf("%p\n", arr[0] + 1); // address increments by 4, pointing to next "inner array"
Here arr[0] is the object pointed to by arr, which is an array of 4 int. Since it is an array, it is automatically converted to a pointer to its first element, which is an int. So this points to the first int. Then adding 1 advances to the next int, and this again yields the same address as the corresponding printf in main.
printf("%p\n", arr + 1); // how does it know to increment address by 3 x 4 here? The complete array size
In this case, arr is a pointer to an array of 4 int, and adding 1 advances it to the next array of 4 int, so the result is likely 16 bytes beyond the value of arr, and this again yields the same address as the corresponding printf in main.
If you saw different values for the printf statements in Fun and main, this was likely because of the incorrect declaration with int* and because int * is eight bytes in your C implementation, compared to four for int. That error would have doubled some of the increments. You should not have seen any multiple of three in the increments.
Regarding the first dimension, Fun does not need to know the first dimension because it never advances any pointers by units of the first dimension. It receives only a pointer to an array of 4 int, and it does not need to know that there are 3 such arrays there.
The detailed answer by Eric Postpischil clearly shows all the issues in OP's code.
I'd like to note that passing a pointer to the correct type would let the compiler doing the right pointer arithmetic:
#include <stdio.h>
#include <stdlib.h>
void Fun(int (*arr)[3][4])
{
printf("Address of the first element: %p\n", (void *)*arr);
printf("Address of the second row: %p\n", (void *)(*arr + 1));
printf("Address after the last element: %p\n", (void *)(arr + 1));
}
void Fun_vla(size_t rows, size_t cols, int (*arr)[rows][cols])
{
printf("Address of the first element: %p\n", (void *)*arr);
printf("Address of the second row: %p\n", (void *)(*arr + 1));
printf("Address after the last element: %p\n", (void *)(arr + 1));
}
int main()
{
int arr[3][4] =
{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
Fun(&arr);
puts("");
Fun_vla(3, 4, &arr);
return 0;
}
This question already has answers here:
C: differences between char pointer and array [duplicate]
(14 answers)
Closed 7 years ago.
I've read various articles and questions here on SO about pointers and arrays equivalency. Nearly each article explains it different. I know that arrays and pointers are strongly related and bellow are my experiments with pointers and arrays equivalency, including comments which explain given behavior (feel free to correct me if I'm wrong somewhere). My question is: are arrays are just constant pointers or is there also another differences?
#include <stdio.h>
int main ()
{
// declaring array this way in fact declares a pointer with name "a" which points to the first element in the array:
int a[] = {0,1,2,3,4};
// assigning an array to the pointer in fact assigns the address of the first array element to the pointer, those two are thus equivalents:
int *pa1 = a;
int *pa2 = &a[0];
printf("########################\n");
// REFERENCING: arrays can use pointer syntax (following are equivalents)
printf("%p\n", (a+0)); // a+0 == 0+a
printf("%p\n", a);
printf("%p\n", &a[0]);
printf("%p\n", &0[a]); // a+0 == 0+a
printf("########################\n");
// DEREFERENCING: arrays can use pointer syntax (following are equivalents)
printf("%d\n", *(a+0)); // a+0 == 0+a
printf("%d\n", *a);
printf("%d\n", a[0]);
printf("%d\n", 0[a]); // a+0 == 0+a
printf("########################\n");
// REFERENCING: arrays can use pointer syntax (following are equivalents)
printf("%p\n", (a+1));
printf("%p\n", &a[1]);
// REFERENCING: pointers can use array syntax (following are equivalents)
printf("%p\n", (pa1+1));
printf("%p\n", &pa1[1]);
printf("########################\n");
// DEREFERENCING: assigning values via pointers using pointer/array syntax (following are equivalents)
*(pa1+1) = *(pa1+1) + 10;
pa2[1] = pa2[1] + 10;
// DEREFERENCING: arrays can use pointer syntax (following are equivalents)
printf("%d\n", *(a+1));
printf("%d\n", a[1]);
printf("%d\n", 1[a]);
// DEREFERENCING: assigning values via arrays using pointer/array syntax (following are equivalents)
*(a+2) = *(a+2) + 10;
a[2] = a[2] + 10;
// DEREFERENCING: pointers can use array syntax (following are equivalents)
printf("%d\n", *(pa1+2));
printf("%d\n", pa1[2]);
printf("%d\n", 2[pa1]);
printf("########################\n");
// REFERENCING: those two pointers points to the same address
printf("%p\n", pa1);
printf("%p\n", pa2);
// DEREFERENCING: those two pointers points to the same address
printf("%d\n", *pa1);
printf("%d\n", *pa2);
printf("########################\n");
// This is correct:
pa1++;
printf("%p\n", pa1);
printf("%d\n", *pa1);
printf("%p\n", pa2);
printf("%d\n", *pa2);
printf("########################\n");
return 0;
}
I would say that arrays are just constant pointers, the only thing that misleads me is that the error messages are different when I try to increment array and constant pointer, here is what I mean:
#include <stdio.h>
int main (){
int var1=0;
int * const ptr;
int a[] = {0,1,2,3,4,5};
// This gives an error:
// error: increment of read-only variable ‘ptr’
ptr++;
// This gives an error:
// error: lvalue required as increment operand
a++;
return 0;
}
If they are not the same can you please post some scenario where this difference is obvious?
Arrays and pointers are completely different animals.
Under most circumstances, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", but the array object itself is not a pointer.
This behavior has its roots in the B language, from which C was derived. In B, an array object was a pointer, and the subscript operation a[i] was interpreted as *(a + i) (offset i elements from address stored in a, dereference the result).
Ritchie kept the *(a + i) semantics, but got rid of the explicit pointer; C converts the array expression to a pointer expression instead (except when the array expression is the operand of the unary & or sizeof operators).
You may pretend, that arrays are the same as constant pointers, but in fact they are different types. One notable difference is a result of the sizeof operator. For instance:
#include <stdio.h>
int main(void)
{
int a[] = {0, 1, 2, 3, 4, 5};
int * const p = a;
printf("sizeof(a) = %zu\n", sizeof(a));
printf("sizeof(p) = %zu\n", sizeof(p));
}
For the former, you are getting total size of array. Assuming that sizeof(int) = 4, it prints 24. OTOH, for the latter, you just get the same as size of int pointer.
Also, you cannot use array initializer for pointer variable:
int * const p = {0, 1, 2, 3, 4, 5};
results into compiler's error if you set it with -pedantic-errors flag, e.g.:
error: excess elements in scalar initializer
Another important difference is that arrays are copied for each element during a struct assignment:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct threeNumbers {
int t[3];
} a = {{1, 2, 3}}, b = {{4, 5, 6}};
int main(void)
{
a = b;
a.t[0] = 100;
printf("%d\n", a.t[0]); // prints 100
printf("%d\n", b.t[0]); // prints 4
}
This is not the case for pointers. Structures with const pointers cannot be assigned to each other. For non-const pointers members, only an adress is copied. If pointers were set with malloc, then this might result into memory leak.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct s1 {
char *z;
int i;
struct s1 *p;
};
struct s1 *ptr;
static struct s1 a[] = {
{"Nagpur", 1, a + 1},
{"Raipur", 2, a + 2},
{"Kanpur", 3, a}
};
ptr = a;
printf("%p\n", a[0]);
printf("%p\n", a[1]);
printf("%p\n", a[2]);
printf("%p\n", ptr);
printf("%p\n", a[2].p);
printf("%p\n", a[1].p->p);
printf("%p\n", a);
return EXIT_SUCCESS;
}
Whenever we have an array, suppose we call it a[10], then the address of a or a[0] are equal. But in the above case, the address of a and that of a[0] is different. I can't figure out why?
What you're passing to printf() here is the structure itself, not a pointer to it:
printf("%p\n", a[0]);
The behavior of this code is poorly defined. (In practice, it will typically end up printing the first element of the structure, but this may not be consistent.) What you probably want is:
printf("%p\n", &a[0]);
^
If you had compiled with warnings enabled (e.g. gcc -Wall -Werror), you would see that this line:
printf("%p\n", a[0]);
is invalid:
ptr.c:20:5: error: format ‘%p’ expects argument of type ‘void *’, but
argument 2 has type ‘struct s1’ [-Werror=format=]
printf("%p\n", a[0]);
^
You're taking the 0th element of that structure, or in other words, dereferencing a, and passing a struct s1 by value to printf, who is doing like you said, and interpreting it as a pointer.
If you instead take the address of the first element of the array, you'll see that they are indeed, at the same address:
printf("%p\n", &a[0]);
The reason why both are different is when you print a, its just reference, whereas a[0] is used to de-reference. Try printf("%p\n",&a[0]).
the printf() calls with the a[x] parameter will not print addresses but rather the contents of that offset. This line segment: 'then the address of a or a[0] are equal' is not true. However, then the address of a and the address of a[0] are equal is true. The '%p' format converter is only for addresses. so the code needs to use addresses, not the contents.
suggest using something like:
printf("%p\n", &a[0]);
printf("%p\n", &a[1]);
printf("%p\n", &a[2]);
printf("%p\n", ptr);
printf("%p\n", a[2].p);
printf("%p\n", a[1].p->p);
printf("%p\n", a);
you are assigning addresses of strings (e.g. "nagpur") char pointer. these strings will be present in code section. so "z" will be having addresses of those strings and you are trying to print those by printing a[0]. you should print &a[0] instead. a[0] is similar operation to *(a+0). so if you want to print its address you should use & operator.