Position of an element in a multidimensional array [ C ] - c

I have to write a function that receives an integer X (the value of the linearized position) and an array that contains the dimensions of a multidimensional array and it has to save in a second array the coordinates of the element with position X in the multidimensional reference system. For example:
X=2 and array[]={A,B} where the array contains the dimensions(A,B) of a 2D matrix in this example. So the position in 2D reference system is:
Knowing: X=x*B+y ----> x=X/B and y=X%B ----> position[]={x,y};
So it was simple to decipher X into x and y because it was the banal case of a 2D matrix but my program has to deal with N-dimensional matrix (So it has to decipher X into position x,y,......,n) .
My idea is to apply the algorithm that I've showed but even I can't find a C code that can deal with a generic N-dimensional matrix (I also tried to write a recursive function without success).
Can someone find a solution to this problem? (Thank you in advance!!!)
I'm a beginner!!!

if you have an array DIM2[X,Y] with dimenstions Xn and Yn, you could represent this (as you said) as a one dimenstional array too.
A[x,y] would then be mapped to DIM1[x + y * Xn]
DIM1 must have size (Xn * Yn)
3 dimension array B[] with dimensions Xn,Yn,Zn could be mapped the same way:
B[x,y,z] would map to DIM1 [ x + y * Xn + z * Xn * Yn], DIM1 must be able to hold (Xn * Yn * Zn) items,
B[x,y,z,a] would map to DIM1 [ x + y * Xn + z * Xn * Yn + a * Xn * Yn *
Zn]
and so on
for a generic N dimensional array, a recursion would be best, where an array with 100 dimensions is array of 99-dimensional arrays. If all dimenstions have the same size, that would be relative simple (writing it, i also mentioned that the recursion can be easily unrolled into a simple for-loop, find it below)
#include <stdio.h>
#include <math.h>
#include <malloc.h>
#define max_depth 5 /* 5 dimensions */
#define size 10 /* array[10] of array */
// recursive part, do not use this one
int _getValue( int *base, int offset, int current, int *coords) {
if (--current)
return _getValue (base + *coords*offset, offset/size, current, coords+1);
return base[*coords];
}
// recursive part, do not use this one
void _setValue( int *base, int offset, int current, int *coords, int newVal) {
if (--current)
_setValue (base + *coords*offset, offset/size, current, coords+1, newVal);
base[*coords]=newVal;
}
// getValue: read item
int getValue( int *base, int *coords) {
int offset=pow( size, max_depth-1); /* amount of ints to skip for first dimension */
return (_getValue (base, offset, max_depth, coords));
}
// setValue: set an item
void setValue( int *base, int *coords, int newVal) {
int offset=pow( size, max_depth-1);
_setValue (base, offset, max_depth, coords, newVal);
}
int main() {
int items_needed = pow( size, max_depth);
printf ("allocating room for %i items\n", items_needed);
int *dataholder = (int *) malloc(items_needed*sizeof(int));
if (!dataholder) {
fprintf (stderr,"out of memory\n");
return 1;
}
int coords1[5] = { 3,1,2,1,1 }; // access member [3,1,2,1,1]
setValue(dataholder, coords1, 4711);
int coords2[5] = { 3,1,0,4,2 };
int x = getValue(dataholder, coords2);
int coords3[5] = { 9,7,5,3,9 };
/* or: access without recursion: */
int i, posX = 0; // position of the wanted integer
int skip = pow( size, max_depth-1); // amount of integers to be skipped for "pick"ing array
for (i=0;i<max_depth; i++) {
posX += coords3[i] * skip; // use array according to current coordinate
skip /= size; // calculate next dimension's size
}
x = dataholder[posX];
return x;
}

Related

How to use a 2d array in other function?? don't know how to make it work

