Error when using multidimensional-array of 0 length - c

I want to use two-dimension array inside of some struct:
typedef struct{
int rows;
int cols;
another_struct *array[][];
}some_struct;
But seems i can't do multidimensional array of incomplete type, so i choose to go with another_struct *array[0][0];
And allocate it this way:
some_struct *allocate_some_struct(int rows, int cols){
some_struct *p;
uint32_t length;
length = sizeof(some_struct) + rows * sizeof(another_struct *[cols]);
p = malloc(length);
p->rows = rows;
p->cols = cols;
return (p);
}
But whenever i try to access it this way : ((another_struct *[p->rows][p->cols])p->array)[i],i get this error: used type 'another_struct *[p->rows][p->cols]' where arithmetic or pointer type is required.
Although (*((another_struct *(*)[p->rows][p-cols])&(p->array)))[i], work perfectly fine.
So my questions is why can't i use first syntax? Is there fundamental difference with the second one ?

In C typing is static, so it means that every type must be completely known when you operate with it (when compiling has finished). For a bidimensional array, this means that all the dimensions must be know for the language to be able to do the access to the individual cells. Access to an array is made using a formula that need the size of the already used indexed parts of it. For a cell is the cell size, but for an array of cells you must know how many cells you have in that direction.
But, there's a workaround that allows you to use indexing with the [] brackets, and doesn't need to know any size but the size of an individual cell. You have to use pointers, as in this example:
double **new_matrix(int rows, int cols)
{
double **res = malloc(rows * sizeof(double *));
int i;
for (i = 0; i < rows; i++)
res[i] = malloc(cols * sizeof(double));
return res;
}
void free_matrix(double **matrix, int rows)
{
int i;
for (i = 0; i < rows; i++) free(matrix[i]);
free(matrix);
}
...
double **matrix = new_matrix(24, 3);
matrix[12][1] /* will access correctly row 13 and column 2 element */
...
free(matrix, 24); /* will free all allocated memory */
There are solutions that allow you to allocate the whole matrix (and the pointers in one bunch (and allow to use free(3) directly on the matrix thing) but I leave this as an exercise to the reader :)

Related

Single dynamic allocation for multi-dimensional array

