finding the size of a multidimensional array? - c

#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
struct Array {
uint32_t* row;
};
int main()
{
struct Array* a = malloc(sizeof(struct Array) * 2);
a[0].row = malloc(sizeof(uint32_t) * 3);
a[1].row = malloc(sizeof(uint32_t) * 2);
uint32_t temp1[] = {2,3,4};
uint32_t temp2[] = {5,8};
for(int i=0;i<3;i++)
a[0].row[i] = temp1[i];
for(int i=0;i<2;i++)
a[1].row[i]= temp2[i];
for(int i=0;i<2;i++)
{
int len = sizeof(a[i].row)/sizeof(a[i].row[0]);
for(int j=0;j<len;j++)
{
printf("%d\t",a[i].row[j]);
}
printf("\n");
}
}
I have a multidimensional array. rows in the array can be of different size so i used a structure.
Now I want to print the elements in the array. But its not printing in the right way.
2 3
5 8
This is showing as my output.
int len = sizeof(a[i].row)/sizeof(a[i].row[0]);
I think there is something wrong in the above line.
please help me to print the elements of array correctly

It will not work this way as it will give you the size of the pointer in uint32_t units.
If you want to dynamically allocate the 2D array you need to keep the sizes somewhere in your data. Here is an example (access using array pointer):
typedef struct
{
size_t cols, rows;
uint32_t data[];
}Array2D;
Array2D *alloc2DArray(const size_t rows, const size_t cols)
{
return malloc(rows * cols * sizeof(uint32_t) + sizeof(Array2D));
}
void printArray(const Array2D *arr)
{
uint32_t (*array)[arr -> cols] = (uint32_t (*)[])arr -> data;
for(size_t row = 0; row < arr -> rows; row++)
{
for(size_t col = 0; col < arr -> cols; col++)
printf("%"PRIu32" ", array[row][col]);
printf("\n");
}
}
Sizes are kept in the struct and the actual data in the flexible struct member.
Remember to use the correct type to store the sizes (size_t)

Related

Process a 2D array made with different methods in the same function in C

I have created two matrices in C with the following code:
static allocation method
int data[NMAX][NMAX]; // define NMAX 10 is in header
dynamic allocation method
int** data = (int**) malloc(sizeof(int*) * N);
for (int i = 0; i < N; i++) {
data[i] = (int*) malloc(sizeof(int) * M);
}
now i want to insert data into them with ONE function like so:
int inputMatrix(int **data, int N, int M) { ... }
How can i make the same function declaration work for both array types?
Currently it outputs
expected 'int **' but argument is of type 'int ** (*)[10]'
I have tried creating the static array like this:
int* data[NMAX];
for (int i = 0; i < N; i++) {
data[i] = (int[NMAX]) {};
}
but this code produces a matrix with every line being the same after I input numbers into it
The function inputMatrix will take an array whose elements are pointers to int, so you can create an array that holds pointers to each rows of statically allocated array and pass that to the function.
Construction of the pointer array can be done like this:
int data[NMAX][NMAX];
int *pdata[NMAX]; // array of pointers
for (int i = 0; i < N; i++) {
pdata[i] = data[i]; // the array data[i] is converted to pointers to their first elements here
}
##EDI##
You array pointers
int arr[10][5];
int main(void)
{
srand(time(NULL));
fillArray(5, 10, arr);
printArray(5, 10, arr);
}
See the implementations below https://godbolt.org/z/M6GhrEojn
Do not use arrays of pointers. Use array pointers instead. You remove one level of indirection and you can allocate and free it using one function call. As the whole array is a contignous chunk of memory it is much easier for processor yo use the cache.
void *allocateArray(size_t rows, size_t cols)
{
int (*a)[cols] = malloc(rows * sizeof(*a));
return a;
}
and example usage:
void fillArray(size_t cols, size_t rows, int (*arr)[cols])
{
for(size_t row = 0; row < rows; row++)
for(size_t col = 0; col < cols; col++)
arr[row][col] = rand();
}
void printArray(size_t cols, size_t rows, int (*arr)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
printf("[%02zu][%02zu]%d,\t", row, col, arr[row][col]);
printf("\n");
}
}
int main(void)
{
size_t cols, rows;
scanf("%zu,%zu", &rows, &cols);
printf("rows:%zu, cols:%zu", rows, cols);
int (*array)[cols] = allocateArray(rows, cols);
srand(time(NULL));
printf("%p\n", array);
if(array)
{
fillArray(rows, cols, array);
printArray(rows, cols, array);
}
free(array);
}