me and my friend are trying to pass a user-defined array to a function and do a "2d array" sort mechanism on that array which is defined outside the function.
we found a function online that sorts a predefined array within itself and tried to use that function.
our problem consist in trying to use the user-defined array in the function.
please check the code below (please note that we don't know how to use structs)
The question is: how do we use our orderListArray[][] in the sort array function?
#include <stdio.h>
#include <stdlib.h>
// define for sort array function later on
#define ARRAYSIZE(array) (sizeof(array)/sizeof(*(array)))
// function prototype
int sortArray();
int printOrderlist();
// data variables to be used throughout the code.
int itemNumber;
int itemAmount;
int maxItem = 0;
int lineCount = 0;
int priceToPrint = 0;
float totalPrice = 0;
// array we wish to implement into "sortArray" function
int orderListArray[][2];
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
int orderList()
{ // begin orderList
// makes sure user enters a maximum of 5 orders
int k = 0; // first place in array
int g = 0; // second place in array
do
{ // begin do1
printf("%d %d\n", k,g);
// asks for item number
puts("Enter item number (1-100):");
scanf("%d", &itemNumber);
// add scan to first spot (k) which is 0,0 (row 0, spot 0)
orderListArray[k][g] = itemNumber;
// add g++ to go to 0,1 ( row 0, spot 1)
g++;
// asks for amount
printf("%d %d\n", k, g);
printf("You can order %d more items\n", 5-itemAmount);
printf("Enter amount:\n");
scanf("%d", &itemAmount);
maxItem = maxItem + itemAmount;
// add itemAmount to g which is 0,1
orderListArray[k][g] = itemAmount;
k++; // go to row 1 instead of row 0
g--; // go back to spot 0 in row.
// lineCount is used when we print rows of array since that is not predefined
lineCount++;
} // end do1
// runs as long as the total amount of items inputed matches.
while (maxItem <= 4);
return 0;
} // end orderList
//////////////////////////////////////////////////////////////////////////////// //////////
//////////////////////////////////////////////////////////////////////////////// //////////
int main(void)
{
orderList();
sortArray();
return 0;
}
//////////////////////////////////////////////////////////////////////////////// //////////
//////////////////////////////////////////////////////////////////////////////// //////////
// is used in sortArray() to sort 2d array.
int compare(const void *a, const void *b) {
int x1 = *(const int*)a;
int x2 = *(const int*)b;
if (x1 > x2) return 1;
if (x1 < x2) return -1;
// x1 and x2 are equal; compare y's
int y1 = *(((const int*)a)+1);
int y2 = *(((const int*)b)+1);
if (y1 > y2) return 1;
if (y1 < y2) return -1;
return 0;
}
//////////////////////////////////////////////////////////////////////////////// //////////
//////////////////////////////////////////////////////////////////////////////// //////////
// sortArray function (here we want to implement the orderListArray[k][g]
// and run on that instead of predefined matrix which is included in the code
int sortArray(int b[], size_t size)
{ // begin sortArray
int matrix[][2] = {{8,6}, {4,2}, {1,0}, {4,8}, {2,4},
{4,3}, {1,2}, {2,2}, {8,3}, {5,5}};
printf("Original: ");
for (size_t i = 0; i < ARRAYSIZE(matrix); i++)
printf("(%d,%d) ", matrix[i][0], matrix[i][1]);
putchar('\n');
qsort(matrix, ARRAYSIZE(matrix), sizeof(*matrix), compare);
printf("Sorted : ");
for (size_t i = 0; i < ARRAYSIZE(matrix); i++)
printf("(%d,%d) ", matrix[i][0], matrix[i][1]);
putchar('\n');
return 0;
} // end sortArray
You have a bona fide 2D array. That's an array of arrays, so the elements are arrays, and therefore your compare function receives pointers to arrays as its arguments. Your comparison code is not actually wrong, but it would be a bit cleaner and clearer to acknowledge the correct types of the elements you are comparing:
int compare(const void *a, const void *b) {
const int (*x1)[2] = a;
const int (*x2)[2] = b;
if ((*x1)[0] > (*x2)[0]) return 1;
if ((*x1)[0] < (*x2)[0]) return -1;
if ((*x1)[1] > (*x2)[1]) return 1;
if ((*x1)[1] < (*x2)[1]) return -1;
return 0;
}
The main question seems to be represented by this code comment, however:
here we want to implement the orderListArray[k][g] and run on that instead of predefined matrix
It's not an especial problem for k to be an adjustable parameter, but it complicates matters greatly for g to be adjustable. To even declare your function requires either fudging types, or using a variable-length array. Either way, your function signature does not provide enough information. You must either know or assume both dimensions of your array, and you have only one parameter, size, to convey that information.
If you are assuming that the array to be sorted will be an array of pairs, as is matrix in your sample code, then simply write the function signature like so:
int sortArray(int b[][2], size_t size) // ...
and rely on the caller to provide the number of elements (pairs) via the size parameter. Then you could call qsort like so:
qsort(b, size, sizeof(*b), compare);
It's a lot messier if the matrix rows are variable length, because then you have to either dynamically choose a comparison function that is specific to the correct length, or generalize your comparison function and convey the row length to it by some means other than its arguments (thus, probably via a file-scope variable). Both of those approaches have significant drawbacks.
A third approach would be to rely on the caller of sortArray() to provide a suitable comparison function, but if you do that then you have to consider what value sortArray() is actually providing relative to calling qsort() directly.

Gaussian Blur, Mean Filter, Convolution

I want to implement a convolution function to use in mean filter and gaussian filter and I need to implement those 2 filters as well to apply to pgm files.
I have
typedef struct _PGM{
int row;
int col;
int max_value;
int **matrix;
}PGM;
struct and
int convolution(int ** kernel,int ksize, PGM * image, PGM * output){
int i, j, x, y;
int sum;
int data;
int scale =ksize*ksize;
int coeff;
for (x=ksize/2; x<image->row-ksize/2;++x) {
for (y=ksize/2; y<image->col-ksize/2; ++y){
sum = 0;
for (i=-ksize/2; i<=ksize/2; ++i){
for (j=-ksize/2; j<=ksize/2; ++j){
data = image->matrix[x +i][y +j];
coeff = kernel[i+ksize/2][j+ksize/2];
sum += data * coeff;
}
}
output->matrix[x][y] = sum / scale;
}
}
return sum/scale;
}
convolution function but I get error(actually it terminates) in convolution function so I could not proceed to filter
Can you help me with the implementation ?
Thank you.
In your convolution there are two things wrong that probably aren't causing the crash. The first is style: You're using x to iterate over the rows of an image, something I picture more as a y displacement, and vice-versa. The second is that when you're computing the sum, you're not resetting the variable sum = 0 prior to evaluating the kernel (the inner two loops) for each pixel. Instead you accumulate sum over all pixels, probably eventually causing integer overflow. While strictly speaking this is UB and could cause a crash, it's not the issue you're facing.
If you would kindly confirm that the crash occurs on the first pixel (x = ksize/2, y = ksize/2), then since the crash occurs at the first coefficient read from the kernel, I suspect you may have passed the "wrong thing" as the kernel. As presented, the kernel is an int**. For a kernel size of 3x3, this means that to call this function correctly, you must have allocated on the heap or stack an array of int*, where you stored 3 pointers to int arrays with 3 coefficients each. If you instead passed a int[3][3] array, the convolution function will attempt to interpret the first one or two int in the array as a pointer to an int when it is not, and try to dereference it to pull in the coefficient. This will most likely cause a segfault.
I also don't know why you are returning the accumulated sum. This isn't a "traditional" output of convolution, but I surmise you were interested in the average brightness of the output image, which is legitimate; In this case you should use a separate and wider integer accumulator (long or long long) and, at the end, divide it by the number of pixels in the output.
You probably found the PGM data structure from the internet, say, here. Allow me to part with this best-practice advice. In my field (computer vision), the computer vision library of choice, OpenCV, does not express a matrix as an array of row pointers to buffers of col elements. Instead, a large slab of memory is allocated, in this case of size image->row * image->col * sizeof(int) at a minimum, but often image->row * image->step * sizeof(int) where image->step is image->col rounded up to the next multiple of 4 or 16. Then, only a single pointer is kept, a pointer to the base of the entire image, although an extra field (the step) has to be kept if images aren't continuous.
I would therefore rework your code thus:
/* Includes */
#include <stdlib.h>
/* Defines */
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
/* Structure */
/**
* Mat structure.
*
* Stores the number of rows and columns in the matrix, the step size
* (number of elements to jump from one row to the next; must be larger than or
* equal to the number of columns), and a pointer to the first element.
*/
typedef struct Mat{
int rows;
int cols;
int step;
int* data;
} Mat;
/* Functions */
/**
* Allocation. Allocates a matrix big enough to hold rows * cols elements.
*
* If a custom step size is wanted, it can be given. Otherwise, an invalid one
* can be given (such as 0 or -1), and the step size will be chosen
* automatically.
*
* If a pointer to existing data is provided, don't bother allocating fresh
* memory. However, in that case, rows, cols and step must all be provided and
* must be correct.
*
* #param [in] rows The number of rows of the new Mat.
* #param [in] cols The number of columns of the new Mat.
* #param [in] step The step size of the new Mat. For newly-allocated
* images (existingData == NULL), can be <= 0, in
* which case a default step size is chosen; For
* pre-existing data (existingData != NULL), must be
* provided.
* #param [in] existingData A pointer to existing data. If NULL, a fresh buffer
* is allocated; Otherwise the given data is used as
* the base pointer.
* #return An allocated Mat structure.
*/
Mat allocMat(int rows, int cols, int step, int* existingData){
Mat M;
M.rows = max(rows, 0);
M.cols = max(cols, 0);
M.step = max(step, M.cols);
if(rows <= 0 || cols <= 0){
M.data = 0;
}else if(existingData == 0){
M.data = malloc(M.rows * M.step * sizeof(*M.data));
}else{
M.data = existingData;
}
return M;
}
/**
* Convolution. Convolves input by the given kernel (centered) and stores
* to output. Does not handle boundaries (i.e., in locations near the border,
* leaves output unchanged).
*
* #param [in] input The input image.
* #param [in] kern The kernel. Both width and height must be odd.
* #param [out] output The output image.
* #return Average brightness of output.
*
* Note: None of the image buffers may overlap with each other.
*/
int convolution(const Mat* input, const Mat* kern, Mat* output){
int i, j, x, y;
int coeff, data;
int sum;
int avg;
long long acc = 0;
/* Short forms of the image dimensions */
const int iw = input ->cols, ih = input ->rows, is = input ->step;
const int kw = kern ->cols, kh = kern ->rows, ks = kern ->step;
const int ow = output->cols, oh = output->rows, os = output->step;
/* Kernel half-sizes and number of elements */
const int kw2 = kw/2, kh2 = kh/2;
const int kelem = kw*kh;
/* Left, right, top and bottom limits */
const int l = kw2,
r = max(min(iw-kw2, ow-kw2), l),
t = kh2,
b = max(min(ih-kh2, oh-kh2), t);
/* Total number of pixels */
const int totalPixels = (r-l)*(b-t);
/* Input, kernel and output base pointers */
const int* iPtr = input ->data;
const int* kPtr = kern ->data + kw2 + ks*kh2;
int* oPtr = output->data;
/* Iterate over pixels of image */
for(y=t; y<b; y++){
for(x=l; x<r; x++){
sum = 0;
/* Iterate over elements of kernel */
for(i=-kh2; i<=kh2; i++){
for(j=-kw2; j<=kw2; j++){
data = iPtr[j + is*i + x];
coeff = kPtr[j + ks*i ];
sum += data * coeff;
}
}
/* Compute average. Add to accumulator and store as output. */
avg = sum / kelem;
acc += avg;
oPtr[x] = avg;
}
/* Bump pointers by one row step. */
iPtr += is;
oPtr += os;
}
/* Compute average brightness over entire output */
if(totalPixels == 0){
avg = 0;
}else{
avg = acc/totalPixels;
}
/* Return average brightness */
return avg;
}
/**
* Main
*/
int main(int argc, char* argv[]){
/**
* Coefficients of K. Binomial 3x3, separable. Unnormalized (weight = 16).
* Step = 3.
*/
int Kcoeff[3][3] = {{1, 2, 1}, {2, 4, 2}, {1, 2, 1}};
Mat I = allocMat(1920, 1080, 0, 0);/* FullHD 1080p: 1920x1080 */
Mat O = allocMat(1920, 1080, 0, 0);/* FullHD 1080p: 1920x1080 */
Mat K = allocMat( 3, 3, 3, &Kcoeff[0][0]);
/* Fill Mat I with something.... */
/* Convolve with K... */
int avg = convolution(&I, &K, &O);
/* Do something with O... */
/* Return */
return 0;
}
Reference: Years of experience in computer vision.

2d array in C with negative indices

I am writing a C-program where I need 2D-arrays (dynamically allocated) with negative indices or where the index does not start at zero. So for an array[i][j] the row-index i should take values from e.g. 1 to 3 and the column-index j should take values from e.g. -1 to 9.
For this purpose I created the following program, here the variable columns_start is set to zero, so just the row-index is shifted and this works really fine.
But when I assign other values than zero to the variable columns_start, I get the message (from valgrind) that the command "free(array[i]);" is invalid.
So my questions are:
Why it is invalid to free the memory that I allocated just before?
How do I have to modify my program to shift the column-index?
Thank you for your help.
#include <stdio.h>
#include <stdlib.h>
main()
{
int **array, **array2;
int rows_end, rows_start, columns_end, columns_start, i, j;
rows_start = 1;
rows_end = 3;
columns_start = 0;
columns_end = 9;
array = malloc((rows_end-rows_start+1) * sizeof(int *));
for(i = 0; i <= (rows_end-rows_start); i++) {
array[i] = malloc((columns_end-columns_start+1) * sizeof(int));
}
array2 = array-rows_start; //shifting row-index
for(i = rows_start; i <= rows_end; i++) {
array2[i] = array[i-rows_start]-columns_start; //shifting column-index
}
for(i = rows_start; i <= rows_end; i++) {
for(j = columns_start; j <= columns_end; j++) {
array2[i][j] = i+j; //writing stuff into array
printf("%i %i %d\n",i, j, array2[i][j]);
}
}
for(i = 0; i <= (rows_end-rows_start); i++) {
free(array[i]);
}
free(array);
}
When you shift column indexes, you assign new values to original array of columns: in
array2[i] = array[i-rows_start]-columns_start;
array2[i] and array[i=rows_start] are the same memory cell as array2 is initialized with array-rows_start.
So deallocation of memory requires reverse shift. Try the following:
free(array[i] + columns_start);
IMHO, such modification of array indexes gives no benefit, while complicating program logic and leading to errors. Try to modify indexes on the fly in single loop.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int a[] = { -1, 41, 42, 43 };
int *b;//you will always read the data via this pointer
b = &a[1];// 1 is becoming the "zero pivot"
printf("zero: %d\n", b[0]);
printf("-1: %d\n", b[-1]);
return EXIT_SUCCESS;
}
If you don't need just a contiguous block, then you may be better off with hash tables instead.
As far as I can see, your free and malloc looks good. But your shifting doesn't make sense. Why don't you just add an offset in your array instead of using array2:
int maxNegValue = 10;
int myNegValue = -6;
array[x][myNegValue+maxNegValue] = ...;
this way, you're always in the positive range.
For malloc: you acquire (maxNegValue + maxPosValue) * sizeof(...)
Ok I understand now, that you need free(array.. + offset); even using your shifting stuff.. that's probably not what you want. If you don't need a very fast implementation I'd suggest to use a struct containing the offset and an array. Then create a function having this struct and x/y as arguments to allow access to the array.
I don't know why valgrind would complain about that free statement, but there seems to be a lot of pointer juggling going on so it doesn't surprise me that you get this problem in the first place. For instance, one thing which caught my eye is:
array2 = array-rows_start;
This will make array2[0] dereference memory which you didn't allocate. I fear it's just a matter of time until you get the offset calcuations wrong and run into this problem.
One one comment you wrote
but im my program I need a lot of these arrays with all different beginning indices, so I hope to find a more elegant solution instead of defining two offsets for every array.
I think I'd hide all this in a matrix helper struct (+ functions) so that you don't have to clutter your code with all the offsets. Consider this in some matrix.h header:
struct matrix; /* opaque type */
/* Allocates a matrix with the given dimensions, sample invocation might be:
*
* struct matrix *m;
* matrix_alloc( &m, -2, 14, -9, 33 );
*/
void matrix_alloc( struct matrix **m, int minRow, int maxRow, int minCol, int maxCol );
/* Releases resources allocated by the given matrix, e.g.:
*
* struct matrix *m;
* ...
* matrix_free( m );
*/
void matrix_free( struct matrix *m );
/* Get/Set the value of some elment in the matrix; takes logicaly (potentially negative)
* coordinates and translates them to zero-based coordinates internally, e.g.:
*
* struct matrix *m;
* ...
* int val = matrix_get( m, 9, -7 );
*/
int matrix_get( struct matrix *m, int row, int col );
void matrix_set( struct matrix *m, int row, int col, int val );
And here's how an implementation might look like (this would be matrix.c):
struct matrix {
int minRow, maxRow, minCol, maxCol;
int **elem;
};
void matrix_alloc( struct matrix **m, int minCol, int maxCol, int minRow, int maxRow ) {
int numRows = maxRow - minRow;
int numCols = maxCol - minCol;
*m = malloc( sizeof( struct matrix ) );
*elem = malloc( numRows * sizeof( *elem ) );
for ( int i = 0; i < numRows; ++i )
*elem = malloc( numCols * sizeof( int ) );
/* setting other fields of the matrix omitted for brevity */
}
void matrix_free( struct matrix *m ) {
/* omitted for brevity */
}
int matrix_get( struct matrix *m, int col, int row ) {
return m->elem[row - m->minRow][col - m->minCol];
}
void matrix_set( struct matrix *m, int col, int row, int val ) {
m->elem[row - m->minRow][col - m->minCol] = val;
}
This way you only need to get this stuff right once, in a central place. The rest of your program doesn't have to deal with raw arrays but rather the struct matrix type.

