I have this function that takes a pointer of an array (in order to modify it from within the function)
int func_test(char *arr[]){
return 0;
}
int main(){
char var[3];
func_test(&var);
return 0;
}
When I try to compile this I get :
passing argument 1 of ‘func_test’ from incompatible pointer type
Why is this problem, and how I pass a pointer to that array in this case?
char * arr[] is not a pointer to an array; it is an array of pointers. Declarations in C are read first from the identifier towards the right, then from the identifier towards the left. So:
char * arr[];
// ^ arr is...
// ^ an array of...
// ^ pointers to...
// ^ char
A pointer to an array is a type (*varname)[], in your case, a char (*arr)[].
You are passing the address of a pointer. I think you want this:
int func_test(char arr[]){
arr[0] = 'a';//etc.
return 0;
}
int main(){
char var[3];
func_test(var);
return 0;
}
char var[3] is an array that holds 3 characters, not 3 pointers to characters - char *arr[] denotes an array that holds pointers to characters.
So you can go like this:
char *var[3];
func_test(var);
Note that the ampersand is not needed because array identifiers automatically decay to pointers of the corresponding type, in this case char **.
That's because the name of an array is already a pointer to it, so use func_test(var).
&var will have type char**
This is an array of pointers
char *arr[]
This is an address of a pointer
&var
So you are passing something different to what the function expects
C's treatment of arrays is a little confusing at first.
Except when it's an operand of either the sizeof or unary & operators, or when it's a string literal being used to initialize another array in a declaration, an expression with type "N-element array of T" will be implicitly converted to type "pointer to T", and its value will be the address of the first element in the array.
Assume the following declaration:
int x[10];
The type of the expression x is "10-element array of int". However, when that expression appears as, say, a parameter to a function:
foo(x);
the type of x is implicitly converted ("decays") to type "pointer to int". Thus, the declaration of foo needs to be
void foo(int *p);
foo receives an int *, not an int [10].
Note that this conversion also occurs for something like
i = x[0];
Again, since x isn't an operand of sizeof or &, its type is converted from "10-element array of int" to "pointer to int". This works because array subscripting is defined in terms of pointer arithmetic; the expression a[n] is equivalent to *(a+n).
So for your code, you'd write
int func_test(char *arr) { return (0); }
int main(void)
{
char var[3];
func_test(var); // no & operator
return 0;
}
Postfix operators like [] have higher precedence than unary operators like *, so a declaration like T *a[N] is interpreted as T *(a[N]), which declares an array of pointer to T. To declare a pointer to an array, you have to use parentheses to explicitly group the * operator with the array name, like T (*a)[N].
Here's a handy table of array declarations, expressions, and types:
Declaration: T a[N]; // a is an N-element array of T
Expression Type Decays To
---------- ---- ---------
a T [N] T *
&a T (*)[N]
a[i] T
&a[i] T *
Declaration: T *a[N]; // a is an N-element array of pointer to T
Expression Type Decays To
---------- ---- ---------
a T *[N] T **
&a T *(*)[N]
a[i] T *
*a[i] T
&a[i] T *
Declaration: T (*a)[N] // a is a pointer to an N-element array of T
Expression Type Decays To
---------- ---- ---------
a T (*)[N]
&a T (**)[N]
*a T [N] T *
(*a)[i] T
Related
Array returns pointer to the first element. I have simple code as below:
int a[10] = {1,2,3};//Filled three elements
int (*ptr)[10];//pointer to an array of 10 ints
ptr = a;
I am getting below warning.
warning: assignment from incompatible pointer type
If i modify the pointer definition as shown below then there is no warning
ptr = &a;
Why does the first assignment results in warning? Does &a returns integer pointer to array of 10 elements? Pls help to understand. Thanks
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
Except for the sizeof, & and alignof operator, arrays decay to pointers.
int a[10] = {1,2,3};//Filled three elements
int (*ptr)[10];//pointer to an array of 10 ints
ptr = a;
In the assignment ptr = a, a decays to a pointer to int (int *), which points to the first element.
int a[10] = {1,2,3};//Filled three elements
int (*ptr)[10];//pointer to an array of 10 ints
ptr = &a;
Here &a is of type int (*)[10], which is a pointer to an array of 10 ints and has the same type as ptr. It is the proper way to assign a pointer to an array.
Also note that the value itself is the same for a and &a, the only difference is the type.
Here I have a 2D array. I want to declare a pointer to point to the first row of the array. First I did something like this
#include <stdio.h>
int main ()
{
int arr[2][2]={{6,2},{3,4}};
int *ptr=arr;
printf("%d",*(ptr+0));
}
First row of the 2D array is also a array. Similar type of pointer declaration for a 1D array don't give any warning. Why am I getting warning during compilation.
[Warning] initialization from incompatible pointer type [enabled by
default]
The following didn't give any warning
int main ()
{
int arr[2][2]={{6,2},{3,4}};
int (*ptr)[2]=arr;
printf("%d",*(ptr+0));
}
Except when it is the operand of the sizeof or unary & operators, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
In the line
int *ptr=arr;
the expression arr has type "2-element array of 2-element array of int" (IOW, T is "2-element array of int"). Since the expression arr is not the operand of either the sizeof or unary & operators, it is converted ("decays") to an expression of type "pointer to 2-element array of int", or int (*)[2], and the value of the expression is the address of the first element of the array.
This is why you got the warning for the line above, but not for
int (*ptr)[2]=arr;
since in that case the types match correctly.
Given the declaration
int arr[2][2]={{6,2},{3,4}};
the following are all true:
Expression Type Decays To Equivalent Value
---------- ---- --------- ----------------
arr int [2][2] int (*)[2] &arr[0][0]
&arr int (*)[2][2] &arr[0][0]
*arr int [2] int * &arr[0][0]
arr[i] int [2] int * &arr[i][0]
&arr[i] int (*)[2] &arr[i][0]
*arr[i] int arr[i][0]
arr[i][j] int
&arr[i][j] int *
So arr, &arr, arr[0], &arr[0], and &arr[0][0] all evaluate to the same value (the address of the first element of an array is the same as the address of the array itself), but the types are all different.
A very important point I want to get across (especially because it's shown up in a couple of other answers) is that array objects do not store any pointer values. If you looked at the contents of arr in memory, you'd see something like the following:
+---+
arr: | 6 | arr[0][0]
+---+
| 2 | arr[0][1]
+---+
| 3 | arr[1][0]
+---+
| 4 | arr[1][1]
+---+
No storage is set aside anywhere for any pointers. When your code is compiled, any expressions that refer to arrays are replaced with pointers to the first element of the array.
arr is an array of arrays of integers while ptr is a pointer to an integer. In an array of arrays you need two levels of indirection to reach an integer (arr[0][0]) while in a pointer you need just one (ptr[0]). You can assign an array of elements of a certain type to a pointer to an element of the same type, but not if the types are different which is the case here.
As you can see, they are two different things so the compiler does a good job on whining on your assignation.
2D arrays contain (as arrurri mentioned) a pointer which points to an array of pointers and each of those point to the actual elements. So, arr is a pointer to pointers and each indexed value of it (arr[i]) is a pointer to a row.
So, what you need to do is ptr=arr[0]; instead.
This question already has answers here:
How come an array's address is equal to its value in C?
(6 answers)
Closed 7 years ago.
The following program prints that a and array share the same address.
How should I understand this behavior?
Is it &arr the address for the pointer arr, which contains the beginning address the 10 chars?
#include <stdio.h>
int main()
{
char arr[10] = {0};
char* a = (char*)(&arr);
*a = 1;
printf("a=%p,arr=%p.\n", a, arr);
printf("%d\n", arr[0]);
return 0;
}
When you allocate an array in C, what you get is something like the following:
+---+
arr[0]: | |
+---+
arr[1]: | |
+---+
...
+---+
arr[N-1]: | |
+---+
That's it. There's no separate memory location set aside for an object named arr to store the address of the first element of the array. Thus, the address of the first element of the array (&arr[0]) is the same value as the address of the array itself (&arr).
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.
So the type of the expression arr in the first printf call is char [10]; by the rule above, the expression "decays" to type char *, and the value is the address of arr[0].
In the expression &arr, arr is the operand of the unary & operator, so the conversion isn't applied; instead of getting an expression of type char **, you get an expression of type char (*)[10] (pointer to 10-element array of char). Again, since the address of the first element of the array is the same as the address of whole array, the expressions arr and &arr have the same value.
In idiomatic C, you should write char *a = arr; or char *a = &(arr[0]);. &arr is normally a char **. Even if modern (C++) compilers fixe it automatically, it is not correct C.
As arr is an array of char, arr[0] is a char and arr is the same as &(arr[0]) so it is a char *. It may be strange if you are used to other languages, but it is how C works. And it would be the same if arr was an array of any other type including struct.
The address printed out by arr and a is the memory address of the first element of the array arr. (Remember, the name of an array is always a pointer to the first element of that array.) This is because after you have defined the array arr, you define a as a pointer to the same address in memory.
According to the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
The address of an array is the address of its first element. So though these types are different
char ( * )[10] ( that corresponds to &arr ) and char *(that is used in the casting in statement
char* a = (char*)(&arr); ) they will have the same value that is the address of the first element of the array.
If you would not use the casting then the correct definition of the pointer initialized by expression &arr would be
char ( *a )[10] = &arr;
The difference is seen then the pointer is incremented. For your definition of pointer a the value of expression ++a will be greater sizeof( char) than the initial value . For the pointer I showed the value of expression ++a will be greater 10 * sizeof( char ) than the initial value.
In your case the type of expression *a is char and you may write *a = 1; while in my case the type of expression *a will be char[10] and you may not write *a = 1;
Why when using a matrix as a parameter of a function we must specify the number of columns but we don't have to indicate number of rows?
I assume you're talking about a function definition like
void foo( int matrix[][COLS] ) { ... }
This requires a little background...
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. So, given the declaration
int arr[10];
the expression arr will have type "10-element array of int"; unless this expression is the operand of the sizeof or unary & operators, it will be converted ("decay") to an expression of type "pointer to int". So if we pass that array to a function, like
blurga( arr );
what blurga receives is a pointer to int, not an array of int. So we can define blurga as
void blurga( int *ap )
{
// do something with ap[i]
}
The formal parameter ap has type "pointer to int". Note that you can use the [] operator on pointer expressions as well as array expressions1.
Now, in the context of a formal parameter declaration, T a[N] and T a[] are interpreted as T *a; all three declare a as a pointer to T, not an array of T. So we can rewrite that function definition as
void blurga( int ap[] )
{
// do something with ap[i]
}
Again, int ap[] is interpreted exactly the same as int *ap.
Now let's look at a two-dimensional array:
int blah[10][10];
The expression blah has type "10-element array of 10-element array of int". Going by the conversion rule above, the expression blah will decay to an expression of type "pointer to 10-element array of int", or int (*)[10]. So if we pass blah to a function, what the function receives is a pointer to an array, not an array of arrays:
void bletch( int (*barr)[10] );
As before T a[] is interpreted as T *a, so we can write that declaration as
void blech( int barr[][10] ); // barr[] == (*bar)
Just remember that barr is a pointer type, not an array type.
1. In fact, a[i] is defined as the result of *(a + i); given a pointer value a, we offset i elements from that address and dereference the result. So basically, the conversion rule still applies; the array expression a is being converted to a pointer expression, and that pointer expression is what the [] is being applied to.
As we know, array name can't be assigned, sentence like:
char * array[], * point;
array = point; /* wrong */
array++; /* wrong */
But in main(int argc, char * argv[]), argv++ is ok and works well.
What do i missing?
In your examples array is a true array, and thus a non-modifiable l-value. In main, since it's declared in the parameter list, argv is actually a char **, i.e. a pointer which is modifiable.
It all boils down to the fact that char *array[] means different things, depending on the context.
In the context of a function parameter declaration, T a[] and T a[N] are both interpreted as T *a; in all three cases, a is declared as a pointer to T, not an array of T. Thus, in int main(int argc, char *argv[]), argv is really declared as char **, or pointer to pointer to char, not array of pointer to char.
(edit -- note that this is true only for function parameter declarations; for a regular variable declaration, T a[N] and T a[] both declare a as an array of T).
Since it's a pointer value, it can be assigned to and it can be incremented.
Beyond that, here's what the language standard has to say:
5.1.2.2.1 Program startup
...
2 If they are declared, the parameters to the main function shall obey the following
constraints:
...
— The parameters argc and argv and the strings pointed to by the argv array shall
be modifiable by the program, and retain their last-stored values between program
startup and program termination.
EDIT
And here's the language for function parameters:
6.7.6.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
EDIT2
Some examples (assumes a C99 compiler):
void foo(int a[], size_t len)
{
size_t i;
printf("sizeof a = %zu\n", sizeof a);
printf("sizeof (int *) = %zu\n", sizeof (int *));
for (i = 0; i < len; i++)
printf("a[%zu] = %d\n", i, *a++);
}
int main(void)
{
int a1[5] = {0};
int a2[] = {0, 1, 2, 3, 4};
printf("sizeof a1 = %zu\n", sizeof a1);
printf("sizeof a2 = %zu\n", sizeof a2);
foo(a1, sizeof a1 / sizeof a1[0]);
foo(a2, sizeof a2 / sizeof a2[0]);
return 0;
}
One more piece of standardese:
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. If the array object has
register storage class, the behavior is undefined.
In the function main, a1 and a2 have been declared as 5-element arrays of int; a2 gets its size from the number of elements in the initializer. The expressions a1 and a2 thus have types "5-element array of int" and they may not be targets of an assignment expression, nor may they be operands to the ++ or -- operators. When these expressions appear in the call to foo, their types are converted to "pointer to int" per the rule above. Thus foo receives a pointer value, not an array value, for a (which is covered by the rule that says array parameters are converted to pointer types). So the expression a in foo has type int *, or pointer to int; thus, a may be the target of an assignment, and it may be an operand of ++ and --.
One more difference: per the rule quoted above, the conversion to a pointer type doesn't happen when the array expression is an operand of the sizeof operator; sizeof a1 should evaluate to the number of bytes taken up by the array a1 (5 * sizeof int). However, since a in foo has type int *, not int [5], sizeof a should only evaluate to the number of bytes for an pointer to int (sizeof (int *)).
main(int argc, char * argv[])
or
main(int argc, char **argv)
are same and correct .Because in function arguments array are decayed into pointers
For more read this
But the code you have shown is the actual array . And name of the array gives the address of the first element and it's non modifiable that's why doing this :
array = point;
array++;
is wrong as you have already mentioned it.