Set pointers on Dynamic Matrix

I'm trying to make a dynamic size matrix of 1-byte elements. To do so I defined the following function. The problem comes when I try to set the first "nrows" elements of the matrix to point the corresponding row (so I can do matrix[i][j]). It looks like that matrix[i] = matrix[nrows + i * single_row_elements_bytes]; doesn't work well enough (the program compiles but throws an core-segment-violation error). How can I make this work?
uint8_t **NewMatrix(unsigned nrows, unsigned ncols)
{
uint8_t **matrix;
size_t row_pointer_bytes = nrows * sizeof *matrix;
size_t single_row_elements_bytes = ncols * sizeof **matrix;
matrix = malloc(row_pointer_bytes + nrows * single_row_elements_bytes);
unsigned i;
for(i = 0; i < nrows; i++)
matrix[i] = matrix[nrows + i * single_row_elements_bytes];
return matrix;
}
Apart from various bugs mentioned in another answer, you are allocating the 2D array incorrectly. You are actually not allocating a 2D array at all, but instead a slow, fragmented look-up table.
The correct way to allocate a 2D array dynamically is described at How do I correctly set up, access, and free a multidimensional array in C?. Detailed explanation about how this works and how array pointers work is explained at Function to dynamically allocate matrix.
Here is an example using the above described techniques, for your specific case:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
void NewMatrix (size_t nrows, size_t ncols, uint8_t (**matrix)[nrows][ncols])
{
*matrix = malloc ( sizeof (uint8_t[nrows][ncols]) );
}
int main (void)
{
size_t r = 3;
size_t c = 4;
uint8_t (*arr_ptr)[r][c];
NewMatrix(r, c, &arr_ptr);
uint8_t (*matrix)[c] = arr_ptr[0];
uint8_t count=0;
for(size_t i=0; i<r; i++)
{
for(size_t j=0; j<c; j++)
{
matrix[i][j] = count;
count++;
printf("%2."PRIu8" ", matrix[i][j]);
}
printf("\n");
}
free(arr_ptr);
}
I think there are a couple of problems with your code.
You can simplify this line:
matrix = malloc(row_pointer_bytes + nrows * single_row_elements_bytes);
to:
matrix = malloc(row_pointer_bytes);
Which allocates space for uint8_t* many rows in the matrix.
The malloc() function only requires size_t amount of bytes needed to allocate requested memory on the heap, and returns a pointer to it.
and that can simply be allocated by knowing how many rows are needed in the matrix, in this case nrows.
Additionally, your for loop:
for(i = 0; i < nrows; i++)
matrix[i] = matrix[nrows + i * single_row_elements_bytes];
Doesn't allocate memory for matrix[i], since each row has n columns, and you need to allocate memory for those columns.
This should instead be:
for(i = 0; i < nrows; i++)
matrix[i] = malloc(single_row_elements_bytes);
Another issue is how are allocating single_row_elements_bytes. Instead of:
size_t single_row_elements_bytes = ncols * sizeof **matrix; //**matrix is uint8_t**
This needs allocate uint8_t bytes for n columns, not uint8_t** bytes. It can be this instead:
size_t single_row_elements_bytes = ncols * sizeof(uint8_t);
Having said this, your code will compile if written like this. This is an example I wrote to test the code.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
uint8_t **NewMatrix(unsigned nrows, unsigned ncols);
int
main(int argc, char *argv[]) {
uint8_t **returnmatrix;
unsigned nrows = 2, ncols = 2;
int i, j;
returnmatrix = NewMatrix(nrows, ncols);
for (i = 0; i < nrows; i++) {
for (j = 0; j < ncols; j++) {
printf("Enter number for row %d column %d: ", i+1, j+1);
/* format speficier for uint8_t, from <inttypes.h> */
if (scanf("%"SCNu8"", &returnmatrix[i][j]) != 1) {
printf("Invalid 8 bit number.\n");
exit(EXIT_FAILURE);
}
}
}
printf("\nYour matrix:\n");
for (i = 0; i < nrows; i++) {
for (j = 0; j < ncols; j++) {
printf("%d ", returnmatrix[i][j]);
}
printf("\n");
}
/* Good to free at the end */
free(returnmatrix);
return 0;
}
uint8_t
**NewMatrix(unsigned nrows, unsigned ncols) {
int i;
uint8_t **matrix;
size_t row_pointer_bytes = nrows * sizeof * matrix;
size_t column_row_elements_bytes = ncols * sizeof(uint8_t);
matrix = malloc(row_pointer_bytes);
/* Good to check return value */
if (!matrix) {
printf("Cannot allocate memory for %d rows.\n", nrows);
exit(EXIT_FAILURE);
}
for(i = 0; i < nrows; i++) {
matrix[i] = malloc(column_row_elements_bytes);
if (!matrix[i]) {
printf("Cannot allocate memory for %d columns.\n", ncols);
exit(EXIT_FAILURE);
}
}
return matrix;
}
Input:
Enter number for row 1 column 1: 1
Enter number for row 1 column 2: 2
Enter number for row 2 column 1: 3
Enter number for row 2 column 2: 4
Output:
Your matrix:
1 2
3 4
Compiled with:
gcc -Wall -o matrix matrix.c
for (i=0;i<nrows;i++)
matrix[i] = (uint8_t *)malloc(ncols * sizeof(uint8_t));
The below 2 lines have to be replaced by the above 2 lines
for(i = 0; i < nrows; i++)
matrix[i] = matrix[nrows + i * single_row_elements_bytes];
with (nrows + i * single_row_elements_bytes) as the allocation size, and with nrows = 5 and ncols =5, say, a total of 65 bytes are allocated.
This include 40 bytes to store row pointers(assuming a 64bit pointer size) and rest 25 bytes to store contents of each r,c element. But the memory for column pointer (pointer to each element in that row) is not allocated.
So, dereferencing matrix[i][j] will seg fault.