Declaring a 2-dimensional array of unknown size, C

I have an array declared as a member of a struct in C. The array is declared as:
char mValue[MAXROWS][MAXCOLUMNS];
where MAXROWS and MAXROWS are 300. Is there a better way to do this? I mean, should I declare these as pointers instead?
Thanks!
As the previous poster suggested, a good way is to create a linear array and then "convert it to 2D". Many times, caching the 2D pointers greatly increases the speed of programs that use this array, like so:
mystruct *p = (mystruct*)calloc(ROWS * COLUMNS, sizeof(mystruct));
mystruct **p2 = (mystruct**)calloc(ROWS, sizeof(mystruct*));
for (int i = 0; i < ROWS; i++)
p2[i] = p + i*COLUMNS;
Then, you can simply access a 2D element with:
p2[row][column] = foo;
If all your rows are the same size, you should use a 1D array with the rows stored in sequence:
ABCDE
FGHIJ ---> ABCDEFGHIJKLMNO
KLMNO
The element at row i, column j will be at index i * ROW_LENGTH + j in the 1D array.
You can allocate the array using malloc(ROW_LENGTH * NUM_ROWS).
Another technique is to create a linear array and then convert it to 2d:
char *p = malloc(ROWS * COLUMNS);
// To access x, y
// This is in row-major ordr
*(p + (x * COLUMNS) + y);
I find that, for this kind of code, its better to create helper functions for accessing the elements. Depending on your profiling data, it may make sense to turn these into macros, but be extra careful.
#include <stdio.h> /* For printf */
/* This is the bit that would go in a header, like char2darray.h */
#include <stdlib.h> /* For calloc */
#include <assert.h> /* For assert */
struct Char2DArray
{
int rows;
int columns;
char *values;
};
/* This is the bit that would go in a source file, like char2darray.c */
void C2DA_initialize(struct Char2DArray *array, int rows, int columns)
{
assert(array != 0);
array->values = calloc(rows * columns, sizeof(char));
array->rows = rows;
array->columns = columns;
}
void C2DA_set(struct Char2DArray *array, int row, int column, int value)
{
assert(array != 0);
assert(array->values != 0);
assert(row < array->rows);
assert(row >= 0);
assert(column < array->columns);
assert(column >= 0);
array->values[(row * array->rows) + column] = value;
}
char C2DA_get(struct Char2DArray *array, int row, int column)
{
assert(array != 0);
assert(array->values != 0);
assert(row < array->rows);
assert(row >= 0);
assert(column < array->columns);
assert(column >= 0);
return array->values[(row * array->rows) + column];
}
void C2DA_free(struct Char2DArray *array)
{
free(array->values);
array->values = 0;
}
/* Here's a main.c to use it */
int main()
{
struct Char2DArray a;
C2DA_initialize(&a, 16, 16);
unsigned char c = 0;
int x, y;
for (x=0; x<16; x++) {
for (y=0; y<16; y++) {
C2DA_set(&a, x, y, (char)c);
c++;
}
}
printf("Character with hex value 0x55 is %c\n", C2DA_get(&a, 5, 5));
C2DA_free(&a);
return 0;
}
If the array needs to have a dynamic size, then you either need to make it a pointer or make the array the last member of the struct and play games when allocating the structure size.
Relevant comp.lang.c FAQ entries:
I came across some code that declared a structure like this...
How can I dynamically allocate a multidimensional array?
I found that changing my approach was very useful when faced with a similar problem.
A vector of vectors filled the same task, avoided memory allocation obstacles, and kept the same familiar shorthand. There may be other pitfalls, but I have not encountered them yet.
//Declaration of mValues, undefined size:
std::vector< std::vector<char> > mValues;
//Filling of mValues:
int max_x = 100 ;
int max_y = 100 ;
char char_foo = 'a';
for ( int x = 0; x <= max_x; ++x ) {
vector<char> temp;
for ( int y = 0; y <= max_y; ++y ) {
temp.push_back( char_foo );
}
mValues.push_back( temp );
}
// Referencing with familiar index notation:
mValues[a][b]; //The a-th row's b-th element
If you are struggling with arrays, but strongly desire the familiar indexing language, I have found this to be a good alternative.
Note that indexing order A then B is going to be critical for memory usage when recalling this data. Failure to call the information in an A,B order will be deeply problematic if performance is an issue.

