what is special of the array name in c - c

int a[5] = {1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d", *(a+1),*(ptr-1));
the result is 2,5.
here is my question: why &a equal to a? a pointer to the first element in the array,so is it right to think &a is get the address of the pointer a? why type of &a is int(*)[5] ? this means &a<=> a[0][5]?
if i write this:
int b = 1;
int *cx = &b;
int *dx = (int *)(&cx + 1);
printf("%d %d", *(cx), *(dx -1));
there will have a question.
what is special of the array name in c?

a[0][5] is not valid. You are assuming that a is a pointer. a is not a pointer. It is an array. It decays to a pointer in expressions.
&a is a constant address value that points to the array a.

Array is a collection of similar datatypes stored in contiguous memory location.
case 1: Normally array name represents the Base Address of the array. According to this a and gives the base address. You Know &a gives The base address
case 2: A pointer to the first element in the array, Gives you the Base address of the array.
int a[5] = {1,2,3,4,5};
int *ptr;
ptr=a; // Here p holds the address of the first element in the array
ptr=ptr+1; // address incremented to next element. now it will point to 2
printf("%d\n",*ptr); // it prints 2.
case 3: From your code
Normally a and &a are starting address. a+1 means in will point to the second element in the array. But &a+1 means it will point to the next array. it will increment the whole array size(that means in your case 20 bytes).
int a[5] = {1,2,3,4,5}; // consider base address is 1000. so &a+1 is 1020. that is next array(but here you did not have).
int *ptr=(int *)(&a+1); // you are assigning 1020 address to ptr. for checking print the address of ptr
printf("%d,%d", *(a+1),*(ptr-1)); // as i told a+1 will point to 2nd element. so it prints 2.
//ptr is pointing to 1020, you are decreasing one element so it point to 1016. the value at 1016 is 5.
//(how? 1 is 1000 means, 2 is 1004, 3 is 1008..... 5 is 1016(because integer needs 4 bytes of address for each elements)).
Remember in array elements are stored in Contiguous memory locations.
int b = 1; // consider address of b is 1000
int *cx = &b; // assingning to *cx
int *dx = (int *)(&cx + 1); // &cx is pointer address(it is not 1000, so consider &cx is 2000)
// &cx+1 means it points to 2004, and you are assigning to *dx
printf("%d %d", *(cx), *(dx -1)); // here *(cx) will print 1. but *(dx-1) means it point to 2000. we dont know what value is there.
// so it will print some garbage value.

First off a is array name which is nothing but a pointer (Address) to the first element of the array, a would contain value of memory location where first element of array is stored.
&a and a will give you same value as it is just a pointer.
Consider you are a class teacher and have gone to museum with students, you have to keep track of 100 students, in the same way there are more teachers with more students in the museum.
So after spending a while when you have get them all together. It would be difficult to identify children and pull them together. In the same way if array name does not exist then it would always be difficult to keep track of your elements.
Luckily, there is always a mentor boy in class who always keep the students together and if you find him you will find all 100 students :).
Same way we have pointer name which stores the address of the first element. Only using that you can get all the elements of array. It means to keep track of 100 elements (Students) I only need to keep one address (array name or mentor name) in my mind rather than all. Hence tracking and accessing becomes really simple.
Sorry to bore you with my story but It could give you a feel as to how special arrays are.
You can run the below code to get a clear idea about how it works in memory level:
int a[5] = {1,2,3,4,10};
int *ptr=(int *)(&a+1);
printf("%d\n",a);
printf("%d\n",&a[0]);
printf("%d\n",&a[1]);
printf("%d\n",&a[2]);
printf("%d\n",&a[3]);
printf("%d\n",&a[4]);
printf("%d\n",(&a+1));
printf("%d\n",(ptr-1));
printf("%d,%d", *(a+1),*(ptr-1));
Hope it helps

Related

Why can't a c pointer be treated as an array?

