passing the array inside a function - c

int f(int b[][3]);
int main()
{
int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
f(a);
printf("%d\n", a[2][1]);
}
int f(int b[][3])
{
++b;
b[1][1] = 1;
}
3x3 => 9 elements contained in the 2-D array a. When it's passed, then b will contain the the base address of the a. If suppose base address is 1000 then ++b how does it to 3 locations and not 9 locations ahead? Are we doing typecasting when the variable a is passed to b[][3] as only the three elements?
How does b[1][1] correspond to the address of 8 and not 5?
We can't do incrementing or decrementing in an array as array is a const pointer, but how is that they are incrementing ++b as its an array?

The function heading
int f(int b[][3])
is a nothing more than a confusing way to write (and is exactly equivalent to)
int f(int (*b)[3])
The type of b is "pointer to three-element array of int". When you increment the b parameter you adjust it to point to the next three-element array of int -- now it points to {4,5,6}. Then b[1] indexes once more and gives you the array {7,8,9} and finally b[1][1] gives you the oneth element of that array, namely 8.

C multidimensional arrays are really linear, except that there is syntactic sugar to do the arithmetic correctly.
so with b[][3], it excepts a 1-D array and implicitly translates b[i][j] --> b[3*i+j]
++b works as follows: (++b)[i][j] = ORIGINAL_b[i+1][j]. So in your case, you are accessing ORIGINAL_b[1+1][1] = ORIGINAL_b[2*3+1] = ORIGINAL_b[7] (the 8th element)
Note: this is in stark contrast to the dynamic malloc version (in **b, b is a array of pointers)

How is b[1][1] corresponds to the address of 8 and not address of 5?
This is expected behavior:
int f(int b[][3])
{
//at this point b[0][0] is 1, b[1][1] is 5
++b;
//now b[0][0] is 4, b[1][1] is 8
b[1][1]=1;
}
The pointer has incremented to point to the next memory slot, which is the second slot of array a. Basically:
b -> a[0]
++b -> a[1]

Related

Pointers problems with C

I don't understand the difference in the t and p pointers. The t pointer gives the same output when printing t and *t only when using **t I get the value.
What's the difference between them?
The code is:
int main()
{
int B [2][3] = {
{2, 3, 6},
{4, 5, 8}
};
int *p = B;
int (*t)[3] = B;
printf ("%d\n", p);
printf ("%d\n", t);
printf ("%d\n", *p);
printf ("%d\n", *t);
printf ("%d\n", **t);
return 0;
}
Output is:
6422000
6422000
2
6422000
2
Comments have addressed the importance of using the correct format specifiers, but here are a couple of other points to consider:
point 1:
The declaration: int *p = B; should generate a compile time warning. This is because int *p is a simple pointer to int, as such it should only be set to point to the address of (&) a single int. But B does not represent an int.
For illustration, it is instructive to see the variations of warnings for the following 3 incorrect ways of initializing p with B. Each starts off with the phrase:
_"warning: incompatible pointer types initializing `int *` with an..."_:
int *p = B;//...expression of type 'int [2][3]'
int *p = &B;//...expression of type 'int (*)[2][3]'
int *p = &B[0]//...expression of type 'int (*)[3]'
Note the incompatible pointer types at the end of each warning. Each of them is specific, providing the programmer hints how to address the potential problem.
The following initializes *p with the address of a single int and generates no warning
int *p = &B[0][0];//assigning address of p to the location of a single integer value.
point 2:
The following declaration/assignment:
int (*t)[3] = B;
creates t as a pointer to an array of 3 int, and points t to the first instance (row) of 3 int in B where B is defined as:
int B [2][3] = {{2, 3, 6}, {4, 5, 8}};
Because t is defined in this way it is flexible in the way it can be used in that it is pointable to any array of 3 int i.e. it does not matter how many rows B has, or to which row t is pointed. Example, given the following arrays:
int B[5][3] = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}, {13,14,15}};
int A[3] = {0}; //A simple array of 3 int all set to 0
The following declarations can be made:
int (*t)[3] = NULL; //points to nothing
t = B; //points to location of 1st element of 1st row in B
t = &B[1]; //points to location of 1st element of 2nd row in B
t = &B[4]; //points to location of 1st element of 5th row in B
t = &A; //points to location of 1st element of A
Writing int *p = B; isn't a good idea but anyway, it puts the address of the very first element of B, 2 into p. So, p outputs the address(6422000) and *p outputs 2. All good till here.
What is t? It's a pointer to an array, B. What will happen when you print it, you'll get the address to B, which is always also the address of it's very first element, which happens to be 6422000. So, what will happen when you dereference t? You'll get and array, B in this case, which will then decay into a pointer and give you the memory address. And the memory address of B is 6422000. And **t will dereference the dereferenced array. The deference array is B, which will decay into the pointer, 6422000 in this case and that will be dereferenced again, giving 2.
Basically:
p: Address of the very first element of B, 2.
*p: Dereferenced p, in this case 2.
t: Address to B. Address of an array is also the address of it's very first element, equivalent to p.
*t: Dereferences into B, B will decay into it's very first element's pointer, equivalent to p.
**t: Dereferenced *t, which is 2.
Note: I know, the first element of B is {2, 3, 6}, not 2. I refer to 2 as "the very first element". That's inaccurate but for the purpose of explanation, I was forced to use the terminology.

