Passing a two-dimensional array to a function in C confusion - c

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;
}

Related

Array and pointer (something like &arr)

#include <stdio.h>
int main()
{
int *a, *b,*c,**d;
int arr[10]={0};
a=arr;
b=&arr;//is this true?why?
c=&arr[0];
d=&a;
printf("%p,%p,%p,%p",a,b,c,d);
return 0;
}
Does &arr something point to the first address of the array?
Is b=&arr; true?
What's the difference between arr and &arr?
Does &arr something point to the first address of the array?
&arr is pointer to whole array of 10 integers and not the pointer to first element of the array.
Is b=&arr; true?
No, given int *b, then b=&arr; is an incompatible pointer type assignment because the type of &arr is int (*)[10] whereas the type of b is int *. (If the definition is int (*b)[10], there is no problem.)
what is the difference between arr and &arr?
The arr, when used in a statement, will be converted to pointer to first element of array (there are few exceptions to this rule). The type of arr is int * and it is equivalent to &arr[0]1) (i.e. both are pointer to first element of array).
The &arr is pointer to the whole array (it's type is int (*)[10]).
The address of an array (&arr) and address of first element of an array (arr or &arr[0]) is numerically same though their type is different. That means, if we add 1 to them there results will be different (provided that the array size is greater than 1). arr + 1 result in pointer to 2nd element whereas &arr + 1 result in pointer after 10 elements of array arr.
Demonstration:
#include<stdio.h>
int main (void) {
int arr[10];
printf ("arr - %p\n", (void *)arr);
printf ("&arr - %p\n", (void *)&arr);
printf ("arr + 1 - %p\n", (void *)(arr + 1));
printf ("&arr + 1 - %p\n", (void *)(&arr + 1));
return 0;
}
Output:
# ./a.out
arr - 0x7ff7bec77950
&arr - 0x7ff7bec77950
arr + 1 - 0x7ff7bec77954
&arr + 1 - 0x7ff7bec77978
Also, when using the format specifier %p in printf(), the corresponding argument('s) should be type casted to (void *).
1). From C11 Standards#6.5.2.1
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))..
Hence,
arr -> (arr + 0) -> &( *(arr + 0) ) -> &arr[0]

When using a multi-dimensional array, What is the difference between using the pointer to that array and using actual array name as pointer

I have this code, Which uses function to which a pointer to an array is passed
#include<stdio.h>
void func(int ptr[][3])
{
printf("%d %d",*ptr,*ptr+1);
}
void main()
{
int arr[2][3]={{1,2,3},{4,5,6}};
int (*ptr)[3]=arr;
func(ptr);
}
Now, If I pass the actual array name to the function as
#include<stdio.h>
void func(int ptr[][3])
{
printf("%d %d",*ptr,*ptr+1);
}
void main()
{
int arr[2][3]={{1,2,3},{4,5,6}};
int (*ptr)[3]=arr;
func(arr);
}
Both of the above code executes and prints the same address. But what is the point of having a pointer if array name of multi-dimensional array does the same job.
Or is there any difference between them?
This:
printf("%d %d",*ptr,*ptr+1);
...isn't doing what I'd guess you intend it to. In particular, the precedence means that *ptr+1 means the same as (*ptr)+1, whereas I'd guess what you really wanted was:
*(ptr + 1)
To get an idea of the real difference between the two, it might make more sense to not dereference the pointers at all, and just print out the addresses:
void func1(int *a) {
printf("%p %p\n", (void *)a, (void *)(a+1));
}
void func2(int ptr[][3]) {
printf("%p %p\n", (void *)ptr, (void *)(ptr+1));
}
int main() {
int x[] = {1, 2, 3};
printf("sizeof int == %d\n\n", (int)sizeof(int));
func1(x);
func2(&x);
}
Now let's look at the result:
sizeof int == 4
0x7ffe3f67ba20 0x7ffe3f67ba24
0x7ffe3f67ba20 0x7ffe3f67ba2c
The first shows addresses ending in f00 and f04. As shown, sizeof(int) == 4, so we're seeing pretty much what we expect--adding 1 to an int * yields a pointer to the next int, so the address is increased by 4.
In the second case, the addresses end with a20 and a2c, so we're seeing a difference of c (12 decimal). In this case, it's not a pointer to an int--it's a pointer to an array of three ints. So, when we add one, the address changes by the size of an array of three ints of 4 bytes apiece (i.e., 3x4 = 12).
But what is the point of having a pointer if array name of multi-dimensional array does the same job.
The point is that an array is something completely different than a pointer and of course, you could have a pointer without an array.
The array holds many objects of the same type in a contiguous memory region. So pointer vs array makes a (huge) difference for the declaration.
Taking a pointer of an array just to pass it along is not necessary because that happens automatically in C. It doesn't hurt either.