In the question Find size of array without using sizeof in C the asker treats an int array like an array of int arrays by taking the address and then specifying an array index of 1:
int arr[100];
printf ("%d\n", (&arr)[1] - arr);
The value ends up being the address of the first element in the "next" array of 100 elements after arr. When I try this similar code it doesn't seem to do the same thing:
int *y = NULL;
printf("y = %d\n", y);
printf("(&y)[0] = %d\n", (&y)[0]);
printf("(&y)[1] = %d\n", (&y)[1]);
I end up getting:
y = 1552652636
(&y)[0] = 1552652636
(&y)[1] = 0
Why isn't (&y)[1] the address of the "next" pointer to an int after y?
Here:
printf("(&y)[1] = %d\n", (&y)[1]);
You say first: take address of y. Then afterwards you say: add 1 times so many bytes as the size of the thing which is pointed to - which is pointer to int, and hence probably 4 bytes are added - and dereference whatever is that on that address. But you don't know what is on that new memory address and you can't/shouldn't access that.
Arrays are not pointers, and pointers are not arrays.
The "array size" code calculates the distance between two arrays, which will be the size of an array.
Your code attempts to calculate the distance between two pointers, which should be the size of a pointer.
I believe the source of confusion is that (&y)[1] is the value of the "next" pointer to an int after y, not its address.
Its address is &y + 1.
In the same way, the address of y is &y, and (&y)[0] - or, equivalently *(&y) - is y's value.
(In the "array size" code, (&arr)[1] is also the "next" value, but since this value is an array, it gets implicitly converted to a pointer to the array's first element — &((&array)[1])[0].)
If you run this:
int *y = NULL;
printf("y = %p\n", y);
printf("&y = %p\n", &y + 0);
printf("&y + 1 = %p\n", &y + 1);
the output looks somewhat like this:
y = (nil)
&y = 0xbf86718c
&y + 1 = 0xbf867190
and 0xbf867190 - 0xbf86718c = 4, which makes sense with 32-bit pointers.
Accessing (&y)[1] (i.e. *(&y + 1)) is undefined and probably results in some random garbage.
Thanks for the answers, I think the simplest way to answer the question is to understand what the value of each expression is. First we must know the type, then we can determine the value
I used the c compiler to generate a warning by assigning the values to the wrong type (a char) so I could see exactly what it thinks the types are.
Given the declaration int arr[100], the type of (&arr)[1] is int [100].
Given the declaration int *ptr, the type of (&ptr)[1] is int *.
The value of a int[100] is the constant memory address of where the array starts. I don't know all the history of why that is exactly.
The value of a int * on the other hand is whatever memory address that pointer happens to be holding at the time.
So they are very different things. To get the constant memory address of where a pointer starts you must dereference it. So &(&ptr)[1] is int ** which the constant memory address of where the int pointer starts.

How pointer to array works?

int s[4][2] = {
{1234, 56},
{1212, 33},
{1434, 80},
{1312, 78}
};
int (*p)[1];
p = s[0];
printf("%d\n", *(*(p + 0))); // 1234
printf("%d\n", *(s[0] + 0)); // 1234
printf("%u\n", p); // 1256433(address of s[0][0])
printf("%u\n", *p); // 1256433(address of s[0][0])
Can anyone explain why doing *(*(p + 0)) prints 1234, and doing *(s[0] + 0) also prints 1234, when p = s[0] and also why does p and *p gives the same result?
Thanking you in anticipation.
This is the way arrays work in C -- arrays are not first class types, in that you can't do anything with them other than declaring them and getting their size. In any other context, when you use an expression with type array (of anything) it is silently converted into a pointer to the array's first element. This is often referred to as an array "decaying" into a pointer.
So lets look at your statements one by one:
p = s[0];
Here, s has array type (it's an int[4][2] -- a 2D int array), so its silently converted into a pointer to its first element (an int (*)[2], pointing at the word containing 1234). You then index this with [0] which adds 0 * sizeof(int [2]) bytes to the pointer, and then dereferences it, giving you an int [2] (1D array of 2 ints). Since this is an array, its silently converted into a pointer to its first element (an int * pointing at 1234). Note that this is the same pointer as before the index, just the pointed at type is different.
You then assign this int * to p, which was declared as int (*)[1]. Since C allows assigning any pointer to any other pointer (even if the pointed at types are different), this works, but any reasonable compiler will give you a type mismatch warning.
p now points at the word containing 1234 (the same place the pointer you get from s points at)
printf("%d\n", *(*(p+0)));
This first adds 0*sizeof(int[1]) to p and dereferences it, giving an array (int[1]) that immediately decays to a pointer to its first element (an int * still pointing at the same place). THAT pointer is then dereferenced, giving the int value 1234 which is printed.
printf("%d\n", *(s[0]+0));
We have s[0] again which via the multiple decay and dereference process noted in the description of the first line, becomes an int * pointing at 1234. We add 0*sizeof(int) to it, and then dereference, giving the integer 1234.
printf("%u\n", p);
p is a pointer, so the address of the pointer is simply printed.
printf("%u\n",*p)
p is dereferenced, giving an int [1] (1D integer array) which decays into a pointer to its first element. That pointer is then printed.
s[0]points to a location in memory. That memory location happens to be the starting point of int s[4][2]. When you make the assignment p = s[0], p and p+0 also point to s[0]. So when you print any one of these with a "%d" specifier, you will get the value stored at that location which happens to be `1234'. If you would like to verify the address is the same for all of these, use a format specifier "%p" instead of "%d".
EDIT to address OP comment question...
Here is an example using your own int **s:
First, C uses pointers. Only pointers. No arrays. The [] notation gives the appearance of arrays, but any variable that is created using the [] notation (eg. int s[4][2]) is resolved into a simple pointer (eg. int **s). Also, a pointer to a pointer is still just a pointer.
int a[8]={0}; (or int *a then malloced)
will look the same in memory as will:
int a[2][4]; ( or in **a=0; then malloced)
The statment:
s[row][col] = 1;
creates the same object code as
*(*(s + row) + col) = 1;
It is also true that
s[row] == *(s + row)
Since s[row] resolves to a pointer, then so does *(s + row)
It follows that s[0] == *(s + 0) == *s
If these three are equal, whatever value is held at this address will be displayed when printing it.
It follows that in your code: given that you have assigned p = s[0]; and s[0] == *s
*(*(p + 0)) == *(s[0] + 0) == *s[0] == **s
printf("%d\n", >>>fill in any one<<<); //will result in 1234
Note, in the following printf statements, your comment indicates addresses were printed. But because you used the unsigned int format specifier "%u",
Consider p == s[0]; which is a pointer to the first location of s. Note that either s[0][0] or **s would give you the value held at the first location of s, but s[0] is the _address_ of the first memory location of s. Therefore, since p is a pointer, pointing to the address at s[0], the following will give you the address of p, or s[0] (both same):
printf("%p\n", *p); // 1256433(address of s[0][0])
As for *p, p was created as int (*p)[1]; and pointer array of 1 element. an array is resolved into a pointer, so again, in the following you will get the address pointing to s[0]:
printf("%u\n", **p);
In summary, both p and *p are pointers. Both will result in giving address when printed.
Edit 2 Answer to your question: So my question is what is the difference between a simple pointer and a pointer to an array?
Look toward the bottom of this tutorial download a pdf. It may explain it better...
But in short, C Does not implement arrays in the same way other languages do. In C, an array of any data type always resolves into a pointer. int a[10]; is just really int *a;, with memory set aside for space to hold 10 integers consecutively. In memory it would look like:
a[0] a[9]
|0|0|0|0|0|0|0|0|0|0| (if all were initialized to zero)
Likewise you would be tempted to think of float b[2][2][2]; as a 3 dimensional array: 2x2x2, it is not. It is really a place in memory, starting at b[0] that has room for 8 floating point numbers. Look at the illustrations HERE.

2D array and pointers

int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
printf("%u %u",*(stud+1),stud+1);
printf("%u, %u", &stud,stud);
Why this statement prints similar values, stud[1] or *(stud+1) is actually an array hence must get the base address i.e &stud[0][0], but stud itself is a pointer to an array of array. Also the third statement prints identical values.
Your observations are correct concerning the expressions are all address-results. But the types of those addresses per the standard are different. Your phrase "but stud itself is a pointer to an array of array". is not accurate. stud is an array of arrays. Pointers are not arrays. After decades of trying to come up with a solid vernacular that describes how it works, and refusing steadfastly to walk the "decay" plank (a word that appears exactly one times in the C standard and even there it is used as a verb-footnote), the best I could come up with is this:
Pointers are not arrays. A pointer holds an address. An array is an address.
Each expression is shown below Given int stud[5][2];
stud int (*)[2]
stud+1 int (*)[2]
*(stud+1) int *
&stud int (*)[5][2]
Remembering that, per the standard, the expressive value of an array is the address of its first element, and pointer-to-element-type is the type of said-address. In both outputs each pair of expressions have equivalent addresses, but they're different types. This is verifiable with some expansion of the original code:
#include <stdio.h>
int main()
{
int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
printf("%p %p\n", *(stud+1), stud+1);
printf("%p %p\n", &stud,stud);
int (*p1)[2] = stud+1; // OK
// int (*p2)[2] = *(stud+1); // incompatible types
int *p3 = *(stud+1); // OK
int (*p4)[5][2] = &stud; // OK
return 0;
}
int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
The above statement defined stud to be an array of 5 elements where each element is of type int[2], i.e., an array of 2 integers. It also initializes the array with an initializer list.
Now, in the expression stud + 1, the array stud decays into a pointer to its first element. Therefore, stud + 1 evaluates to &stud[1] and is of type int (*)[2], i.e., a pointer to an array of 2 integers . *(stud + 1) is then *(&stud[1]), i.e., stud[1]. stud[1] is again an array type, i.e., int[2], so it again decays to a pointer to its first element, i.e., &stud[1][0] (which is the base address of second element of the array stud[1]) in the printf call.
Please note that stud + 1 and *(stud + 1) evaluate to the same address but they are not the same type.
Similarly, &stud and stud decay to the same address but they are different types. stud is of type int[5][2] where as &stud is of type int (*)[5][2].
Why this statement prints similar values, stud[1] or *(stud+1) is actually an array hence must get the base address i.e &stud[0][0], but
stud itself is a pointer to an array of array.
You are wrong here. The base address of stud[1] or *(stud + 1) is &stud[1][0] and not &stud[0][0]. Also, stud is not a pointer but an array type. It decays to a pointer to its first element in some cases like here but it does mean it is a pointer.
Also, you should use %p conversion specifier for printing addresses.
Without using any decaying syntax it may be clearer (these are the same addresses as your code; the first line is in the opposite order; and my parentheses are redundant but hopefully it improves clarity of this example):
printf( "%p %p\n", &(stud[1]), &(stud[1][0]) );
printf( "%p %p\n", &(stud), &(stud[0]) );
In both cases the first address on the line matches the second because the first element of an array lives at the same address as the array. Arrays can't have initial padding, and in C the address of an object is the address of its first byte.
The first element of stud is stud[0], and the first element of stud[1] is stud[1][0].
Since all of those values you are trying to display are all pointers you should use %p instead of %u. If you do that you will see that the addresses pointed to:
printf("%p, %p", &stud,stud);
are different than:
printf("%p %p",*(stud+1),stud+1);
because as you said stud is a pointer to an array of array.
Lets analyze the program
int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
Now address will be like this (assuming 2 byte integer). Brackets denote corresponding elements in array.
1 element of 2-D array ---> 4001(1) 4003(2)
2 element of 2-D array ---> 4005(3) 4007(4)
3 element of 2-D array ---> 4009(5) 4011(6)
4 element of 2-D array ---> 4013(7) 4015(8)
5 element of 2-D array ---> 4017(9) 4019(8)
We know that arr[i] gives the ith element of array. So when we say stud[0] we expect 0th element of array stud[5][2].
We can assume 2-d array as collection of 1-d array. So with statement like printf("%u",stud[0]) we exptect 0th element to get printed and what is 0th element for this array. It is one dimensional array. We know that just mentioning 1-D array gives its base address. Hence printf would print base address of 0th 1-D array and so on.
With this information we can analyze your problem.
Remember stud is 2-D array. stud is treated as pointer to zeroth element of 2-D array. So (stud + 1) would give address of 2nd element of 2-D array. And thus printing (stud+1) would print address of 2nd element of stud array. What is it. It will be 4005 from above addresses.
Now lets see why *(stud +1) also gives the same value.
Now we know that *(stud +1) is equivalent to stud[1]. From above we know stud[1] would print base address of 2nd 1-D array. What is 1-d array at 2nd position it is (3,4) with address (4005,4007). So what is it base address. It is 4005. Thus *(stud+1) also prints 4005.
Now you say stud[0] and &stud[0] print the same value.
From above stud[0] is 1-d array and printing it gives its base address. Now so &stud[0] should give address of 1-D array which is same as its base address. Thus they print the same address.
Similar explanation will hold for other cases.

Pointers to arrays in C

I just saw this code snippet Q4 here and was wondering if I understood this correctly.
#include <stdio.h>
int main(void)
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int*)(&a + 1);
printf("%d %d\n", *(a + 1), *(ptr - 1));
return 0;
}
Here's my explanation:
int a[5] = { 1, 2, 3, 4, 5 }; => a points to the first element of the array. In other words: a contains the address of the first element of the array.
int *ptr = (int*)(&a + 1); => Here &a will be a double pointer and point to the whole array. I visualize it like this: int b[1][5] = {1, 2, 3, 4, 5};, here b points to a row of a 2D array. &a + 1 should point to the next array of integers in the memory (non-existent) [kind of like, b + 1 points to the second (non-existent) row of a 2D array with 1 row]. We cast it as int *, so this should probably point to the first element of the next array (non-existent) in memory.
*(a + 1) => This one's easy. It just points to the second element of the array.
*(ptr - 1) => This one's tricky, and my explanation is probably flawed for this one. As ptr is an int *, this should point to int previous to that pointed by ptr. ptr points to the non-existent second array in memory. So, ptr - 1 should probably point to the last element of the first array (a[4]).
Here &a will be a double pointer.
No. It is a pointer to an array. In this example, int (*)[5]. Refer C pointer to array/array of pointers disambiguation
so when you increment pointer to an array, it will crosses the array and points to non-existent place.
In this example, It is assigned to integer pointer. so when int pointer is decremented, it will point to previous sizeof(int) bytes. so 5 is printed.
Your statement is essentially correct, and you probably understand it better than most professionals. But since you are seeking a critique, here is the long answer. Arrays and pointers in C are different types, this is one of the most subtle details in C. I remember one of my favorite professors saying once that the people who made the language latter regretted making this so subtle and often confusing.
It is true in many cases an array of a type, and a pointer to a type can be treated the same way. They both have a value equal to their address, but they are truly different types.
When you take the address of an array &a, you have a pointer to an array. When you say (a + 1) you have a pointer to an int, when you just say a you have an array (not a pointer). a[1] is exactly the same as typing *(a + 1), in fact you could type 1[a] and it would be exactly the same as the previous two. When you pass an array to a function, you are not really passing an array, you are passing a pointer void Fn(int b[]) and void Fn(int *b) are both the exact same function signature, if you take sizeof b within the function, in both cases you will get the size of a pointer.
Pointer arithmetic is tricky, it always offsets by the size of the object it's pointing to in bytes. Whenever you use the address of operator you get a pointer to the type you applied it to.
So for what's going on in your example above:
&a is a pointer to an array, and so when you add one to it, it is offset by the sizeof that array (5 * sizeof(int)).
When you cast to int*, the cast retains the value of the pointer, but now its type is pointer to int, you then store it in ptr, a variable of type pointer to int.
a is an array, not a pointer. So when you say a + 1 you apply the addition operator to an array, not a pointer; and this yields a pointer to one-past the first element of the type stored in the array, int. Dereferencing it with * gives you the int pointed to.
ptr is a pointer to int, and it points one past the end of the array. (it is legal by the way to point one past the end of an array, it's just not legal to dereference this pointer) When you subtract 1 from it, you end up with a pointer to an int that is the last in the array, which you can dereference. (Your explain of visualizing int b[1][5] = {1, 2, 3, 4, 5}; is something I've not heard before, and while I can't honestly say if this is technically correct, I will say this is how it works and I think this is a great way to think of it; I will likely do so in the back of my mind from now on.)
Types will get very tricky in C, and also in C++. The best is yet to come.
As per your explanation you understand array pointer correctly.Using statement
int *ptr = (int*)(&a + 1);
you point to the next address of address occupied by whole array a[] so you can access the array element using ptr by decrementing address of ptr.

Pointer to array Vs normal pointers

I am bit confused with respect to pointer to arrays and just normal pointer and how to access.
I have tried this...
int *ptr1, i;
int (*ptr2)[3];
int myArray[3] = {1, 1, 1};
int myArray1[5] = {1, 1, 1, 1, 1};
ptr1 = myArray;
ptr2 = myArray1;// compiles fine even though myArray1 contains 5 elements
// and ptr2 is pointing to array of 3 elements.
printf("%d",ptr2[3]); // prints some garbage.
Why this statement is printing garbage? What is the correct statement?
Can anyone explain?
We can also declare pointer to array as
int (*ptr)[]; // ptr is a pointer to array.
When you do
ptr2 = myArray1;
compiler will throw you a warning message. Look boss types are not compatible.
In some context Arrays decays into pointers. Warning message is because, when arrays decays into pointers, the decayed type is pointer. In this case, when you do
ptr1 = myArray;
myArray decays into int *.
But when you do,
ptr2 = myArray1;
myArray1 decays into pointer that is int *, but the type of ptr2 is int (*)[].
In order to avoid warning, you should say
ptr2 = &myArray1; //&myArray1 returns address of array and type is int(*)[].
Why this statement is printing garbage? What is the correct statement? Can anyone explain?
printf("%d",ptr2[3]);// prints some garbage.
Yes, But why? Lets see the correct statement first...(note that index should be less than 3)
printf("myArray1[%d] = %d\n", i, (*ptr2)[2]);
We have to use (*ptr2)[i] to print the array element. This is because, just by mentioning ptr2, we will get the address of the array (not the address of some int). and by de-referencing it (*ptr2) we will get the address of 0th element of the array.
Pointer ptr2 is pointer to int array of size three
ptr2 = myArray1; // you may getting warning for this
should be:
ptr2 = &myArray1; // use & operator
And
printf("%d", ptr2[3]);
should be:
printf("%d", (*ptr2)[2]); // index can't be 3 for three size array
// ^^^^^^^
Notice parenthesis around *ptr2 is needed as precedence of [] operator is higher then * dereference operator (whereas if you use pointer to int you don't need parentheses as in above code).
Read Inconsistency in using pointer to an array and address of an array directly I have explained both array to access array elements. (1) Using pointer to int (2) pointer to array
Whereas ptr1 = myArray; is just find, you can simply access array elements using ptr1[i] (not i values should be 0 to 4)
int (*ptr2)[3];
This signifies that (*ptr2) is the identifier which contains the location in memory of the beginning of an integer array. Or, rephrasing, that ptr2 is an address. That address contains a value. That value is itself the address of the beginning of an array of ints.
So when you write ptr2 = myArray1 you are basically saying "The address of my address holder is the address of the beginning of myArray1".
So when you go to print the value using ptr2[3] you are actually printing the value of the memory address of myArray1, incremented 3*sizeof(ptr2) units. Which is why it looks like garbage, it's some memory address.
What should be in the print statement is (*ptr2)[3] which means "Take the address of ptr2 and get the value stored at that address. Next, using that second address, increment it 3*sizeof(int) and get the value stored at that incremented address."
Arrays in C are nothing more than a contiguous region of allocated memory. Which is why saying:
int *x = malloc(3*sizeof(int));
Is the same as:
int x[3];
Since [] and * both dereference a pointer, if we wanted to access the second element of either array, we could write:
int value = x[1];
or
int value = *x+sizeof(int); // Since *x would be index 0
Two of the major differences are that the [] notation is a bit easier to read but lengths must be determined at compile time. Whereas, with the *x/malloc() notation, we can dynamically create an array or arbitrary length.

Resources