Why *pointer_name behaves differently in 1D and 2D array

Why is it that when *q is used in 1D array it gives the value in the array whereas *p in 2D array gives an address instead. Isn't *pointer_name supposed to tell what is stored, so why is output an address instead of 40 (the value in array)?
#include<stdio.h>
int main(){
int a[3][4] = {
{40, 1, 2, 3} ,
{4, 5, 6, 7} ,
{8, 9, 10, 11}
};
int (*p)[4] = a;
int b[4] = {3,4,8,5};
int *q = b;
printf("%d, %d",*q, *p);// output- 3, 10485040
return 0;
}
Because p is a pointer to an array. When you dereference p the array will decay to a pointer to the first element. Doing *p and &(*p)[0] is equivalent (and also equivalent to &a[0][0]).
If you want to print the first element then you need to dereference both pointers, i.e. **p.
2D array means an array of arrays! so each slot of first row in the 2D array should have the address of another array.
for instance if you have an array a[2][3] , the a[0] value is the address of the first slot of an array with size 4. and a[1] like so etc .

Pointer to array deference

#include <stdio.h>
int main()
{
int a[][3] = {1, 2, 3, 4, 5, 6};
int (*ptr)[3] = a;
printf("%d %d \n ", (*ptr)[1], (*ptr)[2]);
++ptr;
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
ptr++;
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
return 0;
}
can anyone explain why in first printf, (*ptr)[1],(*ptr)[2] is giving 2,3 as output?
isn't (*ptr)[1] output should be 4 and (*ptr)[2] output should 0?
is it means that (*ptr)[1] is equal to ptr[0][1] and
(*ptr)[2] means ptr[0][2]?
int (*ptr)[3] defines a pointer to an array of 3 elements.
Hence the access (*ptr)[1] refers to the 2nd element of the array where ptr is pointing now (in eg. it points to location contatining 2). Think of it as a matrix. Ptr points to the row (in eg it will point to the location containing 4).
Now about ptr++. Compiler knows that ptr is pointing to an array of 3 int elements. So the step ptr++ increments the pointer by 3 * sizeof(int). In our matrix analogy, ptr is now pointing to next row.
yes your view of "is it means that (*ptr)[1] is equal to ptr[0][1] and (*ptr)[2] means ptr[0][2]? " is correct
First of all, you need to keep in mind that
int a[][3] = {1, 2, 3, 4, 5, 6};
is the same as
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
and
int (*ptr)[3] = a;
is the same as
int (*ptr)[3] = &a[0];
Now, (*ptr)[1] first dereferences ptr leading to the first subarray. Then, [1] gets the second element from the first subarray which is 2. Similarly, (*ptr)[2] first dereferences ptr leading to the first subarray. Then, [2] gets the third element from the first subarray which is 3.
Next,
++ptr;
increments ptr which implies that now, it points to the address of the second subarray. So now, (*ptr)[1] first dereferences ptr leading to the second subarray. Then, [1] gets the second element from the second subarray which is 4. Similarly, (*ptr)[2] first dereferences ptr leading to the second subarray. Then, [2] gets the third element from the second subarray which is 5.
Now,
ptr++;
further increments ptr which means that it now points to a memory addess past the second subarray or the 2D array. After this, dereferncing the pointer as in (*ptr)[1] and (*ptr)[2] invokes Undefined Behavior as you are reading invalid memory addresses past the array.
Finally,
is it means that (*ptr)[1] is equal to ptr[0][1] and (*ptr)[2] means ptr[0][2]?
Yes. Correct.