Plain C - Array pointers

I have structure to hold pointer to array of input numbers. When I create matrix I also create default data array. As I suppose the m.data = data; means that m.data pointer points at first element of the array. When I print data right after alocation everything seems ok. But when I print them after in the main function the result is different.
Why does output differs(commented sections)?
#include <stdio.h>
#include <stdlib.h>
typedef struct matrix {
int *data;
int rows;
} Matrix;
//Create Matrix
extern Matrix create_matrix(int size)
{
int data[size * size];
int i = 0;
for(i = 0; i < size * size; i++)
{
data[i] = 0;
}
Matrix m;
m.data = data;
for(i = 0; i < size * size; i++)
{
printf("%d\n",*(m.data + i)); //<--- m.data {0,0 ..... ,0,0,0}
}
m.rows = size;
return m;
};
extern void supply_row_data(Matrix m, int row, int* data)
{
int i = 0;
for(i = 0; i < m.rows; i++)
{
m.data[i] = data[i];
}
};
int main(){
int size = 4;
Matrix m = create_matrix(size);
int i = 0;
int *j = m.data;
for(i = 0; i < size * size; i++)
{
//*(j + i) = i;
printf("%d\n", *(j + i));
}
getch();
}
int data[size * size];
This is a local variable (array) to the function create_matrix It goes out of scope when the function terminates.
m.data = data;
This does not copy the data in the variable data to the data in the variable m.data but rather sets the pointer m.data to the beginning of the array data. When the function returns, the Matrix returned contains what is called a dangling pointer: a pointer to data that no longer exists.
Use the advice from #RSahu to fix this.
That's not how you can copy the data from an array in C.
You need to:
Allocate memory for the data.
m.data = malloc(sizeof(int)*size*size);
Copy the data one element at a time or using memcpy.
memcpy(m.data, data, sizeof(int)*size*size);
Make sure you deallocate the memory allocated to hold the matrix data.
free(m.data);
You should avoid using pointer to local data once function return address of array is no loger valid try to allocate array in following way
int* allocate_vector(size_t elem, int value){
int* vec = (int *) calloc(elem, sizeof(int));
int i = 0;
for( ; i < elem; i++){
*(vec + i) = value;
}
return vec;
}