The basic question is:
For code that expects a pointer to pointer that will be syntactically indexed like a 2-dimensional array, is there a valid way to create such an array using a single allocation?†
While on the surface, it seems I am asking for how to do so (like in this question), I already understand how it could be done (see below). The problem is that there might be an alignment issue.&ddagger;
The rest of the text describes some alternatives, and then explains the method under question.
† Olaf points out a pointer to pointer is not a 2-dimensional array. The premise of the question is that 3rd party code expects a pointer to pointer passed in, and the 3rd party code will index it as a 2-dimensional array.
&ddagger; ErikNyquist presented a possible duplicate which explains how one might perform such an allocation, but I am questioning the validity of the technique with regards to alignment of the data.
If I need to dynamically allocate a multi-dimensional array, I typically use a single allocation call to avoid an iteration when I want to free the array later.
If VLA is available, I might code it like this:
int n, m;
n = initialize_n();
m = initialize_m();
double (*array)[m] = malloc(n * sizeof(*array));
array[i][j] = x;
Without VLA, I either rely on a macro on a structure for array accesses, or I add space for the pointer table for code that expects the ** style of two-dimensional array. The macro approach would look like:
struct array_2d {
int n, m;
double data[];
};
// a2d is a struct array_2d *
#define GET_2D(a2d, i, j) (a2d)->data[(i) * x->n + (j)]
struct array_2d *array = malloc(sizeof(*array) + n * m * sizeof(double));
array->n = n;
array->m = m;
GET_2D(array, i, j) = x;
The pointer table method is more complicated, because it requires a loop to initialize the table.
struct array_p2d {
int n, m;
double *data[];
};
#define GET_P2D(a2d, i, j) (a2d)->data[i][j]
struct array_p2d *array = malloc(sizeof(*array) + n * sizeof(double *)
+ n * m * sizeof(double));
for (k = 0; k < n; ++k) {
array->data[k] = (double *)&array->data[n] + k * m;
}
GET_P2D(array, i, j) = x;
// array->data can also be passed to a function wanting a double **
The problem with the pointer table method is that there might be an alignment issue. As long as whatever type the array is of does not have stricter alignment requirements than a pointer, the code should work.
Is the above expected to always work? If not, is there a valid way to achieve a single allocation for a pointer to pointer style 2-dimensional array?
Well, your malloc allocation is guaranteed to be aligned (unless you're using a non-standard alignment), so all you need to do is to round up the pointer table size to the alignment of the data segment:
const size_t pointer_table_size = n * sizeof(double *);
const size_t data_segment_offset = pointer_table_size +
((_Alignof(double) - (pointer_table_size / _Alignof(double))) % _Alignof(double));
double **array = malloc(data_segment_offset + (n * m * sizeof(double));
double *data = (double **)(((char **) array) + data_segment_offset);
for (int i = 0; i != n; ++i)
array[i] = data + (m * i);

Accessing outside the dimensions in array created by a double pointer

Is this the correct method to define an 5*3 matrix using double pointers?`
int **M1;
M1 = (int **)malloc(5 * sizeof(int *));
for (i=0;i<5;i++)
{
M1[i] = (int *)malloc(3 * sizeof(int));
}`
If so, how can I assign M1[3][15] = 9 in the code and still get no error? And why am I getting a segmentation error in assigning M1[6][3]=2?
I understood after few such initializations that I created a 5*xx array, i.e. I couldn't go above 5th row but I could assign any value to the number of columns. How should I create just a 5*3 array?
In your code, you're allocating memory for 5 pointers
M1 = (int **)malloc(5 * sizeof(int *));
and later, you're trying to access beyond that, based on an unrelated value of m
for (i=0;i<m;i++)
when m goes beyond 4, you're essentially accessing out of bound memory.
A better way to allocate will be
int m = 5;
M1 = malloc(m * sizeof(*M1));
if (M1)
{
for (i=0;i<5;i++)
{
M1[i] = malloc(3 * sizeof(*M1[i]));
}
}
couldn't go above 5th row but I could assign any value to the number of columns.
NO, you can not. In any way possible, accessing out of bound memory invokes undefined behaviour.
Since Sourav tackled the UB case, I'll answer
How should I create just a 5*3 array?
Why not rely on automatic variables? Unless you've a compelling reason not to, use them
int matrix[5][3];
If you don't know the dimensions in advance, and don't prefer doing the double pointer manipulation, flatten it like this:
int *m = malloc(sizeof(int) * rows * cols);
// accessing anything from 0 to (rows * cols) - 1 is permitted
// helper to make usage easier
int get_element(int *m, int i, int j, int cols) {
return m[i * cols + j];
}
OTOH, if you only don't know the first dimension at compile-time, then you may do:
typedef int (Int5) [5]; // cols known at complie-time
int rows = 3;
Int5 *r = malloc(rows * sizeof(Int5));
r[0][0] = 1; // OK
r[0][5] = 2; // warning: out of bounds access
With this method you get a bit more type safety due to the compiler knowing the size in advice.

C: Initializing a dynamic array inside a struct

I'm trying to implement my own basic version of matrix multiplication in C and based on another implementation, I have made a matrix data type. The code works, but being a C novice, I do not understand why.
The issue: The I have a struct with a dynamic array inside it and I am initializing the pointer. See below:
// Matrix data type
typedef struct
{
int rows, columns; // Number of rows and columns in the matrix
double *array; // Matrix elements as a 1-D array
} matrix_t, *matrix;
// Create a new matrix with specified number of rows and columns
// The matrix itself is still empty, however
matrix new_matrix(int rows, int columns)
{
matrix M = malloc(sizeof(matrix_t) + sizeof(double) * rows * columns);
M->rows = rows;
M->columns = columns;
M->array = (double*)(M+1); // INITIALIZE POINTER
return M;
}
Why do I need to initialize the array to (double*)(M+1)? It seems that also (double*)(M+100) works ok, but e.g. (double *)(M+10000) does not work anymore, when I run my matrix multiplication function.
The recommended method for this kind of stuff is unsized array used in conjunction with offsetof. It ensures correct alignment.
#include <stddef.h>
#include <stdlib.h>
// Matrix data type
typedef struct s_matrix
{
int rows, columns; // Number of rows and columns in the matrix
double array[]; // Matrix elements as a 1-D array
} matrix;
// Create a new matrix with specified number of rows and columns
// The matrix itself is still empty, however
matrix* new_matrix(int rows, int columns)
{
size_t size = offsetof(matrix_t, array) + sizeof(double) * rows * columns;
matrix* M = malloc(size);
M->rows = rows;
M->columns = columns;
return M;
}
M+1 points to the memory that immediately follows M (i.e. that follows the two int and the double*). This is the memory you've allocated for the matrix data:
matrix M = malloc(sizeof(matrix_t) + sizeof(double) * rows * columns);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Using M+100 or M+10000 and then attempting to populate the matrix will result in undefined behaviour. This could result in a program that crashes, or a program that appears to work (but in reality is broken), or anything in between.
You need to initialize it because otherwise (wait for it) it's uninitialized!
And you can't use an uninitialized pointer for anything, except to generate undefined behavior.
Initializing it to M + 1 is precisely right, and very good code. Any other value would fail to use the memory you allocated for this exact purpose.
My point is that the double * at the end of struct won't "automatically" point at this memory, which is the implied belief in your question why it should be initialized. Thus, it has to be set to the proper address.

How do I write functions which accept two-dimensional arrays when the width is not known at compile time?

Is it possible to write a function which accept 2-d array when the width is not known at compile time?
A detailed description will be greatly appreciated.
You can't pass a raw two-dimensional array because the routine won't know how to index a particular element. The 2D array is really one contiguous memory segment.
When you write x[a][b] (when x is a 2d array), the compiler knows to look at the address (x + a * width + b). It can't know how to address the particular element if you don't tell it the width.
As an example, check http://www.dfstermole.net/OAC/harray2.html#offset (which has a table showing how to find the linear index for each element in an int[5][4])
There are two ways to work around the limitation:
1) Make your program work with pointer-to-pointers (char *). This is not the same as char[][]. A char * is really one memory segment, with each value being a memory address to another memory segment.
2) Pass a 1d pointer, and do the referencing yourself. Your function would then have to take a "width" parameter, and you could use the aforementioned formula to reference a particular point
To give a code example:
#include <stdio.h>
int get2(int *x) { return x[2]; }
int main() {
int y[2][2] = {{11,12},{21,22}};
printf("%d\n", get2((int *)y));
}
This should print out 21, since y is laid out as { 11, 12, 21, 22 } in memory.
C supports variable-length arrays. You must specify the width from a value known at run-time, which may be an earlier parameter in the function declaration:
void foo(size_t width, int array[][width]);
One way is use the good old "pointer to array of pointers to arrays" trick coupled with a single continuous allocation:
/* Another allocation function
--------------------------- */
double ** AnotherAlloc2DTable(
size_t size1, /*[in] Nb of lines */
size_t size2 /*[in] Nb of values per line */
)
{
double ** ppValues;
size_t const size1x2 = size1*size2;
if(size1x2 / size2 != size1)
return NULL; /*size overflow*/
ppValues = malloc(sizeof(*ppValues)*size1);
if(ppValues != NULL)
{
double * pValues = malloc(sizeof(*pValues)*size1x2);
if(pValues != NULL)
{
size_t i;
/* Assign all pointers */
for(i=0 ; i<size1 ; ++i)
ppValues[i] = pValues + (i*size2);
}
else
{
/* Second allocation failed, free the first one */
free(ppValues), ppValues=NULL;
}
}/*if*/
return ppValues;
}
/* Another destruction function
---------------------------- */
void AnotherFree2DTable(double **ppValues)
{
if(ppValues != NULL)
{
free(ppValues[0]);
free(ppValues);
}
}
Then all you have to do is pass a char ** to your function. The matrix is continuous, and usable as mat[x][y].
Possible accessor functions:
int get_multi(int rows, int cols, int matrix[][cols], int i, int j)
{
return matrix[i][j];
}
int get_flat(int rows, int cols, int matrix[], int i, int j)
{
return matrix[i * cols + j];
}
int get_ptr(int rows, int cols, int *matrix[], int i, int j)
{
return matrix[i][j];
}
An actual multi-dimensional array and a fake one:
int m_multi[5][7];
int m_flat[5 * 7];
Well-defined ways to use the accessor functions:
get_multi(5, 7, m_multi, 4, 2);
get_flat(5, 7, m_flat, 4, 2);
{
int *m_ptr[5];
for(int i = 0; i < 5; ++i)
m_ptr[i] = m_multi[i];
get_ptr(5, 7, m_ptr, 4, 2);
}
{
int *m_ptr[5];
for(int i = 0; i < 5; ++i)
m_ptr[i] = &m_flat[i * 7];
get_ptr(5, 7, m_ptr, 4, 2);
}
Technically undefined usage that works in practice:
get(5, 7, (int *)m_multi, 4, 2);
[Warning - this answer addresses the case where the number of columns - the WIDTH - is known]
When working with 2D arrays, the compiler needs to know the number of columns in your array in order to compute indexing. For instance, if you want a pointer p that points to a range of memory to be treated as a two-dimensional set of values, the compiler cannot do the necessary indexing arithmetic unless it knows how much space is occupied by each row of the array.
Things become clearer with a concrete example, such as the one below. Here, the pointer p is passed in as a pointer to a one-dimensional range of memory. You - the programmer - know that it makes sense to treat this as a 2D array and you also know (must know) how many columns are there in this array. Armed with this knowledge, you can write code to create q, that is treated by the compiler as a 2D array with an unknown number of rows, where each row has exactly NB columns.
I usually employ this when I want the compiler to do all the indexing arithmetic (why do it by hand when the compiler can do it?). In the past, I've found this construct to be useful to carry out 2D transposes from one shape to another - note though that generalized 2D transposes that transpose an MxN array into an NxM array are rather beastly.
void
WorkAs2D (double *p)
{
double (*q)[NB] = (double (*)[NB]) p;
for (uint32_t i = 0; i < NB; i++)
{
for (uint32_t j = 0; j < ZZZ; j++) /* For as many rows as you have in your 2D array */
q[j][i] = ...
}
}
I believe a nice solution would be the use of structures.
So I have an example for 1d-Arrays:
Definition of the struct:
struct ArrayNumber {
unsigned char *array;
int size;
};
Definition of a function:
struct ArrayNumber calcMultiply(struct ArrayNumber nra, struct ArrayNumber nrb);
Init the struct:
struct ArrayNumber rs;
rs.array = malloc(1);
rs.array[0] = 0;
rs.size = 1;
//and adding some size:
rs.size++;
rs.array = realloc(rs.array, rs.size);
hope this could be a solution for you. Just got to change to a 2d Array.

