About C: pointer and Two-dimensional array - c

Here is the question:
What is the output of the program?
#include<stdio.h>
int main()
{
int A[2][10]={{1,2,3,4,5,6,7,8,9,10},{11,12,13,14,15,16,17,18,19,20} };
int (*v)[10]=A;
printf("**v=%d\n",**v);
printf("**(v+1)=%d\n",**(v+1));
printf("*(*v+1)=%d\n",*(*v+1));
printf("*(v[0]+1)=%d\n",*(v[0]+1));
printf("*(v[1])=%d\n",*(v[1]));
}
Outputs:
**v=1
**(v+1)=11
*(*v+1)=2
*(v[0]+1)=2
*(v[1])=11
Especially, I'm not very clear about how did *v divide array A into 10 parts, and please tell me the reasons about each output.
Thanks!

There's a concept called array decay at work. Also, pass each definition through cdecl.
The second line is
declare v as pointer to array 10 of int
Thus it is a pointer to an array of 10 elements. This pointer is initialized with A -- the array it points to is the first row of A.
Then, v+1 is another pointer to an array of 10 elements, following the first one. Thus, it is the second row of A.

In the **v, *v will be replaced by value of v[0], which is an address, say X, therefore the outer * will be used to indicate the value of address X, which is 1.
In the **(v+1), *(v+1) will become v[1], which is again an address, say Y, and the outer asterisk will give the value at address Y, which is 11.
*(*v+1)=2 => *(v[0] + 1) => here pointer shifts to the next location, and this location is v[0][1], which is similar to *(*(v+0)+1). Value at v[0][1] is 2.
*(v[0]+1)=2, same reason.
*(v[1])=11, v[1] holds the base address of the second row, which is the starting address of second row's 0th column, and the value at that location is 11.

Okay, let's review first, how arrays decay and second, how declarations work.
A is declared as a 2D array. When A is used in any expression, it will "decay" to a pointer to its first element. In C, a 2D array is made up of two 1D arrays. So an element of a 2D array is a 1D array. So when A is used in any expression, it will decay to a pointer to the first row of A, which is an array of 10 ints.
int (*v) [10] means that v is a pointer to an array of 10 ints. The assignment
int (*v)[10] = A;
is an expression, so A there has decayed to a pointer to 10 ints as well, so the assignment is valid.
So now when you look at **v, you are dereferencing first, v, which means you are getting what v points at, which is the first row of your 2D array. Then you are dereferencing *v, which means you are getting the first element of that first row. That is 1, so your output is 1.
When you look at **(v + 1), you are first adding 1 to the pointer v. Since v points to a row, adding 1 gets you a pointer to the next row. Then you do the double dereferencing as above and you get the first element of the next row, which is 11.
When you look at *(*v + 1), you are first dereferencing v, which means you get the first row. Then you add 1 to that, which gets you a pointer to the next element of the row. Then you dereference that, which gets you the 2, the second element.
To summarize: v points to the whole first row. *v points to the first element of the first row. (v + 1) points to the whole second row. (*v + 1) points to the second element of the first row.
After this, figuring out the rest is probably quite easy.

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.

Printf and Array

I was asked this question as a class exercise:
int A[] = {1,3,5,7,9,0,2,4,6};
printf("%d\n", *(A+A[1]-*A));
I couldn't figure it out on paper, so went ahead to compiling a simple program and tested it and found that printf("%d",*A) always gives me 1 for the output.
But I still do not understand why this is the case, hence it would be great if someone can explain this.
A is treated like a pointer to the first element of array of integers.
A[1] is the value of the first element of that array, which is 3 (indexes are 0-based)
*A is the value to which A points, which if the zeroth element of array, so 1.
So
A[1] - *A == 3 - 1 == 2
Now we have
*(A + 2)
That's where pointer arithmetic kicks in. Since A is a pointer to integer, A+2 points to the second (0-based) item in that array and *(A+2) gets its value.
So answer is 5.
Also please note for future reference that pointer to an integer and array of integers are somewhat different things in C, but for the purposes of this discussion they are the same thing.
Break it down into its constituent parts:
A by itself is the memory address of the array, which is also equivalent to &A[0], the memory address of the first element of the array.
A[1] is the value stored in the second element of the array, which is 3.
*A dereferences the memory address of the array, which is equivilent to A[0], the value stored in the first element of the array, which is 1.
So, do some substitutions:
*(A+A[1]-*A)
= *(A+(A[1])-(A[0]))
= *(A+3-1)
= *(A+2)
The notation *(Array+index) is the same as the notation Array[index]. Under the hood, they both take the starting address of the array, increment it by the number of bytes of the array element type (in this case, int) multiplied by the index, and then dereference the resulting address. So *(A+2) is the same as A[2], which is 5.
Arrays used in expressions are automatically converted into pointers pointing at the first elements of the arrays except for some exceptions such as operands of sizeof or unary & operators.
E1[E2] is defined to be equivalent to *((E1) + (E2))
+ and - operator used to pointers will move the pointer forward and backward.
In this case, *A is equivalent to *(A + 0), which is equivalent to A[0] and it will give you the first element of the array.
The expression *(A+A[1]-*A) will
Get the pointer to the first element, which points at 1, via A
Move the pointer to A[1] (3) elements ahead via +A[1], so the pointer now points at 7
Move the pointer to *A (1) element before what is pointed via -*A, so the pointer now points at 5
Dereference the pointer via the unary * operator, so the expression is evaluated to 5
An array variable in C is only the pointer to the initial memory location for the array. So if you derreference the array, you will always get the value for the first position.
If you sum up 1 to the original array value, like *(A+1) you will get the second position.
You can get any position from the array using the same method:
*(A) is the first position
*(A+1) is the second position
*(A+2) is the third position
and so on...
If you declare the int array as int* A and allocate the memory and attribute the values, it is usually easier to visualize how this works.

