So my goal is to malloc a maze struct that contains a 2D array; however, when I try to allocate memory for each "cell" of the 2D array I can't seem to free it properly afterwards. Is there a way that I could malloc the struct in one line or at least in a way that I can easily free the allocated memory with the free_maze function? I've attached my .c file along with the header file that defines the struct. Additionally, I have attached an example of a maze that is contained within a text file.
#include <stdlib.h>
#include "maze.h"
Maze* malloc_maze(int num_rows, int num_cols){
Maze* maze = malloc(sizeof(*maze));
if (maze == NULL){
free(maze);
return NULL;
}
maze -> cells = malloc(sizeof(maze -> cells)*(num_cols));
if (maze -> cells == NULL){
free(maze);
return NULL;
}
for(int i = 0; i < num_cols; i++){
maze -> cells[i] = malloc(sizeof(*(maze -> cells))*(num_rows));
}
maze -> num_rows = num_rows;
maze -> num_cols = num_cols;
return maze;
}
void free_maze(Maze* maze){
free(maze);
}
Maze* read_maze(FILE* fp){
Maze* maze;
char c = fgetc(fp);
int rows = 0;
int cols = 0;
int chars = 0;
while(c != EOF){
chars++;
c = fgetc(fp);
}
rewind(fp);
while(c != '\n'){
cols++;
c = fgetc(fp);
}
rows = chars / cols;
cols--;
maze = malloc_maze(rows, cols);
rewind(fp);
for(int row_count =0; row_count <= rows; row_count++){
for(int col_count = 0; col_count < cols; col_count++){
fseek(fp, (row_count*(cols+1)+col_count), SEEK_SET);
maze -> cells[col_count][row_count] = fgetc(fp);
}
}
maze -> num_rows = rows;
maze -> num_cols = cols;
return maze;
}
bool write_maze(const char* filename, const Maze* maze){
FILE* ha;
ha = fopen(filename, "w");
if(ha == NULL){
return false;
}
rewind(ha);
int rows = maze -> num_rows;
int cols = maze -> num_cols;
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
fputc(maze -> cells[j][i], ha);
}
fputc('\n', ha);
}
fclose(ha);
return true;
}
/////////////////header file//////////////////////////
#ifndef MAZE_H
#define MAZE_H
#define WALL 'X'
#define PATH ' '
#include <stdio.h>
#include <stdbool.h>
typedef struct _Maze {
int num_rows;
int num_cols;
char** cells;
} Maze;
Maze* malloc_maze(int num_rows, int num_cols);
void free_maze(Maze* maze){
__attribute__((nonnull));
}
Maze* read_maze(FILE* fp){
__attribute__((nonnull));
}
bool write_maze(const char* filename, const Maze* maze){
__attribute__((nonnull));
}
///////////////example maze within .txt file/////////////////////
XXXXX XXX
X X
X XXX XXX
X X X X
X X XXXXX
X X
XXXXX XXX
Given an allocator function, the deallocator writes itself - you free the pointers in roughly the reverse order they were allocated.
So, given that the allocator is (only reformatted from the question — functionality unchanged):
Maze *malloc_maze(int num_rows, int num_cols)
{
Maze *maze = malloc(sizeof(*maze));
if (maze == NULL)
{
free(maze);
return NULL;
}
maze->cells = malloc(sizeof(maze->cells) * (num_cols));
if (maze->cells == NULL)
{
free(maze);
return NULL;
}
for (int i = 0; i < num_cols; i++)
{
maze->cells[i] = malloc(sizeof(*(maze->cells)) * (num_rows));
}
maze->num_rows = num_rows;
maze->num_cols = num_cols;
return maze;
}
the deallocator should be:
void free_maze(Maze *maze)
{
for (int i = 0; i < num_cols; i++)
free(maze->cells[i]);
free(maze->cells);
free(maze);
}
This makes sure the code doesn't try to access memory after it is freed.
However, closer analysis of the allocator shows that there are some (minor) problems. For example, normally you treat the pair of indexes as maze->cells[row][col], but the memory allocation requires it to be used as maze->cells[col][row]. Both can work, but the row-column order is more usual in C. Also, the sizes in the second and third malloc() calls are incorrect. Fortunately for you, the second one allocates in units of sizeof(char **) instead of sizeof(char *), but those are the same size, so it "doesn't matter". The third one allocates sizeof(char *) units, instead of sizeof(char), so there is much more memory allocated than memory (normally, sizeof(char *) is 4 or 8 bytes but sizeof(char) is 1 by definition).
So, you might do better to use this, which keeps the maze->cells[col][row] access notation:
Maze *malloc_maze(int num_rows, int num_cols)
{
Maze *maze = malloc(sizeof(*maze));
if (maze == NULL)
return NULL;
maze->cells = malloc(sizeof(maze->cells[0]) * num_cols);
if (maze->cells == NULL)
{
free(maze);
return NULL;
}
for (int i = 0; i < num_cols; i++)
{
maze->cells[i] = malloc(sizeof(maze->cells[0][0]) * num_rows);
if (maze->cells[i] == 0)
{
for (int j = 0; j < i; j++)
free(maze->cells[j]);
free(maze->cells);
free(maze);
return NULL;
}
}
maze->num_rows = num_rows;
maze->num_cols = num_cols;
return maze;
}
This cleans up the partially allocated memory on allocation failure. It doesn't change the deallocation code (unless you want to add a null check, but if the allocation failed, you shouldn't be calling the deallocation code).
NOTE: I believe the code automatically takes care of alignment in OP's case. I am still working on to tweak it to work with any data type of members of Maze. The alignment is broken if sizeof(char*) exceeds sizeof(T) where T is the type of cell[0][0].
You can allocate memory for the entire maze in one malloc call. This will allow you to free the memory in one free call. It improves performance because:
it requires a single malloc (and free) call
the memory allocated is contiguous (cache friendly)
Maze *malloc_maze(int num_rows, int num_cols)
{
const size_t mem_size = sizeof(Maze)
+ num_cols*sizeof(((Maze*)0)->cells[0]) /* indirection array */
+ sizeof((((Maze*)0)->cells[0][0]))*num_cols*num_rows; /* matrix */
void *block = malloc(mem_size);
if(block == NULL)
return NULL;
Maze *maze = block;
maze->cells = (void*)(maze + 1);
block = &maze->cells[0] + num_cols;
for(int i = 0; i < num_cols; i++)
{
maze->cells[i] = block;
block = &maze->cells[i][0] + num_rows;
}
maze->num_rows = num_rows;
maze->num_cols = num_cols;
return maze;
}
void free_maze(Maze *maze)
{
free(maze);
}
Related
Having trouble understanding and getting to work String operations in the following code.
Please help, me and my study colleagues are losing our minds over this. ty.
This is a simple method to fill a multi dimensional array with custom strings - which for some reason we cannot figure out for the life of us does simply not work - spits out random junk from the memory instead. Also allocation amounts don't seem to be quite right.
#include <stdio.h>
#include <malloc.h>
#include <string.h>
char*** createKeyPad(int rows, int cols, int num_chars) {
if(num_chars <= 0) return NULL;
char needed = 'a';
char** aptr = NULL;
char*** rptr = NULL;
aptr = (char**) malloc(rows * cols * sizeof(char*));
if(aptr == NULL) {
return NULL;
}
rptr = (char***) malloc(rows * sizeof(char**));
if(rptr == NULL) {
free(aptr);
return NULL;
}
for(int row = 0; row < rows; row++) {
rptr[row] = aptr + (row * cols);
}
for(int row = 0; row < rows; row++) {
for(int col = 0; col < cols; col++) {
char* string;
for(int i = 0; i < num_chars; i++) {
string[i] = needed;
}
string[num_chars] = '\0';
rptr[row][col] = string;
printf("%s", string);
}
}
printf("%s", "hallo");
return rptr;
}
int main() {
printf("Hello, World!\n");
char*** keypad = createKeyPad(5, 5, 3);
for(int row = 0; row < 5; row++) {
for(int col = 0; col < 5; col++) {
printf("%s", keypad[row][col]);
}
printf("\n");
}
}
You have plenty problems in this code.
string is a dangling pointer - ie it was not initialized and does not reference a valid char array
even if string was referencing a valid object you assign the same pointer to all (pseudo)array elements.
Do not use *** pointers.
use the correct type for sizes
Use positive checks and try to minimize function returns.
arrays are indexed from 0 in C and even if the string was referencing an array of num_chars elements, string[num_chars] = '\0'; is accessing an element outside the array bounds.
I would use array pointers and use only one allocation to allocate the space for the whole 3D array.
Use objects instead of types in sizeofs
int createKeyPad(size_t rows, size_t cols, size_t numChars, char (**pad)[cols][numChars])
{
int result = 0;
if(numChars > 1)
{
*pad = malloc(rows * sizeof(**pad));
if(*pad)
{
result = 1;
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
for(size_t i = 0; i < numChars - 1; i++)
{
(*pad)[row][col][i] = row * cols + col + '0';
}
(*pad)[row][col][numChars - 1] = 0;
}
}
}
}
return result;
}
int main(void)
{
printf("Hello, World!\n");
char (*keypad)[5][3];
if(createKeyPad(5, 5, 3, &keypad))
{
for(size_t row = 0; row < 5; row++)
{
for(size_t col = 0; col < 5; col++)
{
printf("%s ", keypad[row][col]);
}
printf("\n");
}
}
free(keypad);
}
https://godbolt.org/z/6zY4zbGW3
The main problem is that char* string; followed by string[i] = needed; is dereferencing an invalid pointer because string is not pointing to anything valid.
In the code's current style of allocating one block for each level and dividing the block up, the memory for all the strings could be allocated in one big block:
char* sptr = (char*) malloc(rows * cols * (num_chars + 1) * sizeof(char));
(Note: The (char*) typecast is not required. Also the * sizeof(char) is not required since sizeof(char) is 1 by definition, but I put it in there in case the code is changed to use something other than char at a later date.)
Then the string variable in the nested loop can be initialized as follows:
char* string = sptr + (row * cols + col) * (num_chars + 1);
I have been given a school assignment in C to create a program that multiplies matrices. I will list assignment constraints below so people don't respond with questions as to why I am doing things this way.
Constraints from instructor:
Cannot use square brackets anywhere in code (use pointer notation instead)
Matrices A, B, C must be single integer pointer variables (int *A, *B, *C)
Can only use main function and those specified by header
Must compile with "gcc -ansi -Wall -o p2 p2.c"
I have not implemented the matrix multiplication function yet, as the issues I am having relate to either file reading or memory allocation.
The specific problem I am having is when I allocate space to the pointer matrix with either malloc OR calloc (tried both), the program inserts 33 in some places in the output instead of 0. I've tried everything at this point and am convinced my knowledge of pointers is fundamentally flawed.
p2.h (given by instructor)
#include <stdio.h>
#include <stdlib.h>
/* This function reads m, n, and p from the datafile.
It then allocates the correct amount of memory required for matrices
A, B, and C.
Then matrices A and B are filled from the datafile.
The values for m, n, and p are passed by reference, and are
thus filled in by this function
PARAMETERS in order are:
int ** matrix A
int ** matrix B
int ** matrix C
int * m The number of rows in matrix A
int * n The number of columns in matrix A and
The number of rows in matrix B
int * p The number of columns in matrix B
char * The name of the datafile, from the command line
*/
void read_matrices(int **, int **, int **, int *, int *, int *, char *);
/* This function prints a matrix. Rows and columns should be preserved.
PARAMETERS in order are:
int * The matrix to print
int The number of rows in the matrix
int The number of columns in the matrix
*/
void print_matrix(int *, int, int);
/* The two matrices A and B are multiplied, and matrix C contains the
result.
PARAMETERS in order are:
int * Matrix A
int * Matrix B
int * Matrix C
int m
int n
int p
*/
void mult_matrices(int *, int *, int *, int, int, int);
p2.c (sorry for the mess a lot of debugging went on)
#include <stdio.h>
#include <stdlib.h>
#include "./p2.h"
/* constants for testing */
#define cM 3
#define cN 2
#define cP 5
int main(int argc, char **argv) {
if (argc < 2) {
printf("Must include an argument.\n");
exit(1);
}
char *path = *(argv + 1);
int *m = (int *) malloc(sizeof(int));
int *n = (int *) malloc(sizeof(int));
int *p = (int *) malloc(sizeof(int));
*m = cM; *n = cN; *p = cP;
int i,j; /* loop counters */
/* allocate space for 2d pointer arrays */
int **A = NULL;
A = (int **) malloc(*m * sizeof(int *));
for (i = 0; i < *m; i++) {
*(A+i) = (int *) malloc(*n * sizeof(int));
}
int **B = NULL;
B = (int **) malloc(*n * sizeof(int *));
for (i = 0; i < *n; i++) {
*(B+i) = (int *) malloc(*p * sizeof(int));
}
int **C = NULL;
C = (int **) malloc(*m * sizeof(int *));
for (i = 0; i < *m; i++) {
*(C+i) = (int *) malloc(*p * sizeof(int));
}
/* write data to A */
for (i = 0; i < *m; i++) {
for (j = 0; j < *n; j++) {
*(*(A+i)+j) = 0;
}
}
/* testing a */
for (i = 0; i < *m; i++) {
for (j = 0; j < *n; j++) {
if (*(*(A+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
/* write data to B */
for (i = 0; i < *n; i++) {
for (j = 0; j < *p; j++) {
*(*(B+i)+j) = 0;
}
}
/* testing b */
for (i = 0; i < *n; i++) {
for (j = 0; j < *p; j++) {
if (*(*(B+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
/* write data to C */
for (i = 0; i < *m; i++) {
for (j = 0; j < *p; j++) {
*(*(C+i)+j) = 0;
}
}
/* testing c */
for (i = 0; i < *m; i++) {
for (j = 0; j < *p; j++) {
if (*(*(C+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
printf("Matrix A: \n");
print_matrix(*A, *m, *n);
printf("Matrix B: \n");
print_matrix(*B, *n, *p);
printf("Matrix C: \n");
print_matrix(*C, *m, *p);
return 0;
}
void read_matrices(int **A, int **B, int **C, int *m, int *n, int *p, char *path) {
FILE *fptr;
fptr = fopen(path, "r");
if (fptr == NULL) {
printf("Cannot open file: ./p2 [filename].txt\n");
exit(1);
}
/* get first 3 numbers from file, set m,n,p */
*m = fgetc(fptr);
fgetc(fptr);
*n = fgetc(fptr);
fgetc(fptr);
*p = fgetc(fptr);
fgetc(fptr);
/* read first matrix */
/* 1) calculate matrix size m x n
* 2) loop through malloc'ed matrix
* 3) each loop, insert char in loc
* 4) if next char NOT 10/32, add nextchar*10 to value in loc
*/
char cur;
while ( (cur = fgetc(fptr)) != EOF ) {
if (cur == 10 || cur == 32) {
/* do nothing :) */
} else {
*m = cur;
*n = cur;
*p = cur;
break;
}
}
printf("m: %c\n", *m);
printf("n: %c\n", *n);
printf("p: %c\n", *p);
printf("next: %c\n", fgetc(fptr));
fclose(fptr);
}
void print_matrix(int *X, int rows, int cols) {
int r, c;
int k = 0;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
printf("\t%d", *(X+k));
k++;
}
printf("\n");
}
}
void mult_matrices(int *A, int *B, int *C, int m, int n, int p) {
}
d2.txt (data file)
3
2
4
1 2
3 4
5 6
7 8 9 10
11 12 13 14
Output: ./p2 d2.txt
[0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]
Matrix A:
0 0
0 0
0 0
Matrix B:
0 0 0 0 0
0 33 0 0 0
Matrix C:
0 0 0 0 0
0 33 0 0 0
0 0 0 0 33
If you notice, I have some debug code that checks whether or not the current item in the array is 0. It seems to indicate that they are all 0, making me think it is a printing problem, but I am even more lost on what would be causing that. The ascii code for 33 is an exclamation point, but I am not sure what relevance it has.
Based on the function signatures you're supposed to use, you need to implement your 2D arrays as 1D with the correct index math. This will result in all memory being laid out contiguously, which is not at all guaranteed with the way you're allocating memory now (two calls to malloc for each matrix). For example:
#include <stdio.h>
#include <stdlib.h>
void print_matrix(int* A, int rows, int cols)
{
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
// If you want to treat A as a 2D matrix, this is where we have to do a bit of
// fancy index math to give you what double bracket notation [][] does for you
// r * cols gives you the index of the right row
// + c give you the column offset in that row
// add that offset to A then dereference
printf("%d\t", *(A + (r * cols + c)));
}
printf("\n");
}
}
int main(void)
{
// matrix A is supposed to be m by n
int* A;
// read these from file, or where ever they're supposed to come from
int m = 2;
int n = 10;
// Allocate the memory in one chunk. This makes the memory all contiguous, just the
// same as if you had done A[m][n]. However, the double call malloc for each int**
// matrix probably will not give you contiguous memory for the entire matrix. Each
// call to malloc is independent.
A = malloc(m * n * sizeof(int)); // or sizeof(*A) would be even better
if (A == NULL)
{
// handle error
}
// We can initialize values for A at this point, still not needing to care about
// rows or columns
for (int i=0; i<m*n; i++)
{
*(A + i) = i; // using i for a better visual when we print
}
print_matrix(A, m, n);
free(A);
return 0;
}
Demo
You are ovecomplicating simple things. Use pointers to arrays and allocate 2D array.
Use the correct type of your size variables.
Try to avoid side effects. Use parameters and function return values.
//this function is for the test purposes only
int writefile(const char *fn)
{
FILE *fo = fopen(fn, "w");
fprintf(fo,
"3\n"
"2\n"
"4\n"
"1 2\n"
"3 4\n"
"5 6\n"
"7 8 9 10\n"
"11 12 13 14\n");
fclose(fo);
}
void *allocIntMatrix(size_t rows, size_t cols)
{
int (*m)[cols] = malloc(rows * sizeof(*m));
return m;
}
void printIntMatrix(size_t rows, size_t cols, int (*m)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
printf("[%5d] ", m[row][col]);
}
printf("\n");
}
}
int readData(FILE *fi, size_t rows, size_t cols, int (*m)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
fscanf(fi, "%d", &m[row][col]);
}
}
return 0;
}
int main(int argc, char **argv)
{
size_t n,m,p;
writefile("a.aaa");
FILE *fi = fopen("a.aaa", "r");
fscanf(fi, "%zu", &m);
fscanf(fi, "%zu", &n);
fscanf(fi, "%zu", &p);
printf("n = %zu, m = %zu, p = %zu\n", n, m, p);
int (*A)[n] = allocIntMatrix(m, n);
int (*B)[p] = allocIntMatrix(n, p);
readData(fi, m, n, A);
readData(fi, n, p, B);
fclose(fi);
printIntMatrix(m, n, A);
printf("\n");
printIntMatrix(n, p, B);
return 0;
}
https://godbolt.org/z/adoEx1r4f
You need to check for errors (file, memory etc). I skipped it for the sake of simplicity of the example.
I'm trying to use calloc on array inside a function but it doesn't work. When trying to debug I found that inside the function the pointer points to the allocated memory but when leaving the function it points to NULL again. Tried all kinds of variations but can't seem to find a solution.
This is my code:
int main(int argc, char *argv[]) {
int *rows = NULL, *solvedRows = NULL;
int **board = NULL, **solvedBoard = NULL;
allocateMemory(dim, &(*rows), &(*board));
allocateMemory(dim, &(*solvedRows), &(*solvedBoard));
}
void allocateMemory(int dim, int** rows, int*** board) {
rows = calloc(dim*dim,sizeof(int));
board = calloc(dim, sizeof(int*));
if (rows == NULL || board == NULL) {
printf("Error: calloc has failed\n");
exit(1);
}
}
Need help to understand what's wrong and how to fix it.
EDIT
I tried:
*rows = calloc(dim*dim,sizeof(int));
*board = calloc(dim, sizeof(int*));
Still have same problem.
Also tried:
allocateMemory(dim, &rows, &board);
for line 4 and (5 the same) and in doesn't compile with the error:
"error: passing argument 2 of 'allocateMemory' from incompatible pointer type [-Werror=incompatible-pointer-types]
allocateMemory(dim, &rows, &board);
^"
error: passing argument 3 of 'allocateMemory' from incompatible pointer type [-Werror=incompatible-pointer-types]
allocateMemory(dim, &rows, &board);
^
EDIT
For anyone who encounters this problem and checks this page, this last try is in fact correct, as Michael answered below. The errors are for a mistake in the corresponding header file, and were fixed when fixing the header file.
Let's focus on your rows variable:
rows is a pointer, which is a variable holding a memory address.
Now you want alocateMemory to write into rows the address of a block of memory, to hold your data. Easy enough:
size_d dim = 10;
int* rows = 0;
rows = calloc(1, sizeof(int) * dim);
However, if you put this code into a function like
void allocateMemory(size_t dim, int* rows) {
rows = calloc(1, sizeof(int) * dim);
}
Now if you call this function like
int* actualRows = 0;
allocateMemory(3, actualRows);
The value of actualRows (namely 0) will be copied into a new variable rows which you manipulate in allocateMemory. When you write into rows, its value changes, but when allocateMemory is left, rows will be destroyed. Never will actualRows be altered.
What you want is that allocateMemory sets the value of actualRows o a memory address. To do this, you have to provide allocateMemory with the address of actualRows like
allocateMemory(3, &actualRows);
&atualRows is the memory address of actualRows and its type is int** (pointer to a pointer to int).
Now you have to adapt the signature of allocateMemory appropriately:
void allocateMemory(size_t dim, int** rows) {
rows = calloc(1, sizeof(int) * dim);
}
And, since rows now is a pointer and you want to change its target, you need to dereference it before assigning it:
*rows = calloc(1, sizeof(int) * dim);
Yielding all in all:
void allocateMemory(size_t dim, int** rows) {
*rows = calloc(1, sizeof(int) * dim);
}
...
int* actualRows = 0;
allocateMemory(3, &actualRows);
...
For your board, its the same in principle. Try
#include <stdio.h>
#include <stdlib.h>
void allocateMemory(int dim, int** rows, int*** board) {
*rows = calloc(dim * dim,sizeof(int));
*board = calloc(dim, dim * sizeof(int*));
if (rows == NULL || board == NULL) {
printf("Error: calloc has failed\n");
}
for(size_t i = 0; i < dim; ++i) {
(*board)[i] = calloc(1, sizeof(int) * dim);
if ((*board)[i] == NULL) {
printf("Error: calloc has failed\n");
}
}
}
int main(int argc, char *argv[]) {
size_t dim = 10;
int *rows = NULL;
int **board = NULL;
allocateMemory(dim, &rows, &board);
rows[0] = 10;
rows[1] = 11;
for(size_t i = 0; i < dim; ++i) {
printf("%i ", rows[i]);
}
printf("\n\n\n");
board[0][0] = 11;
board[9][0] = 99;
board[9][9] = 101;
for(size_t i = 0; i < dim; ++i) {
for(size_t k = 0; k < dim; ++k) {
printf("%i ", board[i][k]);
}
printf("\n");
}
printf("\n");
for(size_t i = 0; i < dim; ++i) free(board[i]);
free(board);
free(rows);
}
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'm trying to free the malloc that is generated with a not fixed number of arrays.
char ** get_moves(){
// some code
char **moves = malloc(sizeof(char *) * k); // 'k', could ranges between 1~9
if (!moves){
return NULL;
}
for(int i = 0; i < k; i++){
moves[i] = malloc(82);
if (!moves[i]) {
free (moves);
return NULL;
}
// more code
return moves;
}
int main(){
//some code
char **res = get_moves(some_input);
//more code
for (int i = 0; i < (sizeof(res)/sizeof(res[0)); i ++){
free(res[i]);
}
free(res);
}
In one of the inputs to get_move, res should have 2 arrays but the sizeof(res)/sizeof(res[0) gives me just 1.
How is the proper way to handle this?
The only way is to keep track of the element count of the array, if you don't want to pass it to every function when passing the array, you can combine both pieces of information in a struct, like here
#include <stdlib.h>
struct ArrayOfStrings
{
int count;
char **data;
};
struct ArrayOfStrings get_moves()
{
struct ArrayOfStrings result;
char **moves;
// some code
result.count = 0;
result.data = malloc(sizeof(char *) * k); // 'k', could ranges between 1~9
if (result.data == NULL)
return result;
result.count = k;
moves = result.data;
for (int i = 0; i < k; i++)
{
moves[i] = malloc(82);
if (moves[i] == NULL)
{
/* also free succesfully allocated ones */
for (int j = i - 1 ; j >= 0 ; --j)
free(moves[j]);
free(moves);
}
result.count = 0;
result.data = NULL;
return result;
}
// more code
return result;
}
int main(){
//some code
struct ArrayOfStrings res = get_moves(some_input);
//more code
for (int i = 0; i < res.count ; i ++)
free(res.data[i]);
free(res.data);
return 0; // you should return from main.
}
sizeof is not for the length of an object's content but for the size of a data type, it is computed at compile time.
So in your case
sizeof(res) / sizeof(res[0]) == sizeof(char **) / sizeof(char *) == 1
since sizeof(char **) == sizeof(char *) it's just the size of a pointer.
sizeof(res)
Returns the sizeof(double-pointer);
So if you intend to get the number of pointers stored then you might not get this by doing what you are doing.
You need to do something like
for(i=0;i<k;i++) /* As I see you are allocating k no of pointer Keep track of it*/
free(res[i]);
free(res);
res is in fact not an array of arrays of char type. Instead it is a pointer to pointer to char type. sizeof(res) will give you the size of char**. You need to keep track of the number of allocations.
Since the maximum number of arrays to allocate is small (9), you can simplify your code by allocating the maximum number. Fill the unused elements with NULL:
#define MAX_K 9
char **moves = malloc(sizeof(char *) * MAX_K);
for(int i = 0; i < k; i++){
...
}
for(int i = k; i < MAX_K; i++){
moves[i] = NULL;
}
To deallocate, just ignore the NULL pointers:
for (int i = 0; i < MAX_K; i ++){
if (res[i])
free(res[i]);
}
free(res);