2D array and pointers - c

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.

Related

Why application of indirection to a two-dimensional array gives a pointer?

After reading some posts on this site, I realized that array in C isn't just a constant pointer as I originaly thought, but is itself a distinct type, but in most cases array "decays" to a constant pointer to the first element of the array. Because of this new information, a question arised in my mind. Suppose we have a two-dimensional A[10][10]. Why is the result of the expression *A a pointer to the first element of the array ? I thought that in this expression, A decays to a constant pointer to the first element of the array A[0][0], and then the application of the indirection should give us the value of the A[0][0], but in fact it still gives us the address of the first element of the array. Certainly, something is wrong with my logic or my understanding of the arrays or pointers, so where do I get it wrong ?
Thanks in advance.
The first element of A is A[0], not A[0][0].
This is because A is an array of ten things. C does not have two-dimensional arrays as a primary type. An array with multiple dimensions is derived or constructed as multiple layers of arrays. To the compiler, the resulting type is still just an array, whose elements happen to be further arrays.
Thus, in *A:
A is converted to a pointer to its first element. That pointer is &A[0], so *A becomes *&A[0].
* and & cancel, so the expression becomes A[0].
A[0] is an array of ten elements, so it is converted to a pointer to its first element, &A[0][0].
*A, or A[0], is itself an array of 10 elements and and array is always expressed by a pointer to its first element. However A[10][10] (let's say an array of ints) is effectively a block of memory holding 100 ints, the 10 of the first row followed by the 10 of the second row and so on. But if the expression *A or A[0] would return an int instead of a ptr to that row, it would be impossible to use the expression A[0][0], right ?
However, because such multidimensional array is a single block of memory, it's also possible to cast it to a pointer and then access it with an expression of this kind :
((int *)A)[iRow * 10 + iCol];
Which is equivalent to the expression :
A[iRow][iCol];
But this if it's possible for a 2D array declared this way :
int main()
{
int A[10][10] = { 0 };
A[9][9] = 9999;
printf("==> %d\n", ((int *)A)[9 * 10 + 9]); //==> 9999
return 0;
}
It is not if the memory is potentially made of separate blocks of bytes (probably requiring several calls to malloc) as with this kind of expressions :
int * A[10]; // or
int ** A;
A decays to a constant pointer to the first element of the array
A[0][0]
No, it does not. Why?
C standard specifies that *(pointer + integer) == pointer[integer] so the *A is an equivalent of *(A + 0) which is A[0]. A[0] will not give you the element A[0][0] only the single dimensional array which will decay to pointer to the first element of the first row of this array.

2D Array decaying to pointer in C

This is an extended question from the answer by "Some programmer dude" in this forum.
Accessing 2D array elements using pointer arithmetic in C
To quote the answerer,
&s[0][0]. This is of type int *.
&s[0]. This is of type int (*)[2].
s[0]. This will decay to a pointer to the first element in s[0], and is equal to 1.
s. This will decay to a pointer to the first element in s, and is equal to 2.
&s. A pointer to the array, of type int (*)[4][2].
I don't get why 3 equals 1 and 4 equals 2?
I thought 3 equals 2 and 4 equals 5.
For example, putting s[0] will give the address of s[0] since it's an array, hence s[0] = &s[0].
Let's take a look at your 2D array and consider the types of the various variables you've asked about:
int s[4][2] = {
{1234,56},
{1212,13},
{1434,80},
{1312,78}
};
Now:
s is a 2D array of ints.
s[0], s[1], etc. are arrays of int.
Your question states:
putting s[0] will give the address of s[0] since it's an array, hence
s[0] = &s[0]
This is not correct. When used in an expression, the name of an array decays to a pointer to the first element of the array. What is the first element of s? It is the entire array s[0].
Since s[0] is an array, it is equivalent to the address of its first element. What is the first element of the array s[0]? It is the int s[0][0]. So since the value of the array name s[0] when used in an expression is equivalent to the address of the first element of the array, i.e., to s[0][0], we have:
s[0] == &s[0][0]
This is why (3) in the answer you have quoted is equivalent to (1).
Similarly, s is equivalent to &s[0]. When used in an expression, the array name s decays to a pointer to the entire array s[0]; as a pointer to an array of two int elements, its type is int (*) [2]. Its value is the address of &s[0], i.e., the address of the entire array (not just of its first element). This is why (4) is equivalent to (2).
As "Some programmer dude" showed in the diagram in his answer to your original question, these various pointers might point to the same location in memory, but semantically they are quite different.
Hope this helps!

array passed as array and pointer-C

Why does this program produce p and q as outputs? What is the difference between passing an array as a pointer or as an array.
#include<stdio.h>
void fun(char i[]){
printf("%c,%c", i[1],i[2]);
}
void fun2(char *i){
printf("\n%c,%c", i,i+1);
}
int main(){
char ar[] = {"Aba"};
fun(ar);
fun2(ar);
return 0;
}
Output:
b,a
p,q
You are printing the ASCII conversion of a pointer address in the second function. You must dereference the pointer via *i and *(i+1).
To print the value you should use either *i and *(i+1) or i[0] and i[1] in both the functions. i contains the first address cell of the array you have passed. In either cases, both pass their address.
what is the difference between passing array as pointer or as an
array.
Both functions, fun and fun2, signatures are equivalent. So, you don't really have an array in fun() as you think.
This is because in C, when you pass an array to a function, it gets converted into a pointer to its first element.
So, this statement in fun2()
printf("\n%c,%c", i,i+1);
doesn't print the chars but the addresses i and i+1. And that's not right either since they don't match with the format specifies you have.
When I compiled your code with gcc, it warns:
In function ‘fun2’:
warning: format ‘%c’ expects argument of type ‘int’, but argument 2 has type ‘char *’ [-Wformat=]
printf("\n%c,%c", i,i+1);
^
warning: format ‘%c’ expects argument of type ‘int’, but argument 3 has type ‘char *’ [-Wformat=]
As you can see, the format specifiers and the arguments you pass don't match. To print values that i and i+1
point to, you can print it just like how you do in fun():
int fun2(char *i){
printf("\n%c,%c", i[1],i[2]);
}
Hope my long answer here helps!
I have taken integers, the concept remains the same with any data type: char, floats, etc, etc.
Okay, a quick short lesson on arrays and pointers.
Thumb rule 1: Arrays and pointers are almost always interchangable but there are exceptions!
Taking a 1-D array, we can declare it like this :-
int arr[10];
This declares a variable named arr which can hold 10 integer elements.
I can similarly use the pointer notation to represent this array using a pointer variable or by using the array name (arr) itself.
printf ("%d", arr[2]); // Array method : will print out the third element, indexing starts from 0
Thumb rule 2: Array name(be it 1D 2D 3D 4D) always decays into a pointer or an address.
printf ("%lu", arr) //will print out the base address of the array, i.e address of the first element
How to print the value using a pointer ? Simply, dereference it using * operator.
printf("%d", *arr) //Pointer notation - will print the first value
How to reference the array using another variable?
int *ptr = arr; //Pointer notation - just simply write the array name as it decays into an address
printf("%d", *ptr); //Pointer notation - prints the first element
Many people say int *ptr is pointer to an array.
In reality it's not. It's actually a pointer to an integer not an array. Why?
Because in the first place we are storing the address of the first integer of the array and then we can traverse it by incrementing the pointer. So, in real pointer is storing the address of an integer(First integer).
Now, coming to 2D arrays :-
Declaration:-
int arr[2][3]; // arrays of 2 rows and 3 columns, total 6 elements
Same above rules implies :-
printf("%d", arr[0][1]); //prints the second element of the first row.
printf("%lu", arr) //prints the base address of the 2D array
Coming to Pointer Notation :-
printf("%d", *(*(arr + 0) + 1); // how this works?
arr contains the address. Adding a integer to it with make you jump to that row.
arr + 1 // gives the second row, i.e. arr is currently pointing to the first element of second row.
Now, further adding an integer to it, will make you skip to that specified column in that particular row.
((arr + 1) // second row + 2 ) // will you skip to third element of the second row
This is the implicit pointer notation that language gives you, when you choose to treat the array name as a pointer.
Now coming to your problem : - Explicit Pointer Notation:-
What are you trying to achieve is, storing the base address of the 2D array in a pointer.
How to correctly do that ?
int (*ptr)[3]; //reading it goes like this - ptr is a pointer to a 1D array of 3 ints
The 3 here specifies the number of columns your 2D array has.
So what it is doing is, trying to store the base address of first 1D array of that 2D array (which means 0th row base address) into the pointer.
The rest remains the same.
int (*ptr)[3] = arr; // storing the 2D array in ptr
Now, you can use it as a normal pointer(Pointer notation applies on it)
(ptr + 1) //now ptr is pointer to the Second 1D array of that 2D array or you can say to the second row's first element.
Another way you can catch an array in a function is like this:-
I use it very less though.
int main()
{
int arr[2][2];
fun(arr);
}
void fun(int catch[][])
{
}
// This is simple to understand and as well as to relate. Now, again catch can be used as pointer or as an array. It depends on you :)
void fun1(int (*ptr)[2])
{
//my way
printf("%d", ptr[1][1]);
printf("%d", *(*(ptr + 1) + 1));
//answer will be the same
}
//Ptr now contains that 2D array base address, again can be used as an array or a pointer :)

Difference between x and &x in c

What is the difference between a pointer to an array and a pointer to the first element of an array? In most cases they would be same. Please specify an example when they are not the same. Thank you.
The type is different:
int x[1] = {0};
&x[0] is a pointer to the first element of x array and is of type int *.
&x is a pointer to x array and is of type int (*)[1].
But their value is the same because there is no padding in arrays:
(int *) &x == x /* in a value context the expression evaluates to 1 */
The identity of an object is given by the pair (address, type). Different objects can have the same address as long as their types are different, in which case one is a subobject of the other.
This is the case with arrays: The array is an object, and the array elements are objects, and the array elements are subobjects of the array. The first element happens to have the same address as the array itself. Something similar is true for structs and the first struct member.
So if you have an array T a[N], then the type of a is T[N] and the type of a[0] is T, and so the address of the array is
T (*array_addr)[N] = &a;
and the address of the first element is
T * elem_addr = &a[0];
Since a naked array expression decays to a pointer to the first element under certain conditions, the last line could also be written as T * elem_addr = a;, which has the exact same meaning.
The main difference is that when you obtain the reference to an array, it decays to a pointer and sizeof can't be used anymore on it to obtain the array size, eg:
int array[10];
printf("%d\n", sizeof(array)/sizeof(array[0]));
printf("%d\n", sizeof(&array)/sizeof(array[0]));
This prints on x64:
10
2
Of course you will lose any reference to the size of the array even if you convert to a pointer without any use of the & operator:
printf("%d\n", sizeof((int*)array)/sizeof(array[0])); // prints 2
you can print the a and &a, than print a++ and &a++. Through the result, you will know the answer, just try it. a means a element address, and &a means the array address. int a[] = {1, 2 };
Pointer to an array and pointer to the first element of an array is represented as q=&a and p=a. When you increment the p as p++ it will point to the next element in array but when you increment q++ it will give to the next location to the last element in that array. Thus pointer to an array represents to whole array while pointer to first element in array represents only to the first element in array.

Array to pointer decay and passing multidimensional arrays to functions

I know that an array decays to a pointer, such that if one declared
char things[8];
and then later on used things somewhere else, things is a pointer to the first element in the array.
Also, from my understanding, if one declares
char moreThings[8][8];
then moreThings is not of type pointer to char but of type "array of pointers to char," because the decay only occurs once.
When moreThings is passed to a function (say with prototype void doThings(char thingsGoHere[8][8]) what is actually going on with the stack?
If moreThings is not of pointer type, then is this really still a pass-by-reference? I guess I always thought that moreThings still represented the base address of the multidimensional array. What if doThings took input thingsGoHere and itself passed it to another function?
Is the rule pretty much that unless one specifies an array input as const then the array will always be modifiable?
I know that the type checking stuff only happens at compile time, but I'm still confused about what technically counts as a pass by reference (i.e. is it only when arguments of type pointer are passed, or would array of pointers be a pass-by-reference as well?)
Sorry to be a little all over the place with this question, but because of my difficulty in understanding this it is hard to articulate a precise inquiry.
You got it slightly wrong: moreThings also decays to a pointer to the first element, but since it is an array of an array of chars, the first element is an "array of 8 chars". So the decayed pointer is of this type:
char (*p)[8] = moreThings;
The value of the pointer is of course the same as the value of &moreThings[0][0], i.e. of the first element of the first element, and also the same of &a, but the type is a different one in each case.
Here's an example if char a[N][3]:
+===========================+===========================+====
|+--------+--------+-------+|+--------+--------+-------+|
|| a[0,0] | a[0,1] | a[0,2]||| a[1,0] | a[1,1] | a[1,2]|| ...
|+--------+--------+-------+++--------+--------+-------++ ...
| a[0] | a[1] |
+===========================+===========================+====
a
^^^
||+-- &a[0,0]
|+-----&a[0]
+-------&a
&a: address of the entire array of arrays of chars, which is a char[N][3]
&a[0], same as a: address of the first element, which is itself a char[3]
&a[0][0]: address of the first element of the first element, which is a char
This demonstrates that different objects may have the same address, but if two objects have the same address and the same type, then they are the same object.
"ARRAY ADDRESS AND POINTERS TO MULTIDIMENSIONAL ARRAYS"
Lets we start with 1-D array first:
Declaration char a[8]; creates an array of 8 elements.
And here a is address of fist element but not address of array.
char* ptr = a; is correct expression as ptr is pointer to char and can address first element.
But the expression ptr = &a is wrong! Because ptr can't address an array.
&a means address of array. Really Value of a and &a are same but semantically both are different, One is address of char other is address of array of 8 chars.
char (*ptr2)[8]; Here ptr2 is pointer to an array of 8 chars, And this time
ptr2=&a is a valid expression.
Data-type of &a is char(*)[8] and type of a is char[8] that simply decays into char* in most operation e.g. char* ptr = a;
To understand better read: Difference between char *str and char str[] and how both stores in memory?
Second case,
Declaration char aa[8][8]; creates a 2-D array of 8x8 size.
Any 2-D array can also be viewed as 1-D array in which each array element is a 1-D array.
aa is address of first element that is an array of 8 chars. Expression ptr2 = aa is valid and correct.
If we declare as follows:
char (*ptr3)[8][8];
char ptr3 = &aa; //is a correct expression
Similarly,
moreThings in your declaration char moreThings[8][8]; contain address of fist element that is char array of 8 elements.
To understand better read: Difference between char* str[] and char str[][] and how both stores in memory?
It would be interesting to know:
morething is an address of 8 char array .
*morething is an address of first element that is &morething[0][0].
&morething is an address of 2-D array of 8 x 8.
And address values of all above three are same but semantically all different.
**morething is value of first element that is morething[0][0].
To understand better read: Difference between &str and str, when str is declared as char str[10]?
Further more,
void doThings(char thingsGoHere[8][8]) is nothing but void doThings(char (*thingsGoHere)[8]) and thus accepts any array that is two dimensional with the second dimension being 8.
About type of variables in C and C++: (I would like to add in answer)
Nothing is pass by reference in C its C++ concept. If its used in C that means author talking about pointer variable.
C supports pass by Address and pass by value.
C++ supports Pass by address, pass by value and also pass by Reference.
Read: pointer variables and reference variables
At the end,
Name Of an array is constant identifier not variable.
Nicely explained by Kerrek,
In addition to that, we can prove it by the following example:
#include <stdio.h>
int main ()
{
int a[10][10];
printf (".. %p %p\n", &a, &a+1);
printf (".. %p %p \n ", &a[0], &a[0]+1);
printf (".. %p %p \n ", &a[0][0], &a[0][0] +1);
}
The Output is :
.. 0x7fff6ae2ca5c 0x7fff6ae2cbec = 400 bytes difference
.. 0x7fff6ae2ca5c 0x7fff6ae2ca84 = 40 bytes difference
.. 0x7fff6ae2ca5c 0x7fff6ae2ca60 = 4 bytes difference.
&a +1 -> Moves the pointer by adding whole array size. ie: 400 bytes
&a[0] + 1 -> Moves the pointer by adding the size of column. ie: 40 bytes.
&a[0][0] +1 -> Moves the pointer by adding the size of element ie: 4 bytes.
[ int size is 4 bytes ]
Hope this helps. :)

Resources