How do we allocate a 2-D array using One malloc statement

I have been asked in an interview how do i allocate a 2-D array and below was my solution to it.
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
exit or return
}
}
I thought I had done a good job but then he asked me to do it using one malloc() statement not two. I don't have any idea how to achieve it.
Can anyone suggest me some idea to do it in single malloc()?
Just compute the total amount of memory needed for both nrows row-pointers, and the actual data, add it all up, and do a single call:
int **array = malloc(nrows * sizeof *array + (nrows * (ncolumns * sizeof **array));
If you think this looks too complex, you can split it up and make it a bit self-documenting by naming the different terms of the size expression:
int **array; /* Declare this first so we can use it with sizeof. */
const size_t row_pointers_bytes = nrows * sizeof *array;
const size_t row_elements_bytes = ncolumns * sizeof **array;
array = malloc(row_pointers_bytes + nrows * row_elements_bytes);
You then need to go through and initialize the row pointers so that each row's pointer points at the first element for that particular row:
size_t i;
int * const data = array + nrows;
for(i = 0; i < nrows; i++)
array[i] = data + i * ncolumns;
Note that the resulting structure is subtly different from what you get if you do e.g. int array[nrows][ncolumns], because we have explicit row pointers, meaning that for an array allocated like this, there's no real requirement that all rows have the same number of columns.
It also means that an access like array[2][3] does something distinct from a similar-looking access into an actual 2d array. In this case, the innermost access happens first, and array[2] reads out a pointer from the 3rd element in array. That pointer is then treatet as the base of a (column) array, into which we index to get the fourth element.
In contrast, for something like
int array2[4][3];
which is a "packed" proper 2d array taking up just 12 integers' worth of space, an access like array[3][2] simply breaks down to adding an offset to the base address to get at the element.
int **array = malloc (nrows * sizeof(int *) + (nrows * (ncolumns * sizeof(int)));
This works because in C, arrays are just all the elements one after another as a bunch of bytes. There is no metadata or anything. malloc() does not know whether it is allocating for use as chars, ints or lines in an array.
Then, you have to initialize:
int *offs = &array[nrows]; /* same as int *offs = array + nrows; */
for (i = 0; i < nrows; i++, offs += ncolumns) {
array[i] = offs;
}
Here's another approach.
If you know the number of columns at compile time, you can do something like this:
#define COLS ... // integer value > 0
...
size_t rows;
int (*arr)[COLS];
... // get number of rows
arr = malloc(sizeof *arr * rows);
if (arr)
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < COLS; j++)
arr[i][j] = ...;
}
If you're working in C99, you can use a pointer to a VLA:
size_t rows, cols;
... // get rows and cols
int (*arr)[cols] = malloc(sizeof *arr * rows);
if (arr)
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
arr[i][j] = ...;
}
How do we allocate a 2-D array using One malloc statement (?)
No answers, so far, allocate memory for a true 2D array.
int **array is a pointer to pointer to int. array is not a pointer to a 2D array.
int a[2][3] is an example of a true 2D array or array 2 of array 3 of int
To allocate memory for a true 2D array, with C99, use malloc() and save to a pointer to a variable-length array (VLA)
// Simply allocate and initialize in one line of code
int (*c)[nrows][ncolumns] = malloc(sizeof *c);
if (c == NULL) {
fprintf(stderr, "out of memory\n");
return;
}
// Use c
(*c)[1][2] = rand();
...
free(c);
Without VLA support, if the dimensions are constants, code can use
#define NROW 4
#define NCOL 5
int (*d)[NROW][NCOL] = malloc(sizeof *d);
You should be able to do this with (bit ugly with all the casting though):
int** array;
size_t pitch, ptrs, i;
char* base;
pitch = rows * sizeof(int);
ptrs = sizeof(int*) * rows;
array = (int**)malloc((columns * pitch) + ptrs);
base = (char*)array + ptrs;
for(i = 0; i < rows; i++)
{
array[i] = (int*)(base + (pitch * i));
}
I'm not a fan of this "array of pointers to array" to solve the multi dimension array paradigm. Always favored a single dimension array, at access the element with array[ row * cols + col]? No problems encapsulating everything in a class, and implementing a 'at' method.
If you insist on accessing the members of the array with this notation: Matrix[i][j], you can do a little C++ magic. #John solution tries to do it this way, but he requires the number of column to be known at compile time. With some C++ and overriding the operator[], you can get this completely:
class Row
{
private:
int* _p;
public:
Row( int* p ) { _p = p; }
int& operator[](int col) { return _p[col]; }
};
class Matrix
{
private:
int* _p;
int _cols;
public:
Matrix( int rows, int cols ) { _cols=cols; _p = (int*)malloc(rows*cols ); }
Row operator[](int row) { return _p + row*_cols; }
};
So now, you can use the Matrix object, for example to create a multiplication table:
Matrix mtrx(rows, cols);
for( i=0; i<rows; ++i ) {
for( j=0; j<rows; ++j ) {
mtrx[i][j] = i*j;
}
}
You should now that the optimizer is doing the right thing and there is no call function or any other kind of overhead. No constructor is called. As long as you don't move the Matrix between function, even the _cols variable isn't created. The statement mtrx[i][j] basically does mtrx[i*cols+j].
It can be done as follows:
#define NUM_ROWS 10
#define NUM_COLS 10
int main(int argc, char **argv)
{
char (*p)[NUM_COLS] = NULL;
p = malloc(NUM_ROWS * NUM_COLS);
memset(p, 81, NUM_ROWS * NUM_COLS);
p[2][3] = 'a';
for (int i = 0; i < NUM_ROWS; i++) {
for (int j = 0; j < NUM_COLS; j++) {
printf("%c\t", p[i][j]);
}
printf("\n");
}
} // end of main
You can allocate (row*column) * sizeof(int) bytes of memory using malloc.
Here is a code snippet to demonstrate.
int row = 3, col = 4;
int *arr = (int *)malloc(row * col * sizeof(int));
int i, j, count = 0;
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
*(arr + i*col + j) = ++count; //row major memory layout
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
printf("%d ", *(arr + i*col + j));

