Passing a multidimensional array as an argument in C - arrays

I am trying to initialize matrices in a helper function, but I am getting a warning accessing the matrix inside the helper function that I can't figure out how to fix. I was reading about multidimensional arrays and even saw the same notation used to pass and access a matrix in multiple examples, but mine generates a warning and I'm not quite sure why.
To my knowledge this error means that the argument is not of a type the function is expecting, but I was using it just fine inside the main function before relocating the initialization into its own function. This leads me to think that I'm doing something wrong when passing the matrix to the helper function.
passing argument 1 of 'memmove' makes pointer from integer without a cast [-Wint-conversion]
Here's my code for the initializer. p is a pointer to data inside an array that I want to initialize into my matrix. I'm using this type of nested for loop to spread 16 bytes of data coming from p into my matrix 1 byte per cell.
void initialize(const unsigned char *p, unsigned char (*matrix)[4]) {
for (unsigned int i = 0; i < 4; i++){
for (unsigned int j = 0; j < 4; j++){
memmove(matrix[i][j], p + (4*i+j), 1); <--- Warning here
};
};
};
Initialize is being called in another function like this:
void func(const unsigned char *p) {
unsigned char matrix[4][4] = {
{0x0,0x0,0x0,0x0},
{0x0,0x0,0x0,0x0},
{0x0,0x0,0x0,0x0},
{0x0,0x0,0x0,0x0}
};
initialize(p, matrix);
};

Function memmove() takes a pointer as the first argument. While matrix[i][j] is a char, a type from integer family. Assingning an integer other than constant 0 to a pointer require a cast. Otherwise a warning is raised.
Therefore I expect that in order to copy a single char you should pass a pointer to element matrix[i][j]. Pointers are formed by applying & operator to objects.
memmove(&matrix[i][j], p + (4*i+j), 1);
however it can written far simpler, more readable and likely more optimal as:
matrix[i][j] = p[4 * i + j];
or even by copying the whole array without any loops:
memmove(matrix, p, 16);

passing argument 1 of 'memmove' makes pointer from integer without a cast [-Wint-conversion]
Instead of passing an integer value as the destination:
unsigned char (*matrix)[4]
...
// v----------v This is an integer of type unsigned char
// memmove(matrix[i][j], p + (4*i+j), 1);
Pass the address of the integer as the destination:
memmove(&matrix[i][j], p + (4*i+j), 1);
// ^-----------^ This is an address
void *memmove(void *s1, const void *s2, size_t n); expects s1 to be an address.
matrix in func() is a matrix, aka "2-D array".
matrix in initialize() is not really a matrix, but a pointer to an array[4] of unsigned char.
Since C99 and selectively afterwards, code can use a variable length array notation.
void initialize(size_t rows, size_t cols, unsigned char (*m)[rows][cols],
const unsigned char *p) {
printf("%zu %zu %zu\n", rows, cols, sizeof *m);
for (size_t r = 0; r < rows; r++){
for (size_t c = 0; c < cols; c++){
(*m)[r][c] = *p++;
}
}
}
#define ROW 5
#define COL 7
int main(void) {
unsigned char matrix[ROW][COL];
unsigned char bytes[sizeof matrix] = "Something abcde fghij klmno pqrst uvwxy z";
size_t r = sizeof matrix / sizeof matrix[0];
size_t c = sizeof matrix[0] / sizeof matrix[0][0];
printf("%zu %zu %zu\n", r, c, sizeof matrix);
initialize(r, c, &matrix, bytes);
}

Related

How do I fill an array inside a struct using offsetof() and pointers in C

I have a struct
typedef struct _st_L3 {
int e;
int f;
int bb[5];
int g;
} st_L3;
and I am using offsetof() to get offset of all the elements.
How can I copy values to bb[5] using memcpy, offsetof() and knowing address of the base struct?
I tried this:
It goes from 0-4
memcpy((base_address_of_st_L3 + offset + sizeof(int)*i ), &int_data, sizeof(int))
How can I copy values to bb[5] using memcpy, offsetof() and knowing address of the base struct?
The following code snipped declares the structure and an array of 5 ints. Then using memcpy it copies the int's into the structure's bb member. I cast the pointer to void* to try to "generalize" the example.
int main() {
st_L3 var;
int array[5]; // int_data
void *pnt = &var; // base_address_of_st_L3
// using operator `[]`
memcpy(&((char*)pnt)[offsetof(st_L3, bb)], array, sizeof(int) * 5);
// using pointer arithmetics
memcpy(((char*)pnt) + offsetof(st_L3, bb), array, sizeof(int) * 5);
// one variable at a time
for (int i = 0; i < 5; ++i) {
memcpy(&((char*)pnt)[offsetof(st_L3, bb) + i], &array[i], sizeof(int));
}
}
Note that doing pointer arithmetics on void* pointers is invalid. That's why a cast to char* is needed.
If I understand your question, you wish to copy and integer to a integer array of size 5?
You can do it this way :
((st_L3*)base_address_of_st_L3)->bb[0] = int_data;
Of course, bb will still have four integers left that won't be initialized.
Or did you mean that int_data is also an array of five integers?
{
int i;
[... snipped ...]
for(i = 0; i < 5; i++)
{
((st_L3*)base_address_of_st_L3)->bb[i] = int_data[i];
}
}