Passing multidimensional arrays as function arguments in C

In C can I pass a multidimensional array to a function as a single argument when I don't know what the dimensions of the array are going to be?
Besides, my multidimensional array may contain types other than strings.
Pass an explicit pointer to the first element with the array dimensions as separate parameters. For example, to handle arbitrarily sized 2-d arrays of int:
void func_2d(int *p, size_t M, size_t N)
{
size_t i, j;
...
p[i*N+j] = ...;
}
which would be called as
...
int arr1[10][20];
int arr2[5][80];
...
func_2d(&arr1[0][0], 10, 20);
func_2d(&arr2[0][0], 5, 80);
Same principle applies for higher-dimension arrays:
func_3d(int *p, size_t X, size_t Y, size_t Z)
{
size_t i, j, k;
...
p[i*Y*Z+j*Z+k] = ...;
...
}
...
arr2[10][20][30];
...
func_3d(&arr[0][0][0], 10, 20, 30);
You can declare your function as:
f(int size, int data[][size]) {...}
The compiler will then do all pointer arithmetic for you.
Note that the dimensions sizes must appear before the array itself.
GNU C allows for argument declaration forwarding (in case you really need to pass dimensions after the array):
f(int size; int data[][size], int size) {...}
The first dimension, although you can pass as argument too, is useless for the C compiler (even for sizeof operator, when applied over array passed as argument will always treat is as a pointer to first element).
You can do this with any data type. Simply make it a pointer-to-pointer:
typedef struct {
int myint;
char* mystring;
} data;
data** array;
But don't forget you still have to malloc the variable, and it does get a bit complex:
//initialize
int x,y,w,h;
w = 10; //width of array
h = 20; //height of array
//malloc the 'y' dimension
array = malloc(sizeof(data*) * h);
//iterate over 'y' dimension
for(y=0;y<h;y++){
//malloc the 'x' dimension
array[y] = malloc(sizeof(data) * w);
//iterate over the 'x' dimension
for(x=0;x<w;x++){
//malloc the string in the data structure
array[y][x].mystring = malloc(50); //50 chars
//initialize
array[y][x].myint = 6;
strcpy(array[y][x].mystring, "w00t");
}
}
The code to deallocate the structure looks similar - don't forget to call free() on everything you malloced! (Also, in robust applications you should check the return of malloc().)
Now let's say you want to pass this to a function. You can still use the double pointer, because you probably want to do manipulations on the data structure, not the pointer to pointers of data structures:
int whatsMyInt(data** arrayPtr, int x, int y){
return arrayPtr[y][x].myint;
}
Call this function with:
printf("My int is %d.\n", whatsMyInt(array, 2, 4));
Output:
My int is 6.
In C can I pass a multidimensional array to a function as a single argument when I don't know what the dimensions of the array are going to be?
No
If by "single argument" you mean passing just the array without passing the array dimensions, no you can't. At least not for true multidimensional arrays.
You can put the dimension[s] into a structure along with the array and claim you're passing a "single argument", but that's really just packing multiple values into a single container and calling that container "one argument".
You can pass an array of known type and number of dimensions but unknown size by passing the dimensions themselves and the array like this:
void print2dIntArray( size_t x, size_t y, int array[ x ][ y ] )
{
for ( size_t ii = 0, ii < x; ii++ )
{
char *sep = "";
for ( size_t jj = 0; jj < y; jj++ )
{
printf( "%s%d", sep, array[ ii ][ jj ] );
sep = ", ";
}
printf( "\n" );
}
}
You would call that function like this:
int a[ 4 ][ 5 ];
int b[ 255 ][ 16 ];
...
print2dIntArray( 4, 5, a );
....
printt2dIntArray( 255, 16, b );
Similarly, a 3-dimensional array of, for example, a struct pixel:
void print3dPixelArray( size_t x, size_t y, size_t z, struct pixel pixelArray[ x ][ y ][ z ] )
{
...
}
or a 1-dimensional double array:
void print1dDoubleArray( size_t x, double doubleArray[ x ] )
{
...
}
BUT...
However, it can be possible to pass "arrays of pointers to arrays of pointers to ... an array of type X" constructs that are often mislabeled as a "multidimensional array" as a single argument as long as the base type X has an sentinel value that can be used to indicate the end of the final, lowest-level single-dimensional array of type X.
For example, the char **argv value passed to main() is a pointer to an array of pointers to char. The initial array of char * pointers ends with a NULL sentinel value, while each char array referenced by the array of char * pointers ends with a NUL character value of '\0'.
For example, if you can use NAN as a sentinel value because actual data won't ever be a NAN, you could print a double ** like this:
void printDoubles( double **notAnArray )
{
while ( *notAnArray )
{
char *sep = "";
for ( size_t ii = 0; ( *notAnArray )[ ii ] != NAN; ii++ )
{
printf( "%s%f", sep, ( *notAnArray )[ ii ] );
sep = ", ";
}
notAnArray++;
}
}
int matmax(int **p, int dim) // p- matrix , dim- dimension of the matrix
{
return p[0][0];
}
int main()
{
int *u[5]; // will be a 5x5 matrix
for(int i = 0; i < 5; i++)
u[i] = new int[5];
u[0][0] = 1; // initialize u[0][0] - not mandatory
// put data in u[][]
printf("%d", matmax(u, 0)); //call to function
getche(); // just to see the result
}

Resources