I read a text file and store the contents in a 2D array called H inside a function, I need to return this 2D array to main somehow so I can use it there and pass it to other functions. I'm not sure how to get the return to work, maybe using pointers. I made the readTxtFile function into a void function to test if the file reading was working (it does) but I can't do anything with the 2D array outside the function. I have two functions getRows() and getCols() that I didn't show here, I can if needed though.
Heres my code so far:
int main(void){
// int *H;
// H = readTxtFile("H.txt");
readTxtFile("H.txt");
return 0;
}
void readTxtFile(char *filename){
int rows, cols;
FILE *fp = fopen(filename, "r");
if (!fp){
perror("can't open H.txt\n");
//return EXIT_FAILURE;
}
rows = getRows(fp);
cols = getCols(fp);
int (*H)[cols] = malloc(sizeof(int[rows][cols]));
if(!H){
perror("fail malloc\n");
exit(EXIT_FAILURE);
}
for(int r = 0; r < rows; ++r){
for(int c = 0; c < cols; ++c){
if(EOF==fscanf(fp, "%d", &H[r][c])){
fprintf(stderr, "The data is insufficient.\n");
free(H);
exit(EXIT_FAILURE);
}
}
}
fclose(fp);
// printH(rows,cols,H);
// return H;
}
This is what the text file looks like:
1 1 0 1 0 0
0 1 1 0 1 0
1 0 0 0 1 1
0 0 1 1 0 1
2 2 2 2 2 2
Any help would be appreciated
What I would do is defining a structure for the 2D array in term of its:
Note that I would "linearize" the array, i.e. allocate a single block of memory of size Columns * Rows * sizeof(int)
, and given the i and j row and column index, these two indexes can be converted with simple math to a single index in the 1D array (e.g. index = rowIndex * Columns + columnIndex
)
Then, I would just return a pointer to this structure from your ReadTxtFile function:
struct IntArray2D {
int Rows;
int Columns;
int* Elements;
};
/*
* Define a couple of helper functions to allocate
* and free the IntArray2D structure.
*/
struct IntArray2D* IntArray2D_Create(int rows, int columns);
void IntArray2D_Free(struct IntArray2D* array);
/*
* On success, returns a 2D array with data read from file.
* On failure, returns NULL.
* NOTE: callers must call IntArray2D_Free() when done
*/
struct IntArray2D* ReadTxtFile(const char* filename);
EDIT As an alternative, you could define the array structure has having a header block with rows and columns count, immediately followed by the "linearized" 2D array elements, using a "flexible array member":
struct IntArray2D {
int Rows;
int Columns;
int Elements[];
};
You can then define some convenient functions to operate on this custom array structure, e.g.:
struct IntArray2D* IntArray2D_Create(int rows, int columns)
{
/* Check rows and columns parameters are > 0 */
/* ... */
struct IntArray2D *p = malloc(sizeof(struct IntArray2D)
+ rows * columns * sizeof(int));
if (p == NULL) {
return NULL;
}
p->Rows = rows;
p->Columns = columns;
/* May zero out the array elements or not... */
memset(p->Elements, 0, rows * columns * sizeof(int));
return p;
}
void IntArray2D_Free(struct IntArray2D* array)
{
free(array);
}
int IntArray2D_GetElement(struct IntArray2D* array,
int row, int column)
{
/* Check array is not NULL; check row and column
indexes are in valid ranges ... */
int index = row * (array->Columns) + column;
return array->Elements[index];
}
void IntArray2D_SetElement(struct IntArray2D* array,
int row, int column,
int value)
{
/* Check array is not NULL; check row and column
indexes are in valid ranges ... */
int index = row * (array->Columns) + column;
array->Elements[index] = value;
}
Inside your ReadTxtFile
function, instead of calling malloc
, you can call IntArray2D_Create
:
struct IntArray2D* ReadTxtFile(const char* filename)
{
struct IntArray2D* data = NULL;
/* ... */
rows = getRows(fp);
cols = getCols(fp);
data = IntArray2D_Create(rows, cols);
if (data == NULL) {
/* Handle error ... */
return NULL;
}
/* Fill the array ... */
In particular, instead your:
if(EOF==fscanf(fp, "%d", &H[r][c])){
you can do:
/* int valueReadFromFile */
if (EOF == fscanf(fp, "%d", &valueReadFromFile)) {
fprintf(stderr, "The data is insufficient.\n");
}
IntArray2D_SetElement(data, r, c, valueReadFromFile);
And then at the end of the function, you can just have:
return data;
}