Determining the difference of row elements in 3d array

I need to know if there is 3 d array say :
int a[2][3][2]={{{1,2},{9,8},{3,7}},{{2,2},{1,4},{5,4}}};
How And what does the expression a[1]-a[0] calculate?
what does the expression a[1]-a[0] calculate?
It calculates the difference between the pointers to which a[1] and a[0] decay if use as operators to the arithemtic operator -.
#include <stdio.h>
int main(void){
int a[2][3][2]={{{1,2},{9,8},{3,7}},{{2,2},{1,4},{5,4}}};
printf("%d\n", (int)(a[1]-a[0]));//3
int (*b1)[2] = a[1];//b1 point to {1,2}
int (*b0)[2] = a[0];//b0 point to {2,2}
printf("%d\n", (int)(b1-b0));//3
printf("%d\n", (int)(&a[1]-&a[0]));//1
return 0;
}
/*
int a[2][3][2]
a <-> int (*)[3][2]
a[n] <-> int [3][2] <-> int (*)[2]
&a[n] <-> int (*)[3][2]
*/
Always think of multidimensional arrays as a grid/table. Here is that same array split up into sections:
a[2] = Container containing 2 2D arrays
[3] = Container containing 3 arrays
[2] = Actual data values
What data you are accessing all depends on how many brackets you are putting when you call the array, for example:
a[1] = {{2, 2},{1, 4},{5, 4}}
a[1][1] = {1, 4}
a[1][1][1] = 4
The expression a[1] - a[0] can't be done because you are subtracting an array by another array, which means you are using objects that point to data, not actual data. But, it literally evaluates to:
a[1] = {{2, 2},{1, 4},{5, 4}} and
a[0] = {{1, 2},{9, 8},{3, 7}} so,
{{2, 2},{1, 4},{5, 4}} - {{1, 2},{9, 8},{3, 7}}

Pointer function with an array

I have a problem, I have a function and I do not understand a specific thing. The function is:
int F( int* x , int n ){
int i , m=0
for (i=0;i<n; i++){
m=x[ i ] + m;
}
return m * m ;
}
I call the function with a pointer and with an integer. Later I do a "for", but I do not understand the line:
m=x[ i ] + m;
Because x is a pointer not an array.
Could you please help me.
Then x points to the memory position then to +1. For example if i call the function with
n=10
x=&n
F(x,n)
the function returns somenthing strange.
X points to the position memory to n, later to the position memory to n+1??
Since x is a pointer, when you pass the array to the function, x points to the first element of the array. Since array is a contigous allocation of memory, The pointer can be made to point to consecutive elements of the array. Thats why
m=x[i]+m
x[i] implies to the ith index from the first element of the array
main()
{
int x[10]={1,2,3,4,5,6,7,8,9,10},sum;
sum=function(x,10);
return 0;
}
This function sends the array to the function, with 10, the size of the array
Arrays are represented as contiguous memory and the array variable gets interpreted as a pointer to the base of that memory (e.g. &(x[0])). Array offset syntax gets translated into pointer arithmetic.
See this post, which clarifies the difference between pointer and arrays:
[] - indexed dereference
a[b] is equivalent to *(a + b). This means a and b must be a pointer to an array element and an integer; not necessarily respectively, because a[b] == *(a + b) == *(b + a) == b[a]. Another important equivalence is p[0] == 0[p] == *p.
The function might be equivalently declared (with more clarity perhaps):
int F(int x[], int n);
and you would call it like so:
int data[3] = {1, 2, 3};
int value = F(data, 3);

Resources