C pointer to 2D arrays - c

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].

Related

Indirection in C with Multidimensional Arrays

I would like to execute something like the following code, but I keep getting a warning for levels of indirection.
It is my understanding that in the following,
int Array1[5];
int Array2[2][4];
int *pointer1 = Array1;
int *pointer2 = Array2;
all 4 examples have the level of indirection of (int*).
But it seems like no matter what combination of the following ideas I try to compile the code, I get indirection warnings:
void loadIntArrayData(int size, int *buffer);
void passArrayIntoThisFunction(char count, int *structure){ //idea 1
void passArrayIntoThisFunction(char count, int **structure){ //idea 2
void passArrayIntoThisFunction(char count, int structure[][3]){ //idea 3
loadIntArrayData(3*count*sizeof(int), structure); //idea 1
loadIntArrayData(3*count*sizeof(int), &(structure[0][0])); //idea 2
loadIntArrayData(3*count*sizeof(int), &(structure[0])); //idea 3
loadIntArrayData(3*count*sizeof(int), structure[0]); //idea 4
}
int main(void){
passArrayIntoThisFunction(2, (int[][3]){{1,2,3},{4,5,6}});
//I want to have a multi-level array ^ here ^ for readability
return 0;
}
Could someone explain levels of indirection when it comes to multi-dimensional arrays?
Here is the warning (small variations depending on which combination used):
'function': 'int *' differs in levels of indirection from 'int[2][3]'
In C, the name of an array decays to the pointer of its first element in all cases but three: usage of the & (address-of) operator, usage of the sizeof operator, and literal string initialization (e.g. char a[] = "foobar";)
Therefore, in int *pointer2 = Array2; your Array2 decays to a int (*)[] (pointer-to-array-of-int) and not an int *.
If you have an array like for example this
int Array2[2][4];
when used in expressions (with rare exceptions) in particularly as an initializer it is converted to pointer to its first element. The elements of the array have the type int[4]. So a pointer to the first element of the array will have the type int( * )[4].
Thus you may write
int Array2[2][4];
int ( *pointer2 )[4] = Array2;
As for this function declaration
void passArrayIntoThisFunction(char count, int structure[][3]);
and its call
passArrayIntoThisFunction(2, (int[][3]){{1,2,3},{4,5,6}});
then the compound literal used as an argument has the type int ( * )[3] and the corresponfing function parameter is adjusted by the compiler to int ( *structure )[3].
So if you want to pass this pointer further to another function then either a corresponding parameter of the function must have the same type or it can have the type int * but in this case you have explicitly to cast the passed pointer to the type int *.

C program will not compile: it shows "lvalue" error

#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.

initialization from incompatible pointer type during array initialization

I have below code :
int main()
{
int* abc[] ={
[3] = (&(int[3]){1,2,3}),
[2] = (&(int[2]){4,5})
};
printf("\n abc[3][1] = %d \n",abc[3][1]);
return 0;
}
I am trying to set up my array abc , so that specific indexes of the array point to a different array of integers.
Later, I would modify this to use macros so that array is initialized during pre-processing, hence such an approach.
Code works fine but I get a warning :
warning: initialization from incompatible pointer type
Is this because my array abc is declared to point to integer but it is actually pointing to array of integers?
How can I make this warning go away?
The types you're using in the compound literals are incorrect.
The elements of the array are int *, but when using &, the types of the compound literals are int (*)[3] and int (*)[2].
It should be:
int* abc[] ={
[3] = ((int[3]){1,2,3}),
[2] = ((int[2]){4,5})
};
Now int[3] and int[2] both decay to int *.

reducing array by reassigning it to one of its elements with & operator in c

I wrote a simple recursive function for binary search that takes three arguments: an array of integers, the length of the array and a value to find. The idea is that at every recursive call it either halves the length and keeps the array[0] in place or moves the starting index to the middle (third line from the bottom in my sample). That is until the value is found or length is 0.
Then I saw this disccussion: How do you shift the starting index of an array in C?
It is said here that an array name is a constant and cannot be reassigned in C. So my question is why this code works?
int rsearch( int needle, int haystack[], int size ) {
if (size == 0) {
printf("%i not found\n", needle);
return 0;
}
int mid = size / 2;
if (haystack[mid] == needle) {
printf( "found %i in the array\n", needle );
return 1;
} else if (haystack[mid] > needle) {
return rsearch( needle, haystack, size / 2 );
} else {
haystack = &haystack[mid + 1];
return rsearch( needle, haystack, (size - 1) / 2 );
}
I'm just studying, and my knowledge of pointers is very limited. And there's no practical application here. Just curious.
P.S.
The other question is what happens to the memory allocated to the original array when it's reduced this way? Is it made available again or is it a memory leak?
Arrays when used as function arguments actually mean a pointer to an array, but not the array as value. So the following function signatures are equivalent: void test(int xptr[10]), void test(int xptr[]), and void test(int *xptr).
At the point where an array is defined, however, you can only initialise it's value, but you cannot assign any other value later on.
When you pass an array, let's say int x[10] to a function by just using x as parameter, like in test(x), then array x automatically decays to a pointer to the first element of x.
See the following code showing the difference:
#include <stdio.h>
void test(int xptr[10]) {
printf("value of xptr[0]: %d\n", xptr[0]); // -> 0
xptr = &xptr[2]; // OK; xptr will point to element 2
printf("value of xptr[0]: %d\n", xptr[0]); // -> 2
}
int main(){
int x[10] = { 0,1,2,3,4,5,6,7,8,9 };
// x = &x[2]; // Error: Array type 'int [10]' is not assignable
// but:
test(x); // OK; and is eqivalent to...
test (&x[0]); // OK;
return 0;
}
As a function argument, this:
int haystack[]
Is equivalent to:
int *haystack
This is mainly because an array decays to a pointer to the first element when passed to a function.
So what you have is not an array but a pointer. Unlike an array, a pointer is a modifiable lvalue, so it is allowed to assign to it.
According to the C Standard (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’’...
and (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.
Thus in this function declaration
int rsearch( int needle, int haystack[], int size );
the parameter int haystack[] is adjusted to int *haystack. So these function declarations
int rsearch( int needle, int haystack[100], int size );
int rsearch( int needle, int haystack[10], int size );
int rsearch( int needle, int haystack[], int size );
int rsearch( int needle, int *haystack, int size );
declare the same one function. You may include all these declarations in your program because a function declaration may appear more than one time. However the function shall be defined only one time (if it is not an inline function).
Accordingly the array passed to the function as argument is implicitly converted to pointer to its first element.
Take into account that it would be better to declare the function like
int rsearch( int needle, const int *haystack, int size );
^^^^^
In this case the function can be used also with constant arrays.
It is said here that an array name is a constant and cannot be
reassigned in C.
It would be correctly to say that array is not a modifiable lvalue.
From the C Standard (6.5.16 Assignment operators)
2 An assignment operator shall have a modifiable lvalue as its left
operand.
and (6.3.2.1 Lvalues, arrays, and function designators)
...A modifiable lvalue is an lvalue that does not have array type,...

Error: incompatible types when assigning to type ‘char[25]’ from type ‘char *’

I'm trying to assign the values of a struct to a map but the following error message appears after compiling:
error: incompatible types when assigning to type ‘char[25]’ from type ‘char *’
in
map[i].n=m.n
My struct is defined this way:
struct m1{
int c;
char n[25];
int q_m;
int q;};
Part of my code:
struct m1 m;
struct m1 *map = 0;
scanf("%d",&m.c);
scanf("%s",&m.n);
scanf("%d",&m.q_m);
scanf("%d",&m.q);
map[i].c=m.c;
map[i].n=m.n;
map[i].q_m=m.q_m;
map[i].q=m.q;
Array expressions may not be the target of an assignment; the = operator isn't defined to copy the contents of one array to the other.
If n is meant to hold a 0-terminated string, use strcpy:
strcpy( map[i].n, m.n );
If n is meant to hold a non-0-terminated string (or a sequence of characters with embedded 0 values), use memcpy:
memcpy( map[i].n, m.n, sizeof map[i].n );
Unless 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.
That's why you got the error message you did; the expression m.n has type "25-element array of char"; since it wasn't the operand of the sizeof or unary & operators, it was converted to type char *. map[i].n wasn't converted (it stayed type char [25]), but as I said earlier, array expressions may not be the target of the assignment operator.
Array variables cannot be an lvalue to the assignment operator, that is they cannot be assigned anything.
To copy an array, copy element by element or use a "low-level" function like memcpy() to copy a specific amount of memory at once:
memcpy(map[i].n, m.n, sizeof map[i].n);
First you need to allocate memory for map.
struct m1 *map = malloc(sizeof(struct m1));
and use strcpyto copy m.n to map->n.
struct m1 *map;
map is a pointer and you should be allocating memory to it before writing something to it.
map = malloc(sizeof(struct m1) * n);
Then you can have
map[i]
After this fix string copy
strcpy(map[i].n,m.n);
It seems like what you most likely want to do (besides allocating memory for the struct) is copying the contents of the array pointed to by n, instead of only copying the actual pointer.
strcpy(map[i].n, m.n);
Looks like you are trying to assign directly m.n value to the array.
Please see below detail Example :
#include<stdio.h>
#include<stdlib.h>
struct db{
int db_num;
char db_name[10];
};
int main()
{
struct db *ptr;
ptr = (struct db*)malloc(sizeof(struct db));
ptr->db_num = 10;
ptr->db_name = "xyz";
printf("Input data Base:\n");
printf("db_num:%d db_name:%s",ptr->db_num,(char*)ptr->db_name);
return 0;
}
In the above code snippet I am trying to assign "XYZ" to the array which is the member of struct db.
It through the similar Error because of ptr->db_name = "xyz";
st_dyna_mem.c:14: error: incompatible types when assigning to type ‘char[10]’ from type ‘char *’
Fix :
For Fixing this type of issue you Can use strcpy() or memcpy().
EX:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct db{
int db_num;
char db_name[10];
};
int main()
{
struct db *ptr;
ptr = (struct db*)malloc(sizeof(struct db));
ptr->db_num = 10;
strcpy(ptr->db_name,"xyz");
printf("Input data Base:\n");
printf("db_num:%d db_name:%s",ptr->db_num,(char*)ptr->db_name);
return 0;
}
Output:
db_num:10 db_name:xyz
You copy all of the structure members. The simplest way to do that is:
map[i]=m;

Resources