Ankit Kulshrestha - 1 year ago 60
C Question

# How to use a 2D array as an output parameter in a function in C

I'm writing a program to compute the shortest path between two points on a graph using Floyd's algorithm. I'm required to write to a binary file and then read from it and print the graph. It is here that my problem lies, since my function signature has to be of the form:

`void read_graph(char *filename, int *n, int ***A)`
.

I've written the following:

``````void read_graph(char *filename, int *n, int ***A)
{
FILE *fin;
size_t i;
int x;
int **arr;

fin  = fopen(filename, "rb");
if (fin == 0) {
printf("Error opening file\n");
exit(1);
} else {
fread(&x, sizeof(int), 1, fin);
printf("Read size of matrix %d\n",x);
*n = x;
fseek(fin, sizeof(int)+1, SEEK_SET);
arr = malloc(x*sizeof(int *));
if (arr == NULL) {
printf("Not enough space.\n");
}
for (i = 0; i < x; ++i) {
arr = malloc(x*sizeof(int));
}
for (i = 0;  i < x; ++i) {
fread(arr,sizeof(int), x, fin);
}

//  ***A = **arr;
}
fclose(fin);
free2darray(*A, x);
}
``````

The
`free2darray`
is a utility function to free the memory. My problem is that this function works if I allocate a 2d array before calling this. However, it is required that this function returns a 2d array to
`***A`
and not the other way round. If you could tell me what I'm doing wrong, it would be super helpful. Also criticism on the code style are welcome.

EDIT: Here's how I'm calling the function currently:

``````int **arr;
int x;
size_t i;
arr = malloc(5*sizeof(int*));
if (arr == NULL) {
printf("Cannot allocated memory for array\n");
exit(1);
}
for (i = 0; i < 5; i++) {
arr[i] = malloc(5*sizeof(int));
}
read_graph("test.dat", &x, &arr);
``````

5 is just a test size. The
`test.dat`
was previously written by populating a 5*5 array with random values.

Thanks

Answer Source

You were close. If you read my answer a few minutes ago, you might have noticed that my solution returned a pointer to the dynamic array. Then I saw in the comments to your question that the function prototype was a given, so I have revised my answer.

All you need to do in `main()` is declare a pointer to `int` to store the size of the matrix, and a pointer to a pointer to `int`, which will be passed to the function `read_graph()`. I included a few lines here to display the contents of the new array.

You need to free the allocated memory before exiting. This was one of the main problems that you had in the original code: you were freeing the memory at the end of the call to `read_graph()`. You need to wait until you don't need the array contents any more before you free these allocations.

The other problem that I found was that when you allocated memory for the individual rows of the dynamic array, you forgot to index `arr`, so you `malloc`ed memory and assigned the address to the same pointer x times. This is your loop that repeatedly reassigns memory to `arr` (and is a memory leak because the reference to the previous allocations is lost):

``````for (i = 0; i < x; ++i) {
arr = malloc(x*sizeof(int));
}
``````

The pointer `A` that is passed into the function is used to receive the results of calls to `malloc()`, so that the allocated memory is visible from the calling function. This changes some of your assignments a bit, since you had declared a pointer in your original code for this purpose. I changed the loop that reads values into the array so that it reads in one value at a time... it looks like you were trying to read in x at a time.

You don't really need the `fseek()` since the file pointer is already in position, so I removed that line. I also added a check to make sure that the data file closes properly. I made up a test data file, and everything seems to work. I also changed your `size_t` variables to `int`s. I did this because there were comparisons of `int` values with `size_t` values in the loops that were generating compiler warnings. The code still works fine, but no sense ignoring warnings. I would have changed everything to `size_t`, but you read the size of the matrix from your file, and that is an `int` in your code. If you can change your file format a bit, the size of the matrix could be stored as a `size_t` value. Here is the revised code:

``````#include <stdio.h>
#include <stdlib.h>

void read_graph(char *filename, int *n, int ***A);

int main(void)
{
int x;
int **arr;

read_graph("test.dat", &x, &arr);

for (int i = 0; i < x; i++) {
for (int j = 0; j < x; j++)
printf("%d ", arr[i][j]);
putchar('\n');
}

free2darray(*A, x);

return 0;
}

void read_graph(char *filename, int *n, int ***A)
{
FILE *fin;
int i;
int x;

fin  = fopen(filename, "rb");
if (fin == 0) {
printf("Error opening file\n");
exit(1);
} else {
fread(&x, sizeof(int), 1, fin);
printf("Read size of matrix %d\n",x);
*n = x;

*A = malloc(x*sizeof(int *));
if (*A == NULL) {
printf("Not enough space.\n");
}
for (i = 0; i < x; ++i) {
(*A)[i] = malloc(x*sizeof(int));
}
for (i = 0; i < x; ++i)
for (int j = 0; j < x; ++j)
fread(&(*A)[i][j], sizeof(int), 1, fin);

}

if (fclose(fin) != 0)
fprintf(stderr, "Unable to close file\n");

}
``````

# Edit

I had to create a test file, so I added some code for this purpose that is not shown above. It reads a text file and creates a binary file that the program can use. The resulting binary file is just a sequence of `int`s. I just put the code at the beginning of `main()`, and created a file called "testdat.txt" in the same directory as "a.out". My text file contained a 5 on the first line, and then 25 integers, one on every line:

``````5
1
2
3
4
5
....
``````

And here is the code:

``````/* Code to create a datafile from a text file */

FILE *fpin, *fpout;
char nstr[100];
int num_out;

fpin = fopen("testdat.txt", "r");
fpout = fopen("test.dat", "wb");
while (fgets(nstr, 100, fpin) != NULL) {
num_out = atoi(nstr);
fwrite(&num_out, sizeof(int), 1, fpout);
}
fclose(fpin);
fclose(fpout);
``````
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download