What is the difference between pointer to array and pointer to pointer?

I'm new in programming and learning about pointers in array. I'm a bit confused right now. Have a look at the program below:
#include <stdio.h>
int fun();
int main()
{
int num[3][3]={23,32,478,55,0,56,25,13, 80};
printf("%d\n",*(*(num+0)+1));
fun(num);
printf("%d\n", *(*(num+0)+1));
*(*(num+0)+0)=23;
printf("%d\n",*(*(num+0)));
return 0;
}
int fun(*p) // Compilation error
{
*(p+0)=0;
return 0;
}
This was the program written in my teacher's notes. Here in the main() function, in the printf() function dereference operator is being used two times because num is pointer to array so first time dereference operator will give pointer to int and then second one will give the value at which the pointer is pointing to.
My question is that when I'm passing the array name as argument to the function fun() then why *p is used; why not **p as num is a pointer to array?
Second thing why *(p+0) is used to change the value of zeroth element of the array; why not *(*(p+0)+0)=0 as in the main() function *(*(num+0)+0) is used to change the value of zeroth element?
The whole thing is very confusing for me but I have to understand it anyway. I have searched about this and found that there is a difference between pointer to array and pointer to pointer but I couldn't understand much.
The trick is the array-pointer-decay: When you mention the name of an array, it will decay into a pointer to its first element in almost all contexts. That is num is simply an array of three arrays of three integers (type = int [3][3]).
Lets analyse the expression *(*(num + 1) + 2).
When you mention num in the expression *(num + 1), it decays into a pointer to its first element which is an array of three integers (type = int (*)[3]). On this pointer pointer arithmetic is performed, and the size of whatever the pointer points to is added to the value of the pointer. In this case it is the size of an array of three integers (that's 12 bytes on many machines). After dereferencing the pointer, you are left with a type of int [3].
However, this dereferencing only concerns the type, because right after the dereferencing operation, we see expression *(/*expression of type int[3]*/ + 2), so the inner expression decays back into a pointer to the first array element. This pointer contains the same address as the pointer that results from num + 1, but it has a different type: int*. Consequently, the pointer arithmetic on this pointer advances the pointer by two integers (8 bytes). So the expression *(*(num + 1) + 2) yields the integer element at an offset of 12 + 8 = 20 bytes, which is the sixth integer in the array.
Regarding your question about the call of fun(), that call is actually broken, and only works because your teacher did not include the arguments in the forward declaration of fun(). The code
int fun(int* arg);
int main() {
int num[3][3] = ...;
...
fun(num);
}
would have generated a compile time error due to the wrong pointer type. The code of your teacher "works", because the pointer to the first array in num is the same as the pointer to the first element of the first array in num, i. e. his code is equivalent to
int fun(int* arg);
int main() {
int num[3][3] = ...;
...
//both calls are equivalent
fun(num[0]);
fun(&num[0][0]);
}
which would compile without error.
This example shows a matrix, pointers to the first integers of arrays, and pointer to pointer
#include<stdio.h>
int fun(int (*p)[3]); /* p is pointer to array of 3 ints */
int main()
{
/* matrix */
int num[3][3]={{23,32,478},{55,0,56},{25,13, 80}};
/* three pointers to first integer of array */
int *pnum[3] = {num[0], num[1], num[2]};
/* pointer to pointer */
int **ppnum = pnum;
printf("%d\n", *(*(num+1)+2));
fun(num);
printf("%d\n", *(*(num+1)+2));
pnum[1][2] = 2;
printf("%d\n", *(*(num+1)+2));
ppnum[1][2] = 3;
printf("%d\n", *(*(num+1)+2));
return 0;
}
int fun(int (*p)[3])
{
p[1][2]=1;
return 0;
}
You do not actually need any pointers to print anything here.
Your int num[3][3] is actually an array of three elements, each of which is an array of three integers. Thus num[0][0] = 23, num[1][1] = 0, and so on. Thus you can say printf("%d", num[0][0]) to print the first element of the array.
Pointer to variable:
Pointer is variable which stores the address( of a variable). Every one know that.
Pointer to Array:
An array is a variable which has the starting point(address) of group of same objects.
And the pointer is a variable which stores the starting point(address) of an Array.
For example:
int iArray[3];
iArray is a variable which has an address value of three integers and the memory is allocated statically. And the below syntax is provided in a typical programming languages.
// iArray[0] = *(iArray+0);
// iArray[1] = *(iArray+1);
// iArray[2] = *(iArray+2);
In the above the iArray is a variable through which we can access the three integer variables, using any of the syntax mentioned above.
*(iArray+0); // Here iArray+0 is the address of the first object. and * is to dereference
*(iArray+1); // Here iArray+1 is the address of the second object. and * is to dereference
So simple, what is there to confuse.
The below lines are for your understanding
int iArray1[3];
int iArray2[3][3];
int *ipArray = 0;
ipArray = iArray1; // correct
ipArray = iArray2[0]; // correct
ipArray = iArray2[2]; // correct
int **ippArray = iArray2; // wrong
As per the above last line, compiler will not take it as a valid assignment. So **p is not used.
Pointer arthmatic cannot be applied on double arrays because of the way memory is allocated.

3d array print address after deference twice?

Why does a 3D array print address after being dereferenced twice? Please help me understand the code posted below, (assume that the array begins at location 1002).
int main()
{
int a[2][3][4]={
{
1,2,3,4,
4,5,6,7,
9,1,1,2
},
{
2,1,4,7,
6,7,8,9,
0,0,0,0
}
};
printf("%u %u %u %u\n",a,*a,**a,***a); //a == *a == **a, all print address 1002. Why?
}
**a has type int * and points to the first int in the 3D array
*a has type int (*)[4] and points to the first row of the 3D array
a has type int (*)[3][4] and points to the first 2D array in the 3D array
&a has type int (*)[2][3][4] and points to the whole 3D array
So they are all pointers that point to the same address. It's just that the type of the pointer is different. The following code may help illustrate this point.
int main( void )
{
int a[2][3][4]={ 1,2,3,4, 4,5,6,7, 9,1,1,2, 2,1,4,7, 6,7,8,9, 0,0,0,0 };
int *ptrInt; // pointer to an int
int (*ptrArray1)[4]; // pointer to an array of ints
int (*ptrArray2)[3][4]; // pointer to a 2D array of ints
int (*ptrArray3)[2][3][4]; // pointer to a 3D array of ints
ptrInt = **a;
ptrArray1 = *a;
ptrArray2 = a;
ptrArray3 = &a;
printf( "%p %p\n", ptrInt , ptrInt + 1 );
printf( "%p %p\n", ptrArray1, ptrArray1 + 1 );
printf( "%p %p\n", ptrArray2, ptrArray2 + 1 );
printf( "%p %p\n", ptrArray3, ptrArray3 + 1 );
}
Note: I left out the inner braces in the array initialization specifically to demonstrate that the inner braces are optional. Best practice would have all of the inner braces.
Typical output from this code is shown below. I've added comments to show the difference between the two pointers as a decimal number.
0x17b00 0x17b04 // 4 bytes, hence pointer to an int
0x17b00 0x17b10 // 16 bytes, pointer to int[4]
0x17b00 0x17b30 // 48 bytes, pointer to int[3][4]
0x17b00 0x17b60 // 96 bytes, pointer to int[2][3][4]
Note that when you add 1 to any pointer, the size of the object is added to the pointer. For example, if you have an int * and you add 1 to that pointer, the value of the pointer will increase by 4 because sizeof(int) == 4. (Yes, that assumes that ints are 32-bits, thank you.)
So by adding 1 to a pointer, you can determine the size of the object that the pointer points to. That gives you a clue about the type of the pointer from the compiler's point of view. In the example above, notice that adding 1 to ptrArray1 changes the pointer by 16. That's because ptrArray1 points to an object of size 16, specifically it points to an array of 4 ints.
Just so that we're all completely confused, allow me to say that the following line of code will print the number 8. I chose 8 since it only appears once in the array, so you can tell where it's coming from.
printf( "%d\n", ptrArray3[0][1][1][2]);
Notice that it appears that I'm using ptrArray3 as a 4-dimensional array. This is why pointers to multidimensional arrays are so confusing in C. When you convert an array to a pointer, the pointer has one less dimension than the array. But when you use the pointer with array syntax, you use it as though it had one more dimension.
So for example, start with a 2D array
int array[4][100];
The corresponding pointer is a pointer to a 1D array
int (*ptr)[100] = array;
But you can use that pointer like a 2D array
ptr[2][100] = 6;
That is the basis for all of the confusion, and the reason that pointer-to-array is a seldom used feature in C.
a has the type array of size 2 of arrays of size 3 of arrays of size 4 of int.
*a has the type array of size 3 of arrays of size 4 of int.
**a has the type array of size 4 of int.
All three arrays when decayed to corresponding pointers have the same value because they point to the same location in memory.
Try the following Code:
int main()
{
int a[2][3][4]={
{
{1,2,3,4},
{4,5,6,7},
{9,1,1,2}
},
{
{2,1,4,7},
{6,7,8,9},
{0,0,0,0}
}
};
printf("%u %u %u u%",a,*a,**a,***a);//how a == *a == **a print address 1002 please help me to understand ?
}
The reason it was returning the address was because you didn't declare your 3d array properly at all. The above is the corrected code, try it out and let us know how it goes

how pointers and array are used interchangeable in c [duplicate]

This question already has answers here:
Is an array name a pointer?
(9 answers)
Closed 8 years ago.
i have often heard that array and pointers can be used interchangeable in some situation but the two does not mean the same thing so what are the circumstances in which we can use array as a pointer and vice versa.
Arrays and pointers are never the same thing.
However, under certain circumstances, an array name in your code will "decay" to a pointer to the first element. That means you lose information about the size of the array since a pointer doesn't know how many elements it points to (technically, it only points at one though you can advance through a contiguous array if you can tell where the end is, such as with a length or sentinel value).
Situations in which arrays do not behave like pointers are (for example):
when you do a sizeof: for the array, it's the size of the entire array, for a decayed pointer, it's the size of the pointer.
when you want to move through an array: with a real array, you must use indexing while you can simply increment the pointer.
Consider the following code:
#include <stdio.h>
void fn (int arr[]) {
printf ("sz = %d\n", sizeof(arr));
printf ("#4 = %d\n", arr[4]);
arr = arr + 1;
printf ("#4 = %d\n", arr[4]);
}
int main (void) {
int x[] = {1,2,3,4,5,6,7,8,9};
printf ("sz = %d\n", sizeof(x));
printf ("#4 = %d\n", x[4]);
//x = x + 1; // Cannot do this
printf ("#4 = %d\n", x[4]);
puts("=====");
fn(x);
return 0;
}
which outputs:
sz = 36
#4 = 5
#4 = 5
=====
sz = 4
#4 = 5
#4 = 6
You can see from that the sizeof is different and you can actually move the pointer whereas the array name is at a fixed location (you'll get an error if you uncomment the line that tries to increment it).
The name of an array behaves pretty much like a pointer to the first element. That is it's value, although it has other attributes that are different.
This is most obvious when calling a function. If you have:
float sum_floats(const float *x, size_t num_values);
you can call it with:
float three[] = { 1.f, 2.f, 3.f };
const float sum = sum_floats(three, sizeof three / sizeof *three);
Note how three in the function call "decays" into &three[0], i.e. a pointer to the first element in the array. Note also how sizeof three still works, since three really is an array.
Inside the function, the array has decayed into const float *, the type of the function's argument, and you can no longer use sizeof to get the size of the caller's array (since the function has no idea that the caller used an array).
Typically an array is a container for a number of elements of the same type, while a pointer is the memory address for a memory location that contains a specific value.
When you declare an array like this:
int arr[] = {1, 2, 3, 4, 5};
printf("%d", *arr); /* will print 1 */
printf("%d", arr[0]); /* will print 1 as well */
/*or*/
int arr[5];
you are allocating memory for 5 integers. Take care that the array name by itself acts as a pointer to the first element in the array.
You can achieve the same thing using pointers:
int* arr = new int[5];

Resources