-1

我有一个很长的程序,我正在努力缩短它。我经常编写 2d 文件数组,但我在整个程序中重复了数十次这个过程,所以我试图将其编写为一个函数来减少我的错误并使代码更短且更易于阅读。

我正在修改我从函数 C 中的分配内存 2d 数组中获得的示例,但使用 FILE 数组来代替。

我已经可以轻松地在 main 中分配 2D 文件数组,但是我想再次将其作为一个函数来执行:

#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;
}

我已经尝试了几乎所有可以想象的(无论如何对我来说)这样做的方式,但我不断从 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

如何让 allocate_mem 和 deallocate_mem 工作?

4

2 回答 2

2

你应该忘记你曾经听说过三颗星或四颗星。与酒店相比,C 编程使用逆向系统:星数越多,代码质量越差。

你甚至不想要一个指向指针的指针……你想要一个二维数组。

话虽如此,请注意这并不是那么微不足道,因为您想要的数组类型是FILE*. 大多数想成为资深程序员的人都会失败,并建议使用多个 for 循环和多个 malloc 调用进行一些废话,以对可怜的无辜堆发起全面攻击。

取而代之的是,从 main() 开始。为了保持理智,您可能希望您的 main 看起来像这样:

int main (void) 
{
  file_arr_t* array;    // pointer to a 2D array
  array = allocate_mem(5,3);
  deallocate_mem(array);
  return 0;
}

在这种情况下,allocate_mem函数需要返回一个指向已分配数组的指针。用于声明数组指针的 C 语法非常糟糕,因此您需要创建一个 typedef 来保存您的理智。typedef 远离指针也是不好的做法,因此最好 typedef 一个要指向的数组类型:

typedef FILE* file_arr_t[3][5];   // type is an array of 3x5 FILE*

wherefile_arr_t*将是一个指向 3x5 文件指针数组的指针。呸。

然后你可以把你的函数写成:

file_arr_t* allocate_mem (size_t x, size_t y)
{
  file_arr_t* array = malloc(sizeof(FILE*[x][y]));

  (*array)[i][j] = ... // do things with the pointer to array

  return array;
}

void deallocate_mem(file_arr_t* array)
{
  free(array);
}

编辑

如果您确实需要在运行时将维度完全动态化,恐怕您会遇到一种或另一种 icky 语法的情况,因为那样您就不能使用 typedef。你最终会得到这样的不可读的东西:

// turning messy, avoid writing code like this.
void allocate_mem (size_t x, size_t y, FILE* (**arr_ptr)[x][y])
{
  *arr_ptr = malloc(sizeof(FILE*[x][y]));
  (**arr_ptr)[i][j] = something;
}

int main (void)
{
  FILE* (*array)[5][3];
  allocate_mem(5, 3, &array);
}

在这种情况下,我建议只使用void*

void* allocate_mem (size_t x, size_t y)
{
  // omit inner-most dimension on purpose to get clearer access syntax later
  FILE* (*array)[y] = malloc(sizeof(FILE*[x][y]));

  // now this pointer can be used with intuitive syntax:
  array[i][j] = something;
  ...

  return array;
}

int main (void)
{
  FILE* (*array)[5][3];
  array = allocate_mem(5, 3);
}
于 2015-06-08T15:22:29.220 回答
0

第一个问题...

void allocate_mem(FILE**** arr, const int n, const int m) {
    arr = malloc(n*m*sizeof(FILE));      // probably not what you want!
    for(int i=0; i<n; i++) {
       arr[i] = malloc(m*sizeof(FILE));  //overwrites initial value of arr when i==0!

i == 0您返回的初始指针arr = malloc(n*m*sizeof(FILE));被覆盖并且您泄漏(失去可见性)此内存时。这必须解决。

我最初的想法是……哇!您正在使用 ( FILE**** arr) 指向指向指针的指针的指针。你真的需要简化这一点。

于 2015-06-08T15:14:46.420 回答