Why Do I need that extra asterix using 2D array?

I know that if arr is an array then arr[i]=*(arr+i); and if is a 2D array then arr[i][j]=*(*(arr+i)+j); So I have this code
main(){
int arr[5][5];
int arr2[25]; // same as arr[5][5];
int i,j;
for(i=0;i<5;i++)
for(j=0;j<5;j++){
arr[i][j]=i+j;
printf("arr[%d][%d] is at %p\n",i,j,&arr[i][j]);
}
printf("*(arr+i)=%d\n",*(arr+1)); // why this dont work
for(i=0;i<24;i++){
arr2[i]=i;
printf("arr2[%d] is at %p\n",i,(arr2+i));
}
printf("*(arr+i)=%d\n",*(arr2+1)); // prints 1 as expected
}
I know that in C there's no such thing as 2D array, its basically a linear row major contiguous blob of memory. So I'm wondering why I cant print the value of 2D arr using *(arr+1), which means add 1*5*4 bytes to the base of arr and dereference the value at that address. I know that **(arr+1) works but I dont know why I need that extra asterix ? Also If I do this printf("*(arr+i)=%p\n",*(arr+1)); is the same as I would use (arr+i) to interpret as an address
arr is an array of arrays of ints. Its type is int [5][5]. So, the elements of arr is 1D arrays. When used in expression, in most cases, arrays converted to a pointer to its first element. In *(arr + 1), arr is converted to pointer to arr[0], i.e, first 1D array. Adding 1 will increment it by 5*4 = 20 bytes, i.e, next element of array arr which is arr[1].
Since arr[1] is an array, it can't be printed (as a whole), but its address can be. arr[1] is itself an array and it will decay to pointer to its first element, i.e, arr[1][0]. To print its element you need another dereference which is acheived by arr[1][j] (j is columns).
arr[1][j] is equivalent to *(arr[1] + j) which is ultimately equivalent to *(*(arr + 1) + j).
Suggested Reading: What exactly is the array name in c?
As you said, a 2D array in C is basically an array of 1D arrays. You might think of this as an array of rows.
The rightmost * will dereference the outer array, selecting the row you want.
*(arr+i) //this gives me a pointer to the row I want
The * to the left of that will dereference in the inner array, selecting an element from the row.
*(*(arr+i)+j) //this gives me an element in the row
**(arr+i) is just a special case of the above where the column number j is 0.
The type of *(arr+1) = the type of arr[1] = int [5], which will decay to int* when used in printf.
To print the pointer, use:
printf("*(arr+i)=%p\n", *(arr+1));
To print the object it points to, use:
printf("*(*(arr+i))=%d\n", *(*(arr+1)));
You can make your code easier to read by using:
printf("arr[1] = %p\n", arr[1]); // Print the pointer
printf("arr[1][0] = %d\n", arr[1][0]); // Print the value

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.

About pointers in C