what's *p when p is declared as int (*)[size] and assigned to an array

code:
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
printf("p:%p\n",p);
printf("*p:%p\n",*p);
result: p = *p = arr = 0x7ffee517c830 they are all the address of the array
The right way to use p to visit arr[i] is *(*p+i)
The type of pointer p is int(*)[5], so p point to an array which type is int [5]. But we can't say that p point to an invisible shell of arr, p is a variable after all. It stores the address of arr, which is also the address of arr[0], the first element of arr.
I thought *p will get me 1, which is the first element of arr.
The dereference operation means take the value in p as address and get the value from this address. Right?
So p stores the address of arr,which is 0x7ffee517c830 here, and 1 is stored in this address. Isn't **p illegal? The first dereference give us 1, and second dereference will use 1 as address which is illegal.
What I am missing?
The result of *p is an lvalue expression of array type. Using (*p) is exactly the same as using arr in any expression you could now think of.
For example:
&*p means &arr
**p means *arr (which is legal).
(*p)[i] means arr[i].
sizeof *p means sizeof arr.
Arrays are not special in this regard. You can see the same phenomenon with int x; int *q = &x;. Now *q and x have exactly the same meaning.
Regarding your last paragraph, I think you are confusing yourself by imagining pointers as glorified integers. Some people teach pointers this way but IMO it is not a good teaching technique because it causes the exact confusing you are now having.
If you dereference an int(*)[5] you get an int[5] and that's all there is to it. The data type matters in dereferencing. It does not make sense to talk about "dereferencing 0x7ffee517c830". Again this is not peculiar to arrays; if you dereference a char ***, you get a char ** etc.
The only way in which arrays are "different" in this discussion is what happens if you try to do arithmetic on them, or output them, etc. If you supply an int[5] as a printf argument for example, there is implicit conversion to int * pointing at the first of those 5 ints. This conversion also happens when applying the * operator to an int[5], which is why you get an int out of that.
p is declared as a 'pointer to int[5]'.
arr is declared as an 'int[5]`
so the initializer p = &arr; is not really that strange. If you substituted any primitive type for int[5] you wouldn't bat an eye.
*p is another handle on arr. so (*p)[0] = 1.
This really only comes up in wierd cases. It's most natural where you dereference the pointer-to-array using the subscript operator. Here's a contrived example where I want to pass a table as argument.
#include <stdio.h>
int print_row_range(int (*tab) [2], int first, int last)
{
int i;
for(i=first; i<= last; i++)
{
printf("{%d, %d}\n", tab[i][0], tab[i][1]);
}
}
int main(int argc, char *argv[])
{
int arr[3][2] = {{1,2},{3,4},{5,6}};
print_row_range(arr,1,2);
}
This example treats the table as an array of rows.
Dereferencing doesn't give you a value. It gives you an object, which can be used as a value of its type if it can be converted to.
*p, being identical to arr, is an object of an array of 5 ints, so if you want to get an integer from the array, you must dereference it again like (*p)[3].
Consider a bigger example:
int arr[5][5];
int (*p)[5] = arr;
Now you get arr[0] with *p, which itself is an array of 5. Here comes the difference:
*( p+1) == arr[1];
*(*p+1) == arr[0][1];
^ ^^^
Got the point?
One use case is to be able to allocate with malloc an 2D (or more) pointer of arrays with only one malloc:
#include <stdio.h>
#include <stdlib.h>
static int (*foo(size_t n))[42] {
return malloc(sizeof *foo(0) * n);
// return malloc(sizeof(int [n][42]); works too
}
int main(void) {
size_t n = 42;
int (*p)[42] = foo(n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
I think this very funny.
One more with VLA:
#include <stdio.h>
#include <stdlib.h>
static void *foo(size_t elem, size_t n, size_t m) {
return malloc(elem * n * m);
}
int main(void) {
size_t n = 42;
int (*p)[n] = foo(sizeof **p, n, n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}

Parsing pointer parameter in C

This code take 5 strings and sort them in ascending way.
void swap (char data[5][255], int i, int j) {
char temp[255];
strcpy(temp,data[i]);
strcpy(data[i],data[j]);
strcpy(data[j],temp);
}
void sort (char data[5][255], int n) {
// * : first address contact
int i, j;
for(i = 0; i < n-1; i++)
for( j = i+1; j > 0; j--)
if(strcmp(data[j-1],data[j])>0)
{
printf("%s",data[j-1]);
swap(data, j-1, j);
}
}
int main() {
char strings[5][255];
char comp[255];
int i, n;
n = sizeof(strings)/sizeof(comp);
printf("Enter 5 strings, max 255 chars each:\n");
for(i=0; i < n; i++)
scanf("%s",strings[i]);
sort(strings, n);
printf("Sorted data:\n");
for(i=0; i < n-1; i++)
printf("%s, ",strings[i]);
printf("%s.\n",strings[i]);
return 0;
}
In addition of that, how can I possibly parse my static array string[5][255] to function by using pointer?
I tried that, for example,
void sort ( char **data, int i ) { ... }
but it throws out error like this.
incompatible pointer types passing 'char [5][255]' to parameter of type 'char **'
Is there anything I can parse my array using pointer?
Since array parsed to function its first address(pointer), I thought function will accept those expression. Please give me some advice to understand.
The parameter you must pass is not a pointer to a pointer char**, but a pointer to a char array char(*)[255]
void sort (char (*data)[255], int n)
When you pass an array, you can omit the size of the first dimension
void sort (char data[][255], int n)
which is equivalent to char(*)[255].
char** is a pointer, which points to another pointer. Whereas char(*)[255] is a pointer, which points to an array.
You have to understand the difference between: char **data vs char (*data)[255]
Those are two different types because the allocation of memory may be different:
When char **data is used pointer arithmetic may not work properly, meaning data could be scattered all over the memory
When char (*data)[255] is used pointer arithmetic works perfectly because all elements of array are adjacent to each other
As I wrote you in the comment char[][] doesn't decay to char** but it decays to char(*)[] ( char (*data)[255] in your case) as the first element decay in a pointer which is not a "pointer to a pointer" but a pointer to an array of 255 characters. It is possible to use a char** pointer if you do something like this (c++):
char **array = new char *[N];
for(int i = 0; i<N; i++)
array[i] = new char[N];
or using the malloc (c).
As #newact suggests it is important to distinguish between
char *data[255] -> char *[255]data = => "data is an array of 255 pointers to char"
And
char (*data)[255] -> char [255](*data) => "data is a pointer to an array of 255 chars"
Try to make the following changes:
void swap ( char *data, int i, int j)
*(data + index1*255 + index2)

Devious pointer expression (int*)arr

I'm learning c and I'm finding difficulties with the expression (int*)arr in the line 18. The whole program is
int main () {
char c, arr['z'-'a'], *pChar;
int i, *pInt, int matr = 74 ;
for ( c='a'; c<'z'; c++) {
arr[c-'a'] = c;
printf("%c ", arr[c-'a']);
}
printf("\n");
pChar = arr + matr%15;
for (i=0; i< 5; i++) {
printf("%c ", *pChar);
pChar++;
}
printf("\n");
pInt = (int *)arr + matr%2;
for (i=0; i<5; i++) {
pChar = (char *)pInt;
printf("%c ", *pChar);
pInt++;
}
return 0;
}
Thank you
You declared arr as char type. As the name of an array can be used as a pointer to its first element ; arr is a pointer to first char of array arr and is of type char *.
pInt is of type int *, for the expression
pInt = (int *)arr + matr%2;
a cast is needed to covert arr to int * type in your program.
In C when the name of an array is used as a value it represents the address of the first element (&arr[0]).
In first case (line 11) you have pChar = &arr[matr%15] because pChar is a char*
In second case (line 18) you have pInt = (int *) &arr[matr%15]. You have to cast pointer to char into pointer to int, bacause pInt is a int*
The other answers have been telling you that you need to use a cast to convert arr to int*.
Better: Don't convert arr to int*.
char c, arr['z'-'a'], *pChar;
int i, *pInt, int matr = 74 ;
This would be clearer if you'd declare each variable on a line of its own:
char c;
char arr['z'-'a'];
char *pChar;
int i;
int *pInt;
int matr = 74;
You've declared arr as an array of char. Assuming an ASCII character set, it has 26 characters. You probably wanted it to have 26.
An expression of array type is implicitly converted, in most contexts, to a pointer to its first element. So arr usually becomes an expression of type char*, equivalent to &arr[0].
Converting that char* pointer to int* (which does require a cast) gives you a pointer to an int that overlays the first sizeof (int) elements of the array.
That's a very odd thing to do, and it actually has undefined behavior (arr doesn't necessarily have the proper alignment to store int objects).
If you want to store int objects, declare an array of int.
I haven't studied your code enough to understand what it's intended to do, but there's almost certainly a better way to do it.

C function that takes const 2d array

I want to write a C function that takes a dynamic 2D array as an input, but doesn't alter the array.
I'm trying to be const correct, not only to make my code clearer, but because my functions are going to be called from within C++ code, and C++ is pretty persnickety about these things.
How do I declare a function to take 'const' pointer to a pointer, i.e. how do I indicate that the function will not alter the contents of the 2d array?
What follows is a specific, super-simple example. I'm using a 2D array of doubles, i.e. double**, to represent a square matrix in C of size n x n, and I want to write a function that computes the trace of one of these matrices:
#include <stdlib.h>
#include <stdio.h>
double **sqr_matrix_new(int n)
{
double **a = calloc(n, sizeof(double*));
int i;
for (i=0; i < n; ++i) a[i] = calloc(n, sizeof(double));
return a;
}
void sqr_matrix_free(double **a, int n)
{
int i;
for (i=0; i < n; ++i) free(a[i]);
free(a);
}
double sqr_matrix_trace(double **a, int n)
{
double trace;
int i;
for (i=0, trace=0.0; i < n; ++i) trace += a[i][i];
return trace;
}
double sqr_matrix_trace_const(const double * const *a, int n)
{
double trace;
int i;
for (i=0, trace=0.0; i < n; ++i) trace += a[i][i];
return trace;
}
int main(int argc, char *argv[])
{
int n = 10;
double **a = sqr_matrix_new(n);
int i, j, k;
for (i=0, k=0; i < n; ++i){
for (j=0; j < n; ++j) a[i][j] = k++;
}
printf("trace is %g\n", sqr_matrix_trace(a, n));
printf("trace is %g\n", sqr_matrix_trace_const(a, n));
printf("trace is %g\n", sqr_matrix_trace_const((const double * const *)a, n));
sqr_matrix_free(a, n);
}
In the above, both versions of the trace function, sqr_matrix_trace() and sqr_matrix_trace_const() compile cleanly (the latter is the one I prefer because it clearly demonstrates that there will be no alteration of the matrix it's given), but the call
sqr_matrix_trace_const(a, n)
produces the following warning:
sqr_matrix.c: In function 'main':
sqr_matrix.c:44: warning: passing argument 1 of 'sqr_matrix_trace_const' from incompatible pointer type
sqr_matrix.c:27: note: expected 'const double * const*' but argument is of type 'double **'
The cast overcomes this:
sqr_matrix_trace_const((const double * const *)a, n)
but it feels wrong to use a cast to use to overcome compiler inconveniences.
Alternatively, I could suppress the compiler warning, but that's a cop-out.
So, I want my code to compile cleanly and I want to convey the const-ness of a dynamic 2D array given to a function without resorting to a cast. It seems like a legitimate aim. Is this possible? If not, what's the standard/accepted practice for doing this?
The C const promotion rules don't allow promotion from T ** to const T const *. Per 6.5.16.1 1 (which applies to function calls as well as assignments per 6.5.2.2 2), conversion of pointers can only add qualifiers to the pointed-to type.
This is to prevent code like (example from 6.5.16.1 6):
const char **cpp;
char *p;
const char c = 'A';
cpp = &p; // constraint violation
*cpp = &c; // valid
*p = 0; // valid
It's correct to observe that const *const *cpp = &p is safe because then *cpp = &c is prevented, but this is a sufficiently obscure case that it's not covered in the standard.
Conclusion: you can and should cast to const double *const * yourself.
Note that it would be more efficient to use a single array of type double * with length n * n and do any necessary array indexing yourself: d[i][j] becomes d[i * n + j].
A C++ compiler would allow that.
As for C, qualified pointer types are not applied recursively.
If your matrix data truly is 2D and rectangular (without a "ragged right edge"), I don't see why you're not representing it as a single double * to the first element, together with integers giving width and height. This would allow you to both cut down on the number of allocations needed to initialize the matrix, but also make it representable as a plain old const double *.

Resources