I have a very long program, which I am trying to shorten. I frequently write 2d file arrays, but I repeat this process dozens of times throughout my program, so I am trying to write as a function to reduce mistakes on my part and make the code shorter and easier to read.
I am modifying an example I got from Allocate memory 2d array in function C but doing so with a FILE array instead.
I can already allocate 2D file arrays easily in main, but again, I want to do this as a function:
#include <stdio.h>
#include <stdlib.h>
void allocate_mem(FILE**** arr, const int n, const int m) {
arr = malloc(n*m*sizeof(FILE));
for(int i=0; i<n; i++) {
arr[i] = malloc(m*sizeof(FILE));
for (unsigned int j = 0; j < m; j++) {
char filename[64];
sprintf(filename,"tmp_%d_%d.txt",i,j);
*arr[i][j] = fopen(filename,"w");
fprintf(*arr[i][j],"blah %d %d\n",i,j);
}
}
}
void deallocate_mem(FILE**** arr, const int n, const int m){
for (int i = 0; i < n; i++) {
for (unsigned int j = 0; j < m; j++) {
fclose(*arr[i][j]);
}
free((*arr)[i]);
}
free(*arr);
}
int main() {
FILE ***array;
allocate_mem(&array,5,3);
deallocate_mem(&array,5,3);
return 0;
}
I have tried almost every conceivable (to me, anyway) way of doing this, but I keep getting mistakes like this from valgrind:
==16192== HEAP SUMMARY:
==16192== in use at exit: 4,440 bytes in 3 blocks
==16192== total heap usage: 3 allocs, 0 frees, 4,440 bytes allocated
==16192==
==16192== Searching for pointers to 3 not-freed blocks
==16192== Checked 70,808 bytes
==16192==
==16192== 552 bytes in 1 blocks are still reachable in loss record 1 of 3
==16192== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16192== by 0x4EA711C: __fopen_internal (iofopen.c:69)
==16192== by 0x40080C: allocate_mem (create_file_array.c:11)
==16192== by 0x400951: main (create_file_array.c:29)
==16192==
==16192== 648 bytes in 1 blocks are still reachable in loss record 2 of 3
==16192== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16192== by 0x4007AC: allocate_mem (create_file_array.c:7)
==16192== by 0x400951: main (create_file_array.c:29)
==16192==
==16192== 3,240 bytes in 1 blocks are still reachable in loss record 3 of 3
==16192== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16192== by 0x400761: allocate_mem (create_file_array.c:5)
==16192== by 0x400951: main (create_file_array.c:29)
==16192==
==16192== LEAK SUMMARY:
==16192== definitely lost: 0 bytes in 0 blocks
==16192== indirectly lost: 0 bytes in 0 blocks
==16192== possibly lost: 0 bytes in 0 blocks
==16192== still reachable: 4,440 bytes in 3 blocks
==16192== suppressed: 0 bytes in 0 blocks
==16192==
==16192== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==16192==
==16192== 1 errors in context 1 of 2:
==16192== Invalid write of size 8
==16192== at 0x40080D: allocate_mem (create_file_array.c:11)
==16192== by 0x400951: main (create_file_array.c:29)
==16192== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==16192==
==16192==
==16192== 1 errors in context 2 of 2:
==16192== Use of uninitialised value of size 8
==16192== at 0x40080D: allocate_mem (create_file_array.c:11)
==16192== by 0x400951: main (create_file_array.c:29)
==16192== Uninitialised value was created by a heap allocation
==16192== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16192== by 0x4007AC: allocate_mem (create_file_array.c:7)
==16192== by 0x400951: main (create_file_array.c:29)
==16192==
==16192== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
create_file_array.c
How can I get allocate_mem and deallocate_mem to work?
You should forget you ever heard about three stars or four stars. C programming uses an inverse system compared with hotels: the more stars, the worse quality of the code.
You don't even want a pointer-to-pointer-to... You want a 2D array.
That being said, note that this isn't all that trivial, since the type you want to have an array of is
FILE*
. Most would-be veteran programmers will fail and suggest some nonsense with multiple for loops and multiple malloc calls, to launch a full-scaled attack on the poor innocent heap.Instead of that, start with main(). To save your sanity, you would probably want your main to look something like this:
In which case the
allocate_mem
function needs to return a pointer to an allocated array. The C syntax for declaring array pointers is completely awful, so you'll need to create a typedef to save your sanity. It is also bad practice to typedef away pointers, so preferably typedef an array type which you want to point at:Where
file_arr_t*
will be a pointer to an array of 3x5 FILE pointers. Phew.Then you can write your functions as:
EDIT
If you truly need to dimensions to be completely dynamical in run-time, I'm afraid you are stuck with one case of icky syntax or another, because then you can't use a typedef. You'd end up with something unreadable like this:
In that case I would recommend to just go with
void*
instead: