Passing variable sized multi-dimensional array by pointer in C - c

I am trying to pass a 2D array of variable size to a function to print it. I know how it's done when one has fixed sized arrays. But how does one do this with variable sized arrays? Here is some code that'll give you an idea what I am trying to do:
void print_grid(char (*g)[9], int size) // the array subscript (9 here) be variable
{
int i, j;
for (i=0; i<size; i++)
{
for (j=0; j<size; j++)
printf("%c ", g[i][j]);
printf("\n");
}
}
I'll call this function using the following code:
char a[3][3], b[9][9];
// assign a, b
print_grid(a, 3);
print_grid(b, 9);
Is there any way to do this without allocating any dynamic memory in print_grid()?

void print_grid(int rows, int cols, char g[][cols]) { ... }

void print_grid(char *g, int size)
{
int i, j;
for( i = 0; i < size; i++)
for( j = 0; j < size; j++)
{
printf("%c ", *(g + i*size + j));
printf("\n");
}
}
print_grid(a, 3);

When you pass an array in C it is always passed by reference, i.e. through a pointer. The type of this pointer is not pointer-to-array, but pointer-to-first-element. For example, the code generator will handle void f(char[][10]) as if it where void f(char*). The array dimensions are lost. The parser, however, will complain if it sees f declared twice so.
The motivation behind C was to have a powerful and portable assembler, not a new programming language. Multidimensional arrays are logical constructs that do not exist in the machine. Arrays are a way of thinking.
To pass the dimensions of arrays to functions C programmers traditionally use structs:
typedef struct array_tag {
int count;
char data[1]; /* actually data[count] */
} ARRAY;
typedef struct grid_tag {
int rows, columns;
char grid[1][1]; /* actually grid[rows][columns] */
} GRID;
void f(ARRAY* x)
{
int i;
for (i = 0; i < x->count; ++i) {
char c = x->data[i];
}
}
void g(GRID* x)
{
int i, j;
for (i = 0; i < x->rows; ++i)
for (j = 0; j < x->columns; ++j) {
char c = x->grid[i][j];
}
}
void h()
{
{
const int len = 100;
ARRAY* x = (ARRAY*) malloc(sizeof(ARRAY) + len * sizeof(char));
x->count = len;
f(x);
}
{
const int rows = 2, cols = 3;
GRID* x = (GRID*) malloc(sizeof(GRID) + rows * cols * sizeof(char));
x->rows = rows;
x->columns = cols;
g(x);
}
}
Yes, the malloc expression in this example allocates few bytes too much. Therefore the GNU-compiler supports arrays of zero length for a long time, which are not allowed in C90.
C99 has gone one step further with flexible arrays. From ISO/IEC 9899:1999, Section 6.7.2.1, paragraph 16: "As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member." In C99 the ARRAY and GRID types can be declared as:
typedef struct array_tag {
int count;
char data[]; /* actually data[count] */
} ARRAY;
typedef struct grid_tag {
int rows, columns;
char grid[][1]; /* actually grid[rows][columns] */
} GRID;
and you can
assert(1*sizeof(int) == sizeof(ARRAY));
assert(2*sizeof(int) == sizeof(GRID));
Many people think C arrays are quirky. But they're also an elegant solution which allows the declaration of indefinitely complex arrays. It is known as the "K&R array equation". A good explanation can be found here.
Hope this helps.

This one does it, assuming a squared grid:
void print_grid(void* g, int size)
{
char* my = (char*) g;
int i, j;
for (i=0; i<size; i++)
{
for (j=0; j<size; j++)
printf("%c ", my[i+j]);
printf("\n");
}
}
If you want to use non-squared grids, replace size with a rows and columns parameter and adjust counting: i<rows and j<columns.

Related

C - Having trouble with passing NxN array as an argument. I keep getting warning: incompatible pointer type [duplicate]