I started to read a few articles about pointers in C and I've got one example that I don't understand.
The example is from here: http://en.wikibooks.org/wiki/C_Programming/Pointers_and_arrays
Here it is:
Let's look at a slightly different problem. We want to have a two dimensional array, but we don't need to have all the rows the same length. What we do is declare an array of pointers. The second line below declares A as an array of pointers. Each pointer points to a float. Here's some applicable code:
float linearA[30];
float *A[6];
A[0] = linearA; /* 5 - 0 = 5 elements in row */
A[1] = linearA + 5; /* 11 - 5 = 6 elements in row */
A[2] = linearA + 11; /* 15 - 11 = 4 elements in row */
A[3] = linearA + 15; /* 21 - 15 = 6 elements */
A[4] = linearA + 21; /* 25 - 21 = 4 elements */
A[5] = linearA + 25; /* 30 - 25 = 5 elements */
A[3][2] = 3.66; /* assigns 3.66 to linearA[17]; */
A[3][-3] = 1.44; /* refers to linearA[12];
negative indices are sometimes useful.
But avoid using them as much as possible. */
My question is why A[0] is a pointer only to five elements and not to ALL of linearA, since the name of an array is a pointer to its first member.
And A[1] = linearA + 5; is 6 elements in a row -- for the same reason? Isn't A[1] supposed to be a pointer to the 6th member of linearA?
Can someone explain where is my mistake?
Except in a few exceptions, in C an array name is converted to a pointer to the first element of the array. linearA is an array 30 of float and in the expression:
A[0] = linearA;
it is converted to a pointer to float.
A is an array 6 of pointer to float. The element of A are of type pointer to float. So A[0] is a pointer to float and not a pointer to an array.
And A[i][j] in C is equivalent to *(A[i] + j) so A[i][j] is a float (dereferencing a pointer to float yields a float).
A[0] is a pointer to the 1st element of linearA. Since linearA is a contiguous array, this pointer actually allows to access any of the linearA 30 elements by adding an appropriate offset. However in this piece of code you emulate a 2D array by pointing to different offsets in the linearA array. The result is 2D-like array addressing: A[n] brings you to the location (i.e. offset in the linearA) of your n-th row and A[n][m] brings you to the m-th element inside this row.
My question is why A[0] is a pointer only to five elements and not to
ALL of linearA, since the name of an array is a pointer to its first
member.
you setup A[0] to point to linearA which is the first float in the array, A[0] is a pointer and thus doesn't know anything about what it points to part from an address. So A[0] is not a pointer to only five elements it points to where the array starts and has no concept of where the array ends.
And A[1] = linearA + 5; is 6 elements in a row -- for the same reason?
Isn't A[1] supposed to be a pointer to the 6th member of linearA?
yes A[1] points to the sixth element but as said before its a starting address.
It's because this line sets up an array of 6 pointers to float:
float *A[6];
And this line sets the first of those pointers to the first element of the 30.
A[0] = linearA;
Therefore each element of A points to a subsection of the original array. You have to assign them though - they'll initially point to random addresses.
The first one is the initial address (&linearA[0]) and the next five are the following ones. These are accessible as A[0][0] to A[0][5]. Because of the way arrays correspond to pointers, you can keep going up, so long as you don't exceed the 30th.
But you can assign A[n] to any part of the array you like. As long as it's part of the original array, it will point that member, and the next 5 (or however many you want).
For example, by pointing A[1] to &linearA[6], you would effectively be setting up a two dimensional array (it would resemble one, but not behave as one).
The example you posted shows a somewhat esoteric technique called Iliffe vector, which is one possible way to implement jagged arrays in C. A jagged array is a matrix in which each row has a different length.
Since arrays are one-dimensional in C, you are creating a single array linearA containing all the elements, which is interpreted as a sequence of rows, each of a different size. The pointer array A contains pointers to the first element of each row that allow you to access elements using row and column indices.
The code displays several interesting features of C pointers and arrays:
linearA + 5
Pointer arithmetic: adding an integer to a pointer (or array) gives you a pointer pointing n elements after the original pointer.
A[3][2] = 3.66;
This nice syntax allows you to think of this structure as a two-dimensional matrix.
Also, and this is probably the main point of the example, pointers and arrays are interchangeable. Here, A[3] is a pointer to float, since A was defined as an array of pointers to floats; appending [2] gives us the element 2 places after the one pointed by the original pointer. This is similar to the pointer arithmetic above, only in this case the pointer is dereferenced. Actually, array access is defined in terms of pointers so X[5] is equivalent to *(X+5).
A[3][-3]
This shows that there is nothing stopping you from accessing an element outside of a given row. In this case, you are accessing the element 3 places before the one pointed by A[3]. This is something that is rarely needed, and it only works in this case because you built the matrix to have contiguous elements. Usually, accessing elements outside the allocated range of an array will crash your program.
Finally, to answer your question:
And A[1] = linearA + 5; is 6 elements in a row -- for the same reason? Isn't A[1] supposed to be a pointer to the 6th member of linearA?
As pointers and arrays are interchangeable, A[1] is both a pointer to the sixth element in linearA and an array starting from the sixth element in linearA. There is nothing in the language saying that the latter is 6 elements long, you have to implement that logic in your code.

Resources