#include <stdio.h>
int main()
{
int ary[2][3];
foo(ary);
}
void foo(int (*ary)[3])
{
int i = 10, j = 2, k;
ary[0] = &i;
ary[1] = &j;
for (k = 0;k < 2; k++)
printf("%d\n", *ary[k]);
}
I tried it with many different compilers but I do not understand why this will not compile.
You're assigning to an expression with an array type.
ary inside foo is a variable of type "pointer to array of three ints".
When you assign to it, you're trying to assign a variable of type "pointer to int" to a variable of type "array of three ints".
This is invalid because an array is not an lvalue (6.3.2.1p3):
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.
#include <stdio.h>
void foo(int (*ary)[3]);
int main()
{
int ary[2][3];
int (*x)[3] = &ary[0];
foo(&ary[0]);
}
void foo(int (*ary)[3])
{
int i = 10, j = 2, k;
*ary[0] = i;
*ary[1] = j;
for (k = 0;k < 2; k++)
printf("%d\n", *ary[k]);
}
In C language array, structure and union always pass by with reference. C language not strictly check reference type and also support implicit casting.
void foo(int (*ary)[3]) this is a syntax of passing a function to a function as reference (call back function). but you trying to assign a value to function which is implicitly cast by c does not matter you pass a array reference. that why its showing lvalue error.
LValue implies that if you assign some value using assignment operator (=) there left side must be a variable but in your case it's a callback reference.
Hope its help.
Related
I am learning some of the basics of C, and am currently stepping my way through arrays and more specifically how passing by reference works. When the below code is run it returns 10 22. When I read through the code however, based on the last command it seems as though the variable a should return 22 instead of 10 (meaning the full output would be 22 22 instead of 10 22). Why would the variable a not update to 22 in this code?
#include <stdio.h>
void set_array(int array[4]);
void set_int(int x);
int main(void)
{
int a = 10;
int b[4] = { 0, 1, 2, 3 };
set_int(a);
set_array(b);
printf("%d %d\n", a, b[0]);
}
void set_array(int array[4])
{
array[0] = 22;
}
void set_int(int x)
{
x = 22;
}
Arrays are [loosely] "pass by reference". Actually, the array "decays" into an int *.
But, scalars are "pass by value".
In set_int, you set the function scoped copy of x but do not return it to the caller.
Here's the refactored code, with a "call by reference" example:
#include <stdio.h>
void
set_array(int array[4])
{
array[0] = 22;
}
int
set_int(int x)
{
x = 22;
return x;
}
void
set_int_byptr(int *x)
{
*x = 37;
}
int
main(void)
{
int a = 10;
int b[4] = { 0, 1, 2, 3 };
int c = 4;
#if 0
set_int(a);
#else
a = set_int(a);
#endif
set_array(b);
set_int_byptr(&c);
printf("a=%d b=%d c=%d\n", a, b[0], c);
return 0;
}
In C if you want to modify variable passed to function you need to pass the pointer to it:
examples:
int setval(int *obj, int value)
{
*obj = val;
return val;
}
void usage()
{
int x;
setval(&x, 22);
}
void *setpointer(void **ptr, size_t size)
{
*ptr = malloc(size);
return *ptr;
}
void usage1()
{
int *array;
setpointer(&array, 200*sizeof(*array));
}
First we need to get this out of the way, because I honestly believe it will make things less confusing - C does not pass any function arguments by reference, ever. C passes all function arguments by value. Sometimes, those values are pointers. This is not the same thing as pass-by-reference.
Among other things, pass-by-value means that any changes to a formal parameter are not reflected in the actual parameter. In your set_int function, x is a distinct object from a, and any changes to x do not affect a.
If we want a function to modify the value in a parameter, we must pass a pointer to that parameter:
void set_int( int *x )
{
*x = 22; // writes a new value to the thing x points to
}
int main( void )
{
int a = 10;
set_int( &a ); // foo writes a new value to a
return 0;
}
In the above code, we want the function set_int to update the variable a, so we must pass a pointer to a to the function.
x == &a // int * == int *
*x == a // int == int
Thus, writing a new value to the expression *x in set_int is the same as writing a new value to a in main. Any change to x itself is local to set_int.
Things get confusing when we add arrays to the mix. An array is not a pointer; however, unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character 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.
When you call set_array(b), the expression b "decays" from type "4-element array of int" (int [4]) to type "pointer to int" (int *), and the value of the expression is the same as &b[0].
Here's another confusing thing - in a function parameter declaration, array declarations of type T a[N] and T a[] are interpreted as T *a - a is a pointer to T, not an array of T. So your prototype
void set_array(int b[4])
is interpreted as
void set_array(int *b)
and what it receives is a pointer to the first element. As a practical matter, this means that any changes to array[i] in set_array are reflected in b, but this is fallout from how C specifically treats array expressions, not a difference in parameter passing mechanisms. The argument is still being passed by value, it's just that the argument is a pointer value that's the result of a well-defined conversion operation on array expressions.
You are doing 2 things over here:
1) Pass by value:
the function set_int(), its parameter is passed simply, without any address, which means it is pass by value, and any change made by this function set_int() will not be reflected in the calling function.
2) Pass by reference:
However, in the case of set_array(b), you are passing the array to the called function, and its base address will be passed (Means address of first element of b, that is &b[0]), hence this is pass by reference and any change is made to this value will be reflected in the calling function
which is the reason 22 is updated for b, but 22 didn't get update for a
Throughout my c codes. ignore confusing identifier name. Reason what in assignment of ptr61 pointer i have to put address (&) operator, while & is needless in assignment of ptr62 pointer.
int var6[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
int (*ptr61)[][4];
ptr61 = &var6;
printf("lvl 9: %d\n", (*ptr61)[2][0]);
int (*ptr62)[4];
ptr62 = var6;
printf("lvl 9: %d\n",*(*(ptr62 + 1)+2));
An array designator used in expressions like for example as initializer is implicitly converted to pointer to its first element.
So if you have an array like this
int var6[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
then this declaration declares an array of 3 elements of the type int[4]. Thus pointer to element of the array will have the type int ( * )[4] and you may write
int (*ptr62)[4] = var6;
If you will write
ptr62 = &var6;
you will get a compiler error because in the left side hand of the assignment there is an object of the type int( * )[4] while in the right hand side there is an object of the type int( * )[3][4] and these types are not compatible and there is no implicit conversion from one type to another.
If you want to declare a pointer to the whole array that has the type int[3][4] then such a pointer will have the type int ( * )[3][4] and you may write
int (*ptr61)[3][4] = &var6;
As for this declaration
int (*ptr61)[][4] = &var6;
then it declares a pointer to the incomplete array type int[][4].
I have two different code examples. In the first code it is possible to dereference:
void getValue(int *myPointer)
{
*myPointer = 10000;
return;
}
int main()
{
int get_the_value = 2;
getValue(&get_the_value);
printf("The value of get_the_value = %d\n", get_the_value);
return 0;
}
But in the code below it is not possible to dereference *B in func().
I have this code below from the internet and they said this:
"B is a pointer to int, thus B[0] is an int, and you can't dereference an int. "
But is *myPointer in the first code not an int type too?
So my question is: Why does dereferencing work in the first code but not in the second code?
#include <stdio.h>
int func(int *B){
*B[0] = 5;
}
int main(void){
int B[3] = {1, 2, 3};
printf("b[0] = %d\n\n", B[0]);
func(&B);
printf("b[0] = %d\n\n", B[0]);
return 0;
}
B[0] is the same as *(B + 0), which is the same as *B, all of which have type int. So given the type of B, you can write either B[0] or *B.
Edit
You have a type mismatch which isn't helping things.
You've declared the parameter B in func to have type int *; like I said above, the expression B[0] is equivalent to *(B + 0), which is equivalent to *B. IOW, the subscript operator implicitly dereferences B.
In main, you've declared B as a 3-element array of int, so the type of the expression B is int [3]. Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type T [N] will be converted ("decay") to an expression of type T *, and the value of the expression will be the address of the first element of the array.
However, when you call func, you pass the expression &B, which has type int (*)[3] (pointer to 3-element array of int). int * and int (*)[3] aren't compatible types. Now, it just so happens that both the expressions B and &B will evaluate to the same location (address of the first element of B), so the code will still "work" if you write either *B or B[0]. However, you should change the call to func to be
func( B ); // no & operator.
Then the types will match up.
I am getting an error in the return line. "Incompatible pointer to integer conversion returning 'int (*)[2]' from a function with result type 'int'" can someone explain what is theory behind this error and how to fix it? still I am getting right result, but don't know about this error. (hints: I am very beginner )
here is my testing code.
#include <stdio.h>
#include<string.h>
/* two diminsanl array testing*/
int array_function(int phase,int array[][2]);
int main()
{
int phase =1;
int array[][2]={};
array_function(phase, array);
phase =2;
array_function(phase, array);
return 0;
}
int array_function(int phase, int array[][2])
{
if(phase==1)
{
array[0][0]=1;
array[0][1]=2;
array[1][0]=3;
array[1][1]=4;
}
if(phase==2)
{
printf("%d\n",array[0][0]);
}
return array; //<------------- error line
}
Well, first of all, your function is expecting an int return, but you're trying to return an int[][].
And, you can't return an array by value in c. You'll need to return a pointer, or wrap the array as part of a struct.
You have int as return type of function ( int array_function() ) but are trying to return a pointer(return array;). Since it look that you don't need to return anything just have the return type as void or return 0. Since array is passed by reference it automatically gets the changes that you do to it inside the function.
If you statically create an array you have to specify both dimensions.
Arrays are passed as pointers and if you pass a static array it is good practice to give the dimensions in the parameters of the function. Simply pass the arrays name to any function even if you allocated it dynamically. If you want to return an array you should return an int* or int** for a 2D array.
Let's say you want to create an array in a function and let the caller have it.
int *createArray(int size)
{
int *array = malloc(size * sizeof(int));
return array;
}
You can call this function from your main.
int *list;
list = createArray(2);
And modify list like any other array.
This is your code properly.
#include <stdio.h>
/* two diminsanl array testing*/
void array_function(int phase, int array[2][2]);
int main()
{
int phase = 1;
int array[2][2];
array_function(phase, array);
phase = 2;
array_function(phase, array);
return 0;
}
void array_function(int phase, int array[2][2])
{
if (phase == 1)
{
array[0][0] = 1;
array[0][1] = 2;
array[1][0] = 3;
array[1][1] = 4;
}
if (phase == 2)
{
printf("%d\n",array[0][0]);
}
}
First this line, is not a legal assignment:
int array[][2]={};
For what you are doing, this line would work:
int array[][2]={0,0,0,0};
second As others have pointed out, this line is attempting to return int[][]. Two problems with this, 1) C cannot return the value representation of an array of ints, (although it can return pointers, such as int **, you don't need to here. See note at bottom). And 2) the prototype clearly calls for int
return array; //<------------- error line
For now, simply change the line to:
return 0;
Those two changes will result in your code populating array[][] with no errors.
Note: because you are passing your array by reference, ( array_function(phase, array); ) the values assigned to array within array_function() are made available back in the main() function without having them returned as a return. (i.e. int ** array_function(phase, array) )
So, first of all, the type of the expression array in array_function is int (*)[2], or "pointer to 2-element array of int".
Except when it is the operand of the sizeof or unary & operator, 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.
When you call phase_array from main, like so:
array_function(phase, array);
the expression array has type "2-element array of 2-element array of int"; since it is not the operand of the sizeof or unary & operators, it is converted to an expression of type "pointer to 2-element array of int", and its value is set to the address of the first element (&array[0]). This pointer value is what gets passed to array_function.
In the context of a function parameter list, declarations of the forms T a[N] and T a[] will be interpreted as T *a; all three declare a as a pointer to T. So,
int array_function(int phase, int array[][2])
is the same as
int array_function(int phase, int (*array)[2])
Which brings us to your error message: you've declared array_function to return an int (which you don't ever use in your main function, btw), but the type of the expression array is int (*)[2]; hence the error message. The two types are not *compatible", and the compiler flags this as an error.
Since you've passed the address of the first element of array to array_function, any changes you make to the array contents will be reflected in main, so you really don't need to return the array. As others have suggested, just change the type of the function to void and don't return anything.
i had a question in my program. When I pass the 3D int array CodedGreen to the function Green_Decode_Tree. An error message"invalid use of array with unspecified bounds" displayed. What is the mistake in my program? Thanks for your help.
for(i=0;i<256;i++){
for(j=0;j<256;j++){
Decode_Tree(green[0], CodedGreen,0,i,j);
}
}
void Green_Decode_Tree(node* tree, int code[][][], int num,int row,int col)
{
int i;
i=num;
if((tree->left == NULL) && (tree->right == NULL)){
fprintf(DecodGreen,"%s\n", tree->ch);
}
else
{
if(code[row][col][num]==1){
i++;
Green_Decode_Tree(tree->left,code,i,row,col);
}
else if (code[row][col][num]==0){
i++;
Green_Decode_Tree(tree->right,code,i,row,col);
}
}
}
i will reveal you a secret. 2d (and 3d) arrays are represented as liner memory arrays. when you have array NxM and access it like a[i][j] it is actually translated to a[i*M + j] as you might notice compiler must know M here to do this conversion, otherwise it will not be able to translate it. So thats what he asks. You must provide all except first sizes in array: int code[][M][N]
Remember that in most contexts, array expressions have their types implicitly converted ("decay") from "N-element array of T" to "pointer to T" and evaluate to the address of the first element. When you pass CodedGreen (type int [X][Y][Z]) to Green_Decode_Tree, what the function receives is a pointer value of type int (*)[Y][Z].
So your prototype for Green_Decode_Tree needs to be
void Green_Decode_Tree(node *tree, int (*code)[Y][Z], int num, int row, int col)
Note that in the context of a function parameter declaration, int *a is synonymous with int a[] (no size), so int (*code)[Y][Z] could also be written as int code[][Y][Z]. I prefer using pointer notation, since that's what the function actually receives, but either will work. Note that in your function you will subscript it as normal:
if (code[row][num][col] == 1)
since the subscript operator implicitly dereferences the pointer (i.e., code[row] == *(code+row)).
This may be helpful:
Declaration Expression Type Decays to
----------- ---------- ---- ---------
T a[X]; a T [X] T *
&a T (*)[X]
T b[X][Y]; b T [X][Y] T (*)[Y]
&b T (*)[X][Y]
b[i] T [Y] T *
&b[i] T (*)[Y]
T c[X][Y][Z]; c T [X][Y][Z] T (*)[Y][Z]
&c T (*)[X][Y][Z]
c[i] T [Y][Z] T (*)[Z]
&c[i] T (*)[Y][Z]
c[i][j] T [Z] T *
The expressions a, b, b[i], c, c[i], and c[i][j] are all array expressions, so their types will decay to pointer types in most contexts. The exceptions are when the array expressions are operands of the sizeof or address-of & operators (as is shown in the table), or when the array expression is a string literal being used to initialize another array in a declaration.