This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 13 days ago.
I wrote this program that is supposed to sort NxN array. It gets compiled but doesn't work because the pointer type is incompatible.
I just need help with the pointers as argument. I get incompatible pointer type warning for both functions swap and dblArraySort. Any idea why is that ?
thanks in advance !
#include <stdio.h>
#include <stdlib.h>
void
swap(int **a, int **b)
{
int temp;
temp = **a;
**a = **b;
**b = temp;
}
void
dblArraySort(int **dblArray, int arrLen)
{
int chkIndex;
int i, j, k;
for (i = 0; i < arrLen; i++) {
if ((i + 1) % 2 == 0) {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex < dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
} else {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex >= dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
}
}
}
int
main()
{
unsigned int arrayLength;
printf("Provide array size: \n");
scanf("%d", &arrayLength);
int doubleArray[arrayLength][arrayLength];
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
scanf("%d", &doubleArray[i][j]);
}
}
dblArraySort(doubleArray, arrayLength);
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
printf("%d ", doubleArray[i][j]);
}
printf("\n");
}
return 0;
}
I tried the code mentioned above
Arrays in C can be confusing. The thing you need to worry about is element type.
The element type of int ** dblArray is int *. In other words, dblArray is an array of int *s.
However, the element type of int doubleArray[arrayLength][arrayLength] is int row_type[arrayLength]. That is not an int *, that is an array, which is a totally different thing.
Moreover, when you use an array⟶pointer conversion, as happens when you say:
dblArraySort(doubleArray, arrayLength); // doubleArray is converted to a pointer
You get a pointer to the array, which in this case is a pointer to the innermost element type, an int — which is also not an int *.
tl;dr: You are trying to pass an array of array of int to a function taking an array of pointer to int. That won’t work.
I would like to comment on your variable naming as well. When you say “double” or “dbl”, as in doubleArray and dblArray the very first thing people will think is that you are handling a linear array of type double, which is also not what the array is.
You have there a two-dimensional array. Not a “double” array. Common naming for such thing would be array2D or matrix.
To make it work you need either C11, which allows you to pass a VLA as:
void sort_array2D( size_t rows, size_t columns, int array[rows][columns] )
{
...
int value = array[i][j];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( Array_Length, Array_Length, array2D );
Or you need to simply assume you must compute the index manually. A little function will help:
size_t index2D( size_t rows, size_t columns, size_t r, size_t c )
{
(void)rows; // (quiet the compiler about not using this argument)
return r * columns + c;
}
Then you can write your function as:
void sort_array2D( int * array, size_t rows, size_t columns )
{
...
int value = array[index2D( rows, columns, i, j )];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( (int *)array2D, Array_Length, Array_Length );
I haven’t bothered to analyze your sort function. It doesn’t look right to me, but honestly, I’ve barely glanced at it. Calling a value from the array chkIndex looks fishy, since the values of the array are not indices per se, at least not in the context of sorting them.
Remember, when messing with arrays in C you need to keep strict care to not mix up the type of the elements. (Or the types of things in general, whether syntactic or conceptual.)

Remove members from an array of char *

I've written this function to remove count members from arr at index idx.
void remove_int(int (*arr)[], int idx, int count)
{
int i, j;
for (i = 0; i < count; i++)
for (j = idx; (*arr)[j]; j++)
(*arr)[j] = (*arr)[j+1];
}
I call it like this:
remove_int(&arr, index, cnt);
This works perfectly for local integers. Here's my problem. I have a header file like this:
struct {
/* other stuff */
char *array[100];
} global_struct;
Members in array are allocated and filled.
Someone figured I could just switch int to char and int (*arr)[] to char *(*arr)[], then call:
remove_char(&global_struct.array, index, cnt);
I tried it, but it doesn't actually modify global_struct.array. How should I change remove_int to work with global_struct.array?
global_struct.array is a pointer to char, and looks like it is intended to point to a string. So you need to change the function signature to something like:
void remove_strings(char *str[], size_t idx, size_t count);
I would suggest changing idx, count, i, and j to type size_t, as this is an unsigned integer type guaranteed to hold any array index. The size_t type has been available since C99.
Here is a demonstration program that incorporates a modified version of the remove_int() function:
#include <stdio.h>
struct {
char *array[100];
} global_struct;
void remove_strings(char *str[], size_t idx, size_t count);
int main(void)
{
global_struct.array[0] = "One";
global_struct.array[1] = "Two";
global_struct.array[2] = "Three";
global_struct.array[3] = "Four";
global_struct.array[4] = "Five";
global_struct.array[5] = NULL;
for (size_t i = 0; global_struct.array[i]; i++) {
printf("%s\n", global_struct.array[i]);
}
remove_strings(global_struct.array, 2, 2);
putchar('\n');
puts("After removal:");
for (size_t i = 0; global_struct.array[i]; i++) {
printf("%s\n", global_struct.array[i]);
}
return 0;
}
void remove_strings(char *str[], size_t idx, size_t count)
{
size_t i, j;
for (i = 0; i < count; i++)
for (j = idx; str[j]; j++)
str[j] = str[j+1];
}
Program output:
One
Two
Three
Four
Five
After removal:
One
Two
Five
Also, it appears that your function remove_int() only works on arrays of int that exclude 0 members, as 0 is used as a sentinel value in the inner loop of your function. It is common to terminate an array of pointers to char with a NULL pointer, as I have done, and of course a string is an array of chars terminated with a '\0'. But, it is not in general a good idea to terminate an array of ints with a zero. This feature of your code did make it a simple matter to adapt it to work with strings.
While your function may satisfy your current requirements, consider changing it to return the number of ints stored in the array. It makes sense to keep track of the number of ints stored in the array, and passing this value as an argument allows the function to iterate over the array without a sentinel value. Here is a revised version of your function:
size_t remove_ints(size_t idx, size_t count, int arr[], size_t arr_sz)
{
size_t i, j;
for (i = 0; i < count; i++)
for (j = idx; j < arr_sz; j++)
arr[j] = arr[j+1];
return arr_sz - count;
}
The purpose of "for (i = 0; i < count; i++)"?
As my understand I think you should:
void remove_int(int (*arr)[], int idx)
{
int j;
for (j = idx; (*arr)[j]; j++)
(*arr)[j] = (*arr)[j+1];
}

Scanf Segfaults Outside of main()

I'm trying to generate a matrix of some arbitrary dimensions. I can do it just fine by calling scanf in main and then assigning matrix elements on a row by row basis, but trying to do it in a single function, outside of main, (and only if scanf() is called outside of main) gives me a segfault error:
int **genmat(int nrow, int ncol){
int i,j;
int **mat = (int**) malloc(sizeof(int)*ncol*nrow);
char rowbuff[16];
for(i=0; i < nrow; i++){
INPUT: scanf("%[^\n]%*c",rowbuff);
if(strlen(rowbuff) != ncol){
printf("Error: Input must be string of length %d\n", ncol);
goto INPUT;
}
else{
for(j=0; j < ncol; j++){
if(rowbuff[j] == '1'){
mat[i][j] = 1;
}
else{
mat[i][j] = 0;
}
}
}
}
return(mat);
}
The following works just fine:
int *genrow(int ncol, char *rowbuff){
int i;
int *row = malloc(sizeof(int)*ncol);
for(i=0;i<ncol;i++){
row[i] = rowbuff[i]%2;
}
return(row);
}
with the following in my main function to call genrow() for each row of the matrix:
for(i=0; i < row; i++){
INPUT: scanf("%[^\n]%*c",rowbuff);
if(strlen(rowbuff) != col){
printf("Error: Input must be string of length %d\n", col);
goto INPUT;
}
else{
int *newrow = genrow(col, rowbuff);
for(j=0; j < col; j++){
matrix[i][j] = newrow[j];
}
free(newrow);
newrow = NULL;
}
}
Why is the behavior different in these two contexts?
Dynamically allocated 2D arrays are unfortunately burdensome and ugly in C. To properly allocate one, it is very important that you do so with a single call to malloc, just as you tried to do. Otherwise it won't be a 2D array, but instead some segmented, slow look-up table.
However, the result of that malloc call will be a pointer to a 2D array, not a pointer-to-pointer. In fact, pointer-pointers have nothing to do with 2D arrays whatsoever - this is a widespread but incorrect belief.
What you should have done is this:
int (*mat)[nrow][ncol] = malloc( sizeof(int[nrow][ncol] );
This is an array pointer to a 2D array. This syntax is already a bit burdensome, but to make things worse, it is not easy to pass this array pointer back to main, because it is a local pointer variable. So you would need to use a pointer to an array pointer... and there's no pretty way to do that. It goes like this:
void genmat (size_t nrow, size_t ncol, int (**mat)[nrow][ncol] )
{
*mat = malloc( sizeof(int[nrow][ncol]) );
To ease usage a bit, you can create a temporary pointer to rows, which doesn't require multiple levels of indirection and is therefore much easier to work with:
int (*matrix)[ncol] = *mat[0]; // in the pointed-at 2D array, point at first row
for(size_t r=0; r<nrow; r++) // whatever you want to do with this matrix:
{
for(size_t c=0; c<ncol; c++)
{
matrix[r][c] = 1; // much more convenient syntax than (**mat)[r][c]
}
}
From main, you'll have to call the code like this:
size_t row = 3;
size_t col = 4;
int (*mat)[row][col];
genmat(row, col, &mat);
Example:
#include <stdio.h>
#include <stdlib.h>
void genmat (size_t nrow, size_t ncol, int (**mat)[nrow][ncol] )
{
*mat = malloc( sizeof(int[nrow][ncol]) );
int (*matrix)[ncol] = *mat[0];
for(size_t r=0; r<nrow; r++)
{
for(size_t c=0; c<ncol; c++)
{
matrix[r][c] = 1;
}
}
}
void printmat (size_t nrow, size_t ncol, int mat[nrow][ncol])
{
for(size_t r=0; r<nrow; r++)
{
for(size_t c=0; c<ncol; c++)
{
printf("%d ", mat[r][c]);
}
printf("\n");
}
}
int main (void)
{
size_t row = 3;
size_t col = 4;
int (*mat)[row][col];
genmat(row, col, &mat);
printmat(row, col, *mat);
free(mat);
return 0;
}
Please note that real code needs to address the case where malloc returns NULL.
I assume the problems is withint **mat = (int**) malloc(sizeof(int)*ncol*nrow);
You are trying to allocate the a 2D array right? But this isn't the correct method to allocate the memory. You can't allocate the whole chunk of memory one short.
What you should be doing here is, allocate the memory for all the rows(basically pointer to store the column address) and then for columns
int **mat= (int **)malloc(nrow * sizeof(int *));
for (i=0; i<nrow; i++)
mat[i] = (int *)malloc(ncol * sizeof(int));
Refer this link for more info http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/

Pass static two dimensional struct array to function by reference

I try to pass a static two dimensional struct as a reference to a function.
But I don't know how to get that done in correct way.
From my understanding, I pass a pointer to the first element of struct test to initfield(). C does know the size of the struct test so I can jump to the specific requested locations of the data. I just don't know how to adress the required data.
Here's my code that hopefully describes what I am looking for.
struct test{
int i;
double d;
};
void initfield(struct test *a, int structsize)
{
int i, j;
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
a[i][j]->i = 1;
a[i][j]->d = 1.0;
}
}
}
int main(void)
{
int i, j;
struct test field[8][8];
initfield(field, 8);
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i", i, j, test.i);
printf("test[%i][%i].d = %i", i, j, test.d);
}
}
return 0;
}
Update :
I've replaced both printf's with the following :
printf("test[%i][%i].i = %i", i, j, field[i][j].i);
printf("test[%i][%i].d = %lf", i, j, field[i][j].d);
However, I still encounter errors with initfield.
The problem, is actually, in your initfield() code,
void initfield(struct test *a, int structsize)
a is of type struct test *, and later, you're doing
a[i][j]->i = 1;
which expects a to be struct test **
That said,
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i", i, j, test.i);
printf("test[%i][%i].d = %i", i, j, test.d);
}
is completely wrong. Neither is there any variable called test, nor you can access a 2-D array using structVar.membervar format. Moreover, you are using %d to print a double, which in turn invokes undefined behaviour.
Solution: You can make use of array properties and pointer arithmetic to achieve what you want.
You have to change the loop inside the initfield() code, like
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
((a+(i*structsize))+j)->i = 7; //I changed the value to store, just like that
((a+(i*structsize))+j)->d = 2.0; //I changed the value to store, just like that
}
}
and, in main(), use %f to print the values.
A Live variant
First, structsize is not a good identifier name. It's not the size of the struct, it's the size of one dimension of the array. I'd implement it with parameters x and y, or width and heigth, or any better names for the two dimensions.
field is also a bad name. A field is often used to call a member of a struct. It is very confusing to use the identifier field to call an array of array of structs.
Then to your problem: field is an array of array of structs. In function parameter, this is equivalent to a pointer to a pointer.
The first parameter of initfield should be of type struct test **. Then later in the function, you dereference twice with your [] operators:
a is of type struct test **
a[i] is of type struct test *
a[i][j] is of type struct test
To access the fields of a[i][j], you need the . operator since its a struct test: a[i][j].d. The operator -> would work if a[i][j] was of type struct test *, but it isn't.
In this case it doesn't matter: as other have said, you can't access the second dimension of the array without explicitly calculating with the help of the size of the first dimension. a[i][j] does not work, you need some kind of pointer arithmetic: struct test *p = a + i * structsize + j and use p->i and p->d.
In the main function however, the dimensions of field are know, so field[i][j].d works.
You're assuming C can figure out that a inside refers to a square array with side length structsize, although you clearly say that a has type "pointer to struct test", which is not the same.
You need to do the indexing manually, inside the function:
static void initfield(struct test *a00, size_t sidelength)
{
for(size_t i = 0; i < sidelength; ++i)
{
for(size_t j = 0; j < sidelength; ++j)
{
struct test *aij = a00 + i * sidelength + j;
aij->i = 1;
aij->j = 1.0;
}
}
}
I didn't test the above, but something like that should work. It basically just uses simple pointer arithmetic to compute the address of the 2D array element at (i, j) given the address of the one at (0, 0).
It works fine i din't thought about doing calculation the adresses myself.
Thanks very much!
Here's my final adapted code which just works perfectly!
struct test{
int i;
double d;
};
void initfield(struct test *a00, int structsize)
{
int i, j;
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
struct test *acurrent = a00 + i * structsize + j;
acurrent->i = 1;
acurrent->d = 1.0;
}
}
}
int main(void)
{
int i, j;
struct test field[8][8];
initfield(&field[0][0], 8);
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i\n", i, j, field[i][j].i);
printf("test[%i][%i].d = %lf\n", i, j, field[i][j].d);
}
}
return 0;
}
Best way to do this:
void initfield(size_t x, size_t y, struct test a[x][y]);
Be aware though, C is strange, the above is still a pointer, equivalent to struct test*. If you wish to have a true array pointer type, you'd have to do:
void initfield(size_t x, size_t y, struct test a[x][y])
{
struct test (*ptr)[x][y] = (void*)a;
or preferably:
struct test (*ptr)[y] = *a;
ptr[i][j] = something; // use the array pointer with sane syntax

create a pointer to a 2D array

I have a
bool array[size][size]
and want to pass a pointer of it to a function to change its value.
void change_to_true(???, int i, int j) { // don't know what type it should be
array[i][j] = 1;
}
How do I create a pointer of the array, and how should I pass the pointer to the function so
that I can change its value? BTW it's c code.
Thanks
Edit:
I tried
static bool array[size][size];
bool (*array_t)[index] = array;
void change_to_true(bool array, int i, int j);
Compiler told me subscripted value is neither array nor pointer
I tried to change the type definition of the function parameter from bool array to bool* array, still not work.
I also tried bool (*array_t)[][size] = &array and bool (*array_t)[size][size] = &array; for the pointer, still not work.
Also since the size of the array is decided during the runtime, I can't have a enum or a global array defined that way.
This should work:
void change_to_true(bool** array, int i, int j)
Simple solution — but no pointer to 2D array
The function should be simply:
#include <stdbool.h>
enum { size = 24 };
extern void change_to_true(bool array[][size], int i, int j);
void change_to_true(bool array[][size], int i, int j)
{
array[i][j] = true;
}
int main(void)
{
bool array[size][size];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
array[i][j] = false;
change_to_true(array, i, j);
}
}
}
I'm assuming, of course, that you have a C99 or C2011 compiler. If you're stuck with C89, then you'll have to provide definitions for bool and true; the rest does not need to change. I'm not convinced the function call is worth it, compared with the assignment of false.
Solution using pointer to 2D array
Note that the code above does not, strictly, create a pointer to a 2D array. If you are really, really sure that's what you want, then the notation changes:
#include <stdbool.h>
enum { size = 24 };
extern void change_to_true(bool (*array)[][size], int i, int j);
void change_to_true(bool (*array)[][size], int i, int j)
{
(*array)[i][j] = true;
}
int main(void)
{
bool array[size][size];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
array[i][j] = false;
change_to_true(&array, i, j);
}
}
}
There's no benefit to using a formal 'pointer to array' that I can think of, though — not in this context.
Solution using C99 variable length arrays
In C99, you can also use a VLA — variable length array — like this:
#include <stdbool.h>
extern void change_to_true(int size, bool array[][size], int i, int j);
void change_to_true(int size, bool array[][size], int i, int j)
{
array[i][j] = true;
}
int main(void)
{
for (int size = 2; size < 10; size++)
{
bool array[size][size];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
array[i][j] = false;
change_to_true(size, array, i, j);
}
}
}
}
Note that the size must precede the array declaration in the function declaration. And yes, you also write this with pointer to array notation (actually, I edited the pointer to array notation code first, then realized that I wanted the simpler version).
Which to use?
Unless you have compelling reasons not mentioned in the question, the first version is the code to use.
This should answer you question.
In short, you make a pointer to the first element and then pass it around.
[EDIT] C supports bool since C 99
Besides that, by declaring it that way, the actual array is a pointer to a memory zone with all the size^2 instances. This means that you can pass array to change it in the function, and in your header declare that you are receiving bool array[][].
That way it should work.

Resources