#include<stdio.h>
void foo(int **arr) {
arr[1][1]++;
}
main() {
int arr[20][20];
printf("%d\n",arr[1][1]);
foo((int**)arr);
printf("%d\n",arr[1][1]);
}
Suppose you declare:
int arr[ 10 ][ 20 ] ;
What type is arr?
You may think that it's int **, but that's incorrect.
Its actually of type int (*)[20] when it decays (like when you pass it to a function);
Array decaying applies only once.
Details here
Now consider the following,
#include<stdio.h>
#include<stdlib.h>
void foo(int arr[][20]) {
arr[1][1]++;
}
main() {
int (*arr)[20];
arr = malloc(sizeof(int (*)[]) * 2); //2 rows & malloc will do implicit cast.
printf("%d\n",arr[1][1]);
foo(arr);
printf("%d\n",arr[1][1]);
}
Output :
$ gcc fdsf.c && ./a.out
0
1
arr and arr+1 are pointing to array of 20 integers.
arr + 0 --> int int int ... int (20 ints, contiguous)
[0][0] [0][1]
arr + 1 --> int int int ... int (20 ints, contiguous)
[1][0] [1][1]
Here's what an int[2][2] looks like in memory:
int[2] int[2]
That is, an array immediately followed by another array.
Here's what an int[2] looks like in memory:
int int
That is, an int immediately followed by another int.
So, here's also what an int[2][2] looks like in memory:
int int int int
^ ^
| |___ this is arr[1][1]
|
|____ this is p[1], assuming sizeof(int*) == sizeof(int)
If you cast arr to an int**, I'm going to call the result p. Then it points to the same memory. When you do p[1][1] you don't get arr[1][1]. What the program does instead is, it reads the value at p[1], adjusts that up by the size of an int, and dereferences it. If that second int contained, say, the value "21" then you have just tried to dereference the pointer "25" (if int is 4 bytes). That ain't right.
Arrays are not the same as pointers, and 2-D arrays are certainly not the same thing as pointers-to-pointers.
Because foo expect a pointer to a pointer to int and you are passing it a pointer to an array of 20 int. Casting it won't change the fact that it isn't the correct type.
If you change it like this, you get the expected result:
#include<stdio.h>
void foo(int arr[][20]) {
arr[1][1]++;
}
int
main() {
int arr[20][20];
arr[1][1] = 1;
printf("%d\n",arr[1][1]);
foo(arr);
printf("%d\n",arr[1][1]);
}
foo needs to know the array size (well, at least the second array dimension, first isn't needed), otherwise it can't do the necessary pointer arithmetic for the [1][1].
Problem is that int arr[20][20] for 2d array means that this array is stored as 1d array, and lines are stored one after other. when you do indexing to int **arr you actually take 2nd element from first line of array, then you dereference it and take first element there.
Related
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
This question already has answers here:
Stack pointer difference for char pointer and array
(1 answer)
C pointers and arrays/ 'sizeof' operator [duplicate]
(2 answers)
Closed 9 years ago.
Hi i was doing this exercise and wanted to get the size of array after i pass the pointer to the array to the function:
But the sizeof() operator doesn't work on pointer but works on the array name. Why is it so?
Is this any way i could get the size of the array on the findPut function?
#include <stdio.h>
//global vars
int i,j;
//functions prototypes
void findPut(int *, int);
int main(void){
int ins=4;
int arr[10]={1,2,3,5,6,7,8};
printf("%d\n",sizeof(arr)); //gives 40
int *ap=arr;
printf("%d\n",sizeof(*ap)); //gives 4 instead of 40 why?? if ap and arr the same thing
findPut(ap, ins);
return 0;
}
//functions
void findPut(int *p, int n){
//vars
//getting size of array
int size= sizeof(*p);
//sizeof(int);
printf("%d\n",size); //gives 4 but expected 40????
}
When you dereference *p you get an int, so it returns 4 (which is the size of int on your platform).
Because, sizeof(*ap) means sizeof(arr[0]); since array is of type int, sizeof(int), since in your system configuration, int is of size 4 you got the result as 4.
You can try it your self by printing the value of *p, you will get the value of arr[0].
Let int *p be a pointer and int arr[10]
Please note that:
Arrays and Pointers are not equivalent.
sizeof operator is a compile time operator.
sizeof(arr), evaluates to 10*sizeof(int), that is 10*4=40 in your case.
When you dereference p (getting the value that p points to), it doesn't give you whole array, but one unit of
your array that is an int so, *p means arr[0]. sizeof(arr[0]) is
4 (in your case) that's obvious.
When you use sizeof(p), it will give you the size of the pointer in your machine.
In my machine it is 8.
main function's return type should be int always. It has to retport operating system the exit status of the program. If you use void it might return random garbage.
The example demonstrate the issue:
#include<stdio.h>
#include<stdlib.h>
int main(){
int *p=NULL;
int arr[10]={10,1,2,3,5,6,7,8,9,10};
p=arr;
printf("values: arr[0]=%d *p= %d\n\n",arr[0],*p);
printf("sizes : sizeof(arr[0])=%lu, sizeof(*p)= %lu sizeof(int)=%lu\n\n",sizeof(arr[0]),sizeof(*p),sizeof(int));
printf("Sizeof pointer p: %lu \n\n",sizeof(p));
printf("Sizeof arr: %lu \n\n",sizeof(arr));
printf("Pointing p to the first byte of 100 byte sequence\n\n");
p=malloc(100);
printf("Though p is pointing 100 byte block, sizeof(p)=%lu",sizeof(p));
return 0;
}
Essentially, sizeof evaluates the sizeof type but not the sizeof type it points to.
Thank you, i do appreciate your knowledge but is there any way i could
find the size of array inside another function( not the one where i
define the array).
You can't in my IMHO! You have to pass the size along with the array.
Example:
int main(){
int arr[10]={10,1,2,3,4,5};
printf("Length of array: %lu",findLength(arr,sizeof(arr)));
return 0;
}
size_t findLength(int *p,int size){
return size/sizeof(*p);
}
You have an int array and an int pointer:
int arr[10] = {1,2,3,5,6,7,8};
int* ap;
ap = arr;
In C, the expression arr is equivalent to &arr[0]. It stands to reason, then, that *ap is equivalent to arr[0], which is an int, which for your binary has a size of 4.
You also need to understand that arrays and pointers aren't the same thing. You may have been confused by the fact that arrays and pointers are often used interchangeably in the sense that a pointer can store the address of the beginning of an array (its first element, in other words) and navigate the consecutive addresses as if it had the actual array passed to it.
I have a two dimensional array like this:
void getC(int **p)
{
*p = &c[0][0];
}
int c[10][10];
int *a;
getC(a);
a[0][0];
it says error: no match for 'operator[]' in `a[0][0];` what is the problem and how to fix it?
You're compiling a C program with a C++ compiler. Watch out!
You need to put the definition of c above the getC function (or provide a forward declaration).
You have statements outside of a function, which isn't allowed in C. Wrap the int *a and subsequent lines with int main(void) { ... }
You need a & to make your getC() call legal - you're passing an int *, but it expects int **:
getC(&a);
The statement a[0][0] has no effect, and is anyway wrong since a is just an int *; you can't dereference it twice.
You should probably get a beginner C book and start working through it.
Essentially you are sort of downgrading the array/pointer from an int (*)[10] (pointer to array of 10 int) to a simple int pointer, by just returning the address of the first element of the 2dim array. While this is techically correct (the address of one element of the 2dim array is of course an int*), the information about the structure/layout of the ints in the array is lost, so the resulting a-ptr doesn't now anything about the fact that the int was part of a [10][10] structure.
In your case, the only way to get to the array elements would be to multiply your way through the int arrays, based on your own knowledge that at address a there are 100 ints organized 10x10:
int *a;
getC(&a);
...= a[10*x + y]; // equivalent of c[x][y];
.
However, essentially, the correct way (completely preserving types) would be
int c[10][10];
void getC(int (**p)[10]) // pointer to pointer to array of 10 ints
{
*p = c; // c itself can seamlessly change into a pointer to one sub-element
// (i.e. pointer to array of 10)
}
int main()
{
int (*a)[10]; // pointer to array(s) of 10 ints
int q;
getC(&a);
q= a[9][9];
...
}
The same again with one more dimension level (probably the most intutive solution):
However, essentially, the correct way (completely preserving types) would be
int c[10][10];
void getC(int (**p)[10][10]) // pointer to pointer to array of 10x10 ints
{
*p = &c; // &c can seamlessly change into a pointer to 10x10 ints
}
int main()
{
int (*a)[10][10]; // pointer to array(s) of 10x10 ints
int q;
getC(&a); // pass adress of pointer to 10x10 ints
q= (*a)[9][9]; // need *a in brackets to derference the pointer (operator precedence)
...
}
Please help me understand the programs below.
#include<stdio.h>
int main()
{
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
printf("value at memory location %p is %d", &a[1], a[1]);
return 0;
}
&a[1] and &a+1. Are they same or different?
#include <stdio.h>
int main()
{
int v[10];
int **p;
int *a[5];
v[0] = 1234;
v[1] = 5678;
a[0] = v;
a[1] = v+1;
printf("%d\t%d\t%d\t%d\n", *a[0],*a[1],a[0][0],**a);
printf("%d\n", sizeof(v));
return 0;
}
I wanted to know how *a[5] is represented in memory. Is *a a base pointer that points to a[0],a[1],a[2],a[3],a[4]?
#include<stdio.h>
int main()
{
int v[10];
int **p;
int (*a)[10];
a=&v;
printf("%d\n",*a);
return 0;
}
a=v; // gives error why? does v here decay into *v. Then does &v get decayed into (*)[]v? & means const pointer. Here, how is it possible to set a const pointer to a non-const pointer without a typecast?
Where does the array get stored in the memory. Does it get stored onto the data segment of the memory.
#include<stdio.h>
int main()
{
int carray[5]={1,2,3,4,5};
printf("%d\n",carray[0]);
printf("%d\t%d\t%d\n",sizeof(carray),sizeof(&carray),sizeof(&carray[0]));
return 0;
}
EDITED:
I have gone through some of the articles which stated that the only two possible situations where an array name cannot be decyed into pointer is the sizeof and &. But in the above program sizeof(&carray) gives the size as 4. and &carray decays into (*)[]carray as its an rvalue.
Then the statement that array name cannot get decayed into pointers on two conditions sizeof and & becomes false here.
&a[1] and &a+1. Are they same or different?
Different. &a[1] is the same as (a+1). In general, x[y] is by definition equivalent to *(x+y).
I wanted to know how *a[5] is represented in memory. Does *a is a base
pointer that points to a[0],a[1],a[2],a[3],a[4].
In your second example, a is an array of pointers. *a[i] is the value of the object, the address of which is stored as the ith element in your array. *a in this case is the same as a[0], which is the first element in your array (which is a pointer).
a=v //why this gives error
Because a (in your last example) is a pointer to an array. You want to assign to a, then you need to assign the address of the array v (or any other array with correct dimensions);
a = &v;
This is very good that you've commited to understanding things, but nothing will help you better than a good C book.
Hope this helps.
Stuff you are gonna need to know when dealing with pointers is that:
int *a and int a[]
is a declaration of an Array, the only diffrence is that in a[] youre gonna have to declare its constant size, *a gives you flexability, it can point at an array size 1 to infinity
int *a[] and int **a
is a declaration of an Array of Array,sometimes called Matrix, the only diffrence is that in *a[] youre gonna have to declare how many Arrays a[] gonna contain pointers of, **a gives you flexability, it can point at any Array of arrays that you want it to be assigned to.
IN GENERAL:
When adding & to a variable, your adding a * to its Type definition:
int a;
&a -> &(int)=int*
when adding * to a variable, you decrase a * from its Type definition
int *a;
*a -> * (int * )=int
int *a;
&a - the Address given to the pointer a by the system(pointer of pointer = **a)
&a+1 - the Address to the beginning of the array + 1 byte
&a[1] == &(a+1) - the Address to the beginning of the array + 1 size of int
int **a;
*a == a[0] - the Address of the first Array in the array of arrays a
*a[0]==a[0][0] - the first int of first array
int *a, b[5];
*a=*b - ERROR because a points at garbage to begin with
a=b - a points at array b
ask me what else you want to know and ill edit this answer.
Given the following code:
void
foo( int* array )
{
// ...
}
void
bar( int** matrix )
{
// ...
}
int
main( void ) {
int array[ 10 ];
int matrix[ 10 ][ 10 ];
foo( array );
bar( matrix );
return 0;
}
I don't understand why I get this warning:
warning: passing argument 1 of ‘bar’ from incompatible pointer type
Although 'foo' call seems to be ok.
Thanks :)
Well, it's certainly not well understood by the C community as can be seen by glancing over SO. The magic is, all of the following are totally, 100%, equivalent:
void foo(int (*array)[10]);
void foo(int array[][10]);
void foo(int array[10][10]);
void foo(int array[42][10]);
It is very important to draw the distinction of a pointer and an array. An array is not a pointer. An array can be converted to a pointer to its first element. If you have a pointer you have this:
--------
| ptr | -------> data
--------
However, if you have an array, you have this:
---------------------------
| c1 | c2 | c3 | ... | cn |
---------------------------
With the pointer, the data is at a whole other planet, but linked to by the pointer. An array has the data itself. Now, a multi-dimensional array is just an array of arrays. The arrays are nested into a parent array. So, the sizeof of your array is:
(sizeof(int) * 10) * 10
That is because you have 10 arrays, all of which are arrays of 10 integers. Now, if you want to pass that array, it is converted. But to what? A pointer to its first element. The element type is not a pointer, but an array. As a consequence, you pass a pointer to an array of 10 int:
int (*)[10] // a pointer to an int[10]
It is neither a array of int*, nor a int**. You may ask why the array is not passed as an int**. It's because the compiler has to know the row-length. If you do an array[1][0], the compiler will address a place sizeof(int) * 10 bytes apart from the begin of the 2 dimensional array. It decodes that information in the pointer-to-array type.
So, you have to chose among one of the above fully equivalent function prototypes. Naturally, the last one is just confusing. The compiler just silently ignores any number written in the most outer dimension if a parameter is declared to be an array. So i would also not use the second last version. Best is to use the first or second version. What is important to remember is that C has no (real) array parameters! The parameter will be a pointer in the end (pointer to array in this case).
Note how the multi-dimensional case of above is similar to the degenerate, one dimensional case below. All of the following 4 versions are fully equivalent:
void foo(int *array);
void foo(int array[]);
void foo(int array[10]);
void foo(int array[42]);
Passing multi-dimensional arrays in C is a tricky subject. See this FAQ.
The question to ask is how you'll be using bar. If you always know it will be passed a 10x10 array then rewrite it as
bar(int matrix[10][10]);
If you want to cope with arrays of varying dimensions then you might have to pass in the lengths:
bar(int *matrix, int width, int height);
The problem is that the data structure matrix[10][10] is actually not a table of ten pointers to array[10]'s, but it is an sequential array of 100 integers. The proper signature for bar is
bar (int matrix[10][10])
If you actually want to represent the matrix using indirection and have int **matrix as the parameter type for bar, then you need to allocate it differently:
int *matrix[10];
int my_data[100];
int i;
for (i = 0; i < 10; i++) { matrix[i] = &(my_data[i * 10]); }
bar(matrix);
Now 'matrix' matches the type int **. 'matrix' is an array of ten pointers, and you can pass it by pointer, hence getting the second *.
Here is some code to practice on - it contains all possible types of passing 2dimensional array and code to access element values
#include <stdio.h>
#define NUMROWS 2
#define NUMCOLUMNS 5
#define FILL_ARRAY() \
*array[0] = '1'; \
(*array)[7] = '2'; \
*(array[1]) = '3'; \
*(*(array+1)+1) = '4'; \
*(array[0]+3) = '5'; \
*(*array+2) = '7'; \
array[0][1] = '6';
void multi_01( char (*array)[NUMCOLUMNS] ) { FILL_ARRAY(); }
void multi_02( char array[][NUMCOLUMNS] ) { FILL_ARRAY(); }
void multi_03( char array[NUMROWS][NUMCOLUMNS] ) { FILL_ARRAY(); }
void multi_04( char **array ) { FILL_ARRAY(); }
void multi_05( char *array[] ) { FILL_ARRAY(); }
void multi_06( char *array[NUMCOLUMNS] ) { FILL_ARRAY(); }
int main(int argc, char **argv)
{
int i;
char mystr[NUMROWS][NUMCOLUMNS] = { { 'X', 'X', 'X', 'X'}, {'X','X','X'} };
char *pmystr[sizeof(mystr)/sizeof(*mystr)];
int numcolumns = sizeof(*mystr);
int numrows = sizeof(mystr)/sizeof(*mystr);
for( i=0; i<numrows; i++ ) pmystr[i] = *(mystr+i);
multi_01( mystr ); multi_02( mystr ); multi_03( mystr );
multi_04( pmystr ); multi_05( pmystr ); multi_06( pmystr );
printf("array '%s', '%s'\n", mystr[0], mystr[1]);
getc(stdin);
return 0;
}
You should define bar as:
bar( int* matrix )
In C all arrays should be passed as int* (or type_of_element* for other types).
int ** would be ok if your data was really an array of pointers. int[*data[] for example. Thats what you get in main(int argc, char *argv[]).
int **matrix
would indicate that you have a pointer to a pointer to int. That's commonly used to indicate a pointer to an array of pointers (also called a vector). That's definitely NOT the case with
int matrix[10][10]
which is a more of a pointer to a single section of memory sized for 10x10 ints. Try changing to:
void bar(int *matrix[])