I'm new to C and I'm trying to define a matrix using a struct and some methods that will change the int** field of the struct. The matrix is supposed to be dynamically allocated and also resizable in how many rows it can have. When I run the program below and print out the values of the matrix in main, the matrix just have random values, not the ones inserted in genMatrix() and addRow(). What am I doing wrong? Very grateful for any help.
I define the struct like this:
typedef struct matrix {
int** matrix;
int rows;
int cols;
int capacity;
} matrix;
And then have the following methods that should change the field of the struct:
matrix* genMatrix() {
matrix* matrix = malloc(sizeof(matrix));
initMatrix(matrix, 100, 3, 200);
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
int row[] = {i+j, i*j, i-j};
addRow(matrix, row);
}
}
return matrix;
}
void initMatrix(matrix* matrix, int rows, int cols, int capacity) {
matrix->matrix = malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
matrix->matrix[i] = malloc(cols * sizeof(int));
}
matrix->cols = cols;
matrix->rows = rows;
matrix->capacity = capacity;
}
void addRow(matrix* matrix, int* row) {
if (matrix->rows == matrix->capacity) {
matrix->capacity *= 2;
matrix->matrix = realloc(matrix->matrix, matrix->capacity * sizeof(int*));
}
matrix->matrix[matrix->rows++] = row;
}
And in main I call the function genMatrix and then print the result out, but get random values like 32691, -1240670624 etc.
int main() {
matrix* matrix = genMatrix();
}
WHen you try to add a row here:
int row[] = {i+j, i*j, i-j};
addRow(matrix, row);
the data you are adding is a temporary local variable. On the next loop iteration it will get overwritten and then when the loop exits it will go out of scope.
You need to allocate some memory for the new row data, e.g. using malloc:
int * row = malloc(3 * sizeof(int));
row[0] = i+j;
row[1] = i*j;
row[2] = i-j;
addRow(matrix, row);
Don't forget to free all these row allocations later when you're done with the matrix.
You are storing row, a local variable. This pointer ceases to be valid once its scope ends:
for (int j = 0; j < 10; j++) {
int row[] = {i+j, i*j, i-j};
addRow(matrix, row);
}
You must dynamically allocate memory for the row data, too.
row is a local variable.As soon as loop goes for new iteration data gets overwritten and after loop exits data goes out of scope .
So use
int * row = malloc(NumOfRows * sizeof(int));
and then row members.
Related
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);
}
I want to declare 2D-array in .h file without given numbers of COLS nor ROWS (cause they are read somewhere from inside the main() )
I mean I could tried another way of doing this like below
if one of ROWS and COLS is given at the firsthand.
int COLS = 20;
int (*array)[COLS];
array = malloc((*array) * ROWS);
thus I tried like below:
below is 2d.h
int* a;
int** b;
int size;
below is test2d.c, inside int main(){}
read_size() //size value read from some file
a = malloc(sizeof(int) * size);
b = malloc(sizeof(*a) * size);
for(int i=0; i<size; i++){
for(int j=0; j<size; j++){
b[i][j] = i+j;
printf("ok");
}
}
//print all
should be printing all 0112 but the result is segmentation fault.
To allocate a 2D array you need to allocate the 2D pointer b, which you have done. After that you need to allocate memory for b[i] in a for loop as below
// cols and rows are input by user or other parts of program.
int **b;
b = malloc(sizeof(int*) * rows);
for(int i=0; i<rows; i++){
b[i] = malloc(sizeof(int) * cols);
}
The explanation for this is that b is an array of pointers to int. In each element of b you allocate an array of int. This gives you a 2D array.
If you want a rectangular (not jagged array), it's most efficient to allocate all the cells as a single block, then the row pointers can all point into that block:
#include <stdlib.h>
int **make_array(size_t height, size_t width)
{
/* assume this multiplication won't overflow size_t */
int *cells = malloc((sizeof *cells) * height * width);
int **rows = malloc((sizeof *rows) * height);
if (!rows || !cells) {
free(cells);
free(rows);
return 0;
}
/* now populate the array of pointers to rows */
for (size_t row = 0; row < height; ++row) {
rows[row] = cells + width * row;
}
return rows;
}
This also makes deallocation much simpler, as we no longer need a loop:
void free_array(int **a)
{
if (!a) return;
free(a[0]);
free(a);
}
I'm making a program where I have to work constantly with matrices in functions, this is one of the many functions, this function is supposed to take open an external file which is a data set, where the data is separated with tabulations, it opens the file and saves the data in a matrix M, I know this matrix is composed of 6 columns, but the row number is unknown, I know the error is where I declare the matrix, it has to be declared with pointers since the function returns the matrix.
//type float** since it will return a matrix
float **carga_archivo(char *nombre_archivo)
{
float **M=(float **)malloc(6*sizeof(float*)); //error should be here
int i=0;
FILE *archivo; //FILE type pointer to open the external file
archivo=fopen(nombre__archivo,"r"); //Opens the file in the address indicated
//"nombre_de_archivo" is a variable
while(!feof(archivo)) //Browses the file row per row till the end of it
{
//saves the data in its corresponding place in the matrix
fscanf(archivo,"%f\t%f\t%f\t%f\t%f\t%f\n",
&M[0][i],&M[1][i],&M[2][i],&M[3][i],&M[4][i],&M[5][i]);
i++;
}
tam=i;
fclose (archivo); //closes the file
return M;
}
What I need is the right way to declare the matrix.
P.S. I documented the main lines in the code in case it could help someone who needs something similar.
Any correction is welcome.
Update:
Applied some changes proposed in comments, and worked better, here is the new code I nade for that function
float **carga_archivo(char *nombre_archivo)
{
int i=0;
float P[300][6];
FILE *archivo;
archivo=fopen(nombre_archivo,"r");
while(!feof(archivo))
{
i++;
//this was just so the feof function could browse row per row
//instead of character per character
scanf("%f\t%f\t%f\t%f\t%f\t%f\n",
&P[0][i],&P[1][i],&P[2][i],&P[3][i],&P[4][i],&P[5][i]);
printf("%i\n",i);
}
tam=i;
printf("%i",tam);
int filas = 6;
int columnas = tam;
float **M;
M = (float **)malloc(filas*sizeof(float*));
for (i=0;i<filas;i++)
M[i] = (float*)malloc(columnas*sizeof(float));
for (i = 0; i < columnas; ++i)
fscanf(archivo,"%f\t%f\t%f\t%f\t%f\t%f\n",
&M[0][i],&M[1][i],&M[2][i],&M[3][i],&M[4][i],&M[5][i]);
fclose (archivo);
return M;
}
The new problem is when the function is called, the program actually compiles, but when its running and the function is called the program crashes and stops.
Here Is the part of the code that calls to that function.
int main()
{
int i,j;
char *nombre_archivo="Agua_Vapor.txt";
float **agua_vapor=carga_archivo(nombre_archivo);
for (i = 0; i < 6; i++)
{
for (j = 0; i < tam; i++)
printf("%f ", agua_vapor[i][j]);
printf("\n");
}
return 0;
}
Your program has undefined behaviour, because you're populating memory referenced by uninitialised pointers.
Since you know there are always 6 columns, a simple approach is to store the matrix as row-major instead of column-major (your example is column-major). This means you can store the matrix data as one large piece of memory and use realloc when necessary. You may want to make a simple struct for this too.
struct matrix {
int rows, cols;
float ** data;
};
Then create it dynamically.
struct matrix * matrix_alloc( int rows, int cols )
{
int i;
struct matrix * m = malloc(sizeof(struct matrix));
m->rows = rows;
m->cols = cols;
m->data = malloc(rows * sizeof(float*));
m->data[0] = malloc(rows * cols * sizeof(float));
for( i = 1; i < rows; i++ ) {
m->data[i] = m->data[i-1] + cols;
}
return m;
}
void matrix_free( struct matrix * m )
{
free( m->data[0] );
free( m->data );
free( m );
}
Now, when you decide you need to add storage for more rows:
void matrix_set_row_dimension( struct matrix * m, int rows )
{
float **new_index, *new_block;
new_index = realloc(m->data, rows * sizeof(float**));
new_block = realloc(m->data[0], rows * m->cols * sizeof(float));
if( new_index && new_block )
{
int i = m->rows;
m->rows = rows;
m->data = new_index;
/* if block address changed, prepare to reindex entire block */
if( m->data[0] != new_block )
{
m->data[0] = new_block;
i = 1;
}
/* reindex */
for( ; i < rows; i++ ) {
m->data[i] = m->data[i-1] + cols;
}
}
}
So, now as you populate the matrix...
struct matrix * m = matrix_alloc( 10, 6 ); /* Start with 10 rows */
int row = 0;
while( 1 ) {
/* Double matrix row count if not large enough */
if( row == m->rows )
{
matrix_set_row_dimension( m, m->rows * 2 );
/* Check for error here */
}
/* Now the matrix has enough storage to continue adding */
m->data[row][0] = 42;
m->data[row][1] = 42;
m->data[row][2] = 42;
m->data[row][3] = 42;
m->data[row][4] = 42;
m->data[row][5] = 42;
row++;
}
I found a function that frees memory of a matrix:
void free_matrix(int ***matrix, int rows, int cols) {
int row;
if (matrix != NULL && *matrix != NULL) {
for (row = 0; row < rows; row++) {
free((*matrix)[row]);
(*matrix)[row] = NULL;
}
free(*matrix);
*matrix = NULL;
}
}
I call the method like this:
int **my_vector = create_matrix(5, 5);
free_matrix(&my_vector, 5, 5);
I don't quite understand why the author decided to use ***matrix and not **matrix since in my other method where I create the matrix, he is exactly doing that:
void fill_matrix(int **matrix, int rows, int cols) {
int row = 0;
int col = 0;
for (row = 0; row < rows; row++) {
for (col = 0; col < cols; col++) {
matrix[row][col] = ((row + 1) * 10) + col;
}
}
}
int **create_matrix(int rows, int cols) {
int row;
int **matrix = malloc(rows * sizeof(int *));
for (row = 0; row < rows; row++) {
matrix[row] = malloc(cols * sizeof(int));
}
return matrix;
}
There must a reason why suddenly the author decided to use int ***matrix instead of int **matrix.
The author passes the address of the matrix pointer to allow the free_matrix matrix to reset the pointer to NULL in the caller's scope. It is a precaution to prevent accesses to the matrix data after it has been freed, but if the caller made a copy of the matrix pointer, it can still invoke undefined behavior by accessing it via the copy.
As suggested by Olaf, matrices should be implemented as 2D arrays, for much simpler allocation and deallocation:
/* allocating a pointer to a 2D array matrix[rows][cols] filled to 0 */
int (*matrix)[cols] = calloc(sizeof(*matrix), rows);
/* free the matrix */
free(matrix); matrix = NULL;
But, if the sizes are not constant, the syntax required to pass these matrices as function arguments or worse to return them is not so obvious and requires a C99 compliant compiler.
To clarify the dubious advantage of the *** approach, lets look at the more common 2 star solution:
void free_matrix(int **matrix, int rows, int cols) {
int row;
if (matrix != NULL) {
for (row = 0; row < rows; row++) {
free(matrix[row]);
}
free(matrix);
}
}
int main(void) {
int **my_vector = create_matrix(5, 5);
fill_matrix(my_vector, 5, 5);
free_matrix(my_vector, 5, 5);
if (my_vector) {
/* trying to access the freed data will invoke undefined behavior */
}
return 0;
}
In the code above, my_vector is not reset to NULL by free_matrix, so the programmer might try to access it and invoke undefined behavior (crash or anything else), whereas in the posted code, the three star free_matrix would reset my_vector to NULL which can be easily tested.
I would like a function to return an array, or a pointer to an array, in either c or c++, that does something like the following:
double[][] copy(double b[][], int mx, int my, int nx, int ny)
{
double[nx][ny] a;
int i,j;
for(i = mx; i<= nx; ++i)
for(j = my; j<= ny; ++j)
a[i][j] = b[i][j];
return a;
}
void main(void){
double A[2][3];
double B[2][3] = {{1,2}{3,4}{5,6}};
A = copy(B,0,0,1,2);
}
This is the proper method for returning an array from a function is as follows:
#define NUM_ROWS (5)
#define NUM_COLS (3)
char **createCharArray(void)
{
char **charArray = malloc(NUM_ROWS * sizeof(*charArray));
for(int row = 0; row < NUM_ROWS; row++)
charArray[row] = malloc(NUM_COLS * sizeof(**charArray));
return charArray;
}
In this example, the above function can be called like this:
char **newCharArray = createCharArray();
newCharArray can now be used:
char ch = 'a';
for(int row = 0; row < NUM_ROWS; row++)
for(int col = 0; col < NUM_COLS; col++)
newCharArray[row][col] = ch++;
An array can be passed as an argument to function similarly:
void freeCharArray(char **charArr)
{
for(int row = 0; row < NUM_ROWS; row++)
free(charArr[row]);
free(charArr);
}
You can return the double ** from your copy function like this.
double ** copy(double *src, int row, int col)
{
// first allocate the array with required size
double **copiedArr = (double **) malloc(sizeof(double *)*row);
for(int i=0;i<row;i++)
{
// create space for the inner array
*(copiedArr+i) = (double *) malloc(sizeof(double)*col);
for(int j=0; j<col; j++)
{
// copy the values from source to destination.
*(*(copiedArr+i)+j) = (*(src+i+j));
}
}
// return the newly allocated array.
return copiedArr;
}
call to this function is done like this.
double src[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
double **dest = copy(&src[0][0],3,3); //here is your new array
Here you have to assign returned value of copy() to double** not to double[][].
If you try to assign the returned value to array then it will generate "Incompatible types" error (detail).
As memory allocated to copiedArray on the heap so you have to take responsibility to clear the memory.
void freemem(double **mem, int row)
{
for(int i=0;i<row; i++)
{
free(*(mem+i));
}
free(mem);
}
I also want to point out some correction in your sample code:
return type of main should be int.
one should put the return statement at the end of main.
you can't return the stack allocated value, it is cause of crash
in most of cases.