Can anyone explain me how to return a two dimensonal array in C from a function?

I am new to C and during my learning I want to return a two dimensional array from a function, so that I can use it in my main program. Can anyone explain me the same with example. Thanks in advance.
It depends how it is implemented. You can either work with just a one-dimensional array where you know the length of each (row) and the next row begins immediately after the previous one. OR, you can have an array of pointers to arrays. The extra cost though is you need to de-reference two pointers to get to one element of data.
// 2D array of data, with just one array
char* get_2d_ex1(int rows, int cols) {
int r, c, idx;
char* p = malloc(rows*cols);
for (r=0; r<rows; r++) {
for (c=0; c<cols; c++) {
idx = r*cols + c; // this is key
p[idx] = c; // put the col# in its place, for example.
}
}
return p;
}
Declare your function as returning a pointer to a pointer. If we use int as an example:
int **samplefunction() {
int** retval = new int*[100];
for (int i = 1; i < 100; i++) {
retval[i] = new int[100];
}
// do stuff here to retval[i][j]
return retval;
}
Here's an example of how you might create, manipulate and free a "2d array":
#include <stdlib.h>
#define ROWS 5
#define COLS 10
int **create_2d_array(size_t rows, size_t cols)
{
size_t i;
int **array = (int**)malloc(rows * sizeof(int*));
for (i = 0; i < rows; i++)
array[i] = (int*)malloc(cols * sizeof(int));
return array;
}
void free_2d_array(int **array, size_t rows, size_t cols)
{
size_t i;
for (i = 0; i < rows; i++)
free(array[i]);
free(array);
}
int main(void)
{
int **array2d = create_2d_array(ROWS, COLS);
/* ... */
array2d[3][4] = 5;
/* ... */
free_2d_array(array2d, ROWS, COLS);
return 0;
}
To create a "2d array"/matrix, all you have to do is create a dynamic array of pointers (in this case int*) of the size of the rows/width:
int **array = (int**)malloc(rows * sizeof(int*));
Then you set each of those pointers to point to a dynamic array of int of the size of the columns/height:
array[i] = (int*)malloc(cols * sizeof(int));
Note that the casts on malloc aren't required, it's just a habit I have.

Resources