Double array through pointers in C

I want to scan a 2D array with the help of pointers and have written this code, could you tell me why the compiler gives errors?
#include<stdio.h>
#include<stdlib.h>
int main(void) {
int i,j,n,a,b;
int (*(*p)[])[];
printf("\n\tEnter the size of the matrix in the form aXb\t\n");
scanf("%dX%d",&a,&b);
p=(int (*(*p)[b])[a])malloc(b*sizeof(int (*p)[a]));
for(i=0;i<b;i++) {
p[i]=(int (*p)[a])malloc(a*sizeof(int));
printf("\t\bEnter Column %d\t\n");
for(j=0;j<a;j++)
scanf("%d",&p[i][j]);
}
return 0;
}
This statement has several problems:
p=(int (*(*p)[b])[a])malloc(b*sizeof(int (*p)[a]));
First, malloc returns a void*. You are casting that pointer using (int (*(*p)[b])[a]) which yields a value, not a data type. That isn't a valid cast, so that's one reason that the compiler is yelling at you. At this point, p hasn't been initialized so the de-referencing taking place here can crash your program if this statement was executed.
Inside your malloc call, you are using sizeof(int (*p)[a]). The statement int (*p)[a] isn't a valid C statement.
It seems that you are making this a bit more complex that it needs to be. There are two ways of building a 2D array. You can build an array using malloc(a * b * sizeof(int)) as Reinderien explains. You can also build a 1D array of pointers, each pointing to an array of type int. From your code, it seems you are trying to do the latter.
The easier way to do this would be something like this:
int **p;
... get input from user ...
// Declare an array of int pointers of length b
p = malloc(b * sizeof(int*));
// For each int* in 'p' ...
for (i = 0; i < b; ++i) {
// ... allocate an int array of length 'a' and store a pointer in 'p[i]' ..
p[i] = malloc(a * sizeof(int));
// ... and fill in that array using data from the user
printf("\t\bEnter Column %d\t\n");
for(j = 0; j < a; j++)
scanf("%d", &p[i][j]);
}
Using this method of building a 2D array allows you to use the syntax p[x][y]. Since p is a pointer-to-pointer, p[x] is a pointer to an array and p[x][y] is an item in the pointed-to array.
That's some pretty contorted syntax. Usually when you make a 2D array:
The declaration is simply int *p;
The allocation is simply p = malloc(a*b*sizeof(int));
You cannot write p[i][j]. You must do one of several things - either make a secondary array int **q that contains row pointers to be able to write q[i][j] (better performance and legibility), or write p[b*i + j] (fewer steps).
Additionally, note that:
Your printf will spew garbage due to the missing %d parameter.
Since C is not typesafe, using scanf will hide any errors in indirection that you may make.
About the closest thing I could think of that remotely resembles what you were trying to do:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j;
const int a = 3, b = 4;
int m[4][3];
int (*p[4])[3];
for (i = 0; i < b; i++)
{
p[i] = &m[i];
printf("\t\bEnter Column %d\t\n", i);
for (j = 0; j < a; j++)
{
int x;
scanf("%d", &x);
(*p[i])[j] = x;
}
}
return 0;
}
It compiles and functions as expected, but it's pointlessly complicated. p is an array of pointers to arrays.

Resources