在C中包含动态char数组的结构

时间:2012-02-01 19:27:35

标签: c

我正在寻找正确的方法来分配和解除分配结构中包含的动态大小的字符数组(事实上是一个“Command”结构数组)。以下是在C中解决此问题的正确方法吗?在我意识到我必须在开始时将所有数组条目都为NULL之前,我遇到了很多问题。如果我不这样做,我得到“指针被释放没有分配”错误。

请注意,我必须释放Command struct数据,因为我在循环中重用它们。

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

#define MAX_NB_ARGS 10

typedef struct {
    char* args[MAX_NB_ARGS];
} Command;

void init_commands(Command commands[2]) {
    int i;
    for (i=0; i<2; ++i) {
        int j;
        for (j=0; j<MAX_NB_ARGS; ++j) {
            // If I don't null these, the free_commands
            // function tries to free unallocated memory
            // and breaks
            commands[i].args[j] = NULL;
        }
        // Constant of 3 here but in reality variable size
        // Idem for the size of the "args" string
        for (j=0; j<3; ++j) {
            commands[i].args[j] = malloc(5*sizeof(char));
            strcpy(commands[i].args[j], "test");
        }
    }
}

void free_commands(Command commands[2]) {
    int i;
    for (i=0; i<2; ++i) {
        int j=0;
        // Do I really clear the second command?
        // Debugger shows every args as nil on
        // on the second iteration.
        while (commands[i].args[j]) {
            free(commands[i].args[j]);
            commands[i].args[j] = NULL;
            ++j;
        }
    }
}

int main () {
    Command commands[2];
    int i=0;
    // Command structs are being reused within the loop
    while ((i++)<2) {
        init_commands(commands);
        puts(commands[1].args[2]); //test print. works.
        free_commands(commands);
    }
    return 0;
}

2 个答案:

答案 0 :(得分:1)

你在free_commands中崩溃的原因是因为函数的参数是一个未初始化的堆栈变量。因此,数组args []包含未初始化的指针值。所以,是的,你需要将它们初始化为NULL以使free_commands正常工作,否则你将使用垃圾指针调用free()。为了避免内存泄漏,您需要为每个malloc()调用free()。

至于你的其他评论,你需要贯穿每个命令的每个参数。但是你的循环结构不正确。不要对内循环使用while循环,你可以将命令0中的参数推进到命令1的参数或者可能在命令数组之外的所有参数(如果每个命令的每个参数都被分配了一个内存块,就会发生这种情况) )。它应该是从0到MAX_NB_ARGS的for循环。使用NULL指针调用free()是安全的,或者如果检测到NULL则可以提前中断内部循环。

另外不要忘记检查malloc()的返回值。

答案 1 :(得分:0)

当我在MacOS X 10.7.2上运行valgrind下的代码时,代码会编译并运行得很干净,而且我认为剩下的唯一内存是系统内存。似乎什么都没有泄露。

这与我对代码的关注一致;我没有看到代码中的泄漏。

如果我在printf()malloc()电话周围添加适当的free()语句,我会得到:

allocating (0,0) <<test>>
allocating (0,1) <<test>>
allocating (0,2) <<test>>
allocating (1,0) <<test>>
allocating (1,1) <<test>>
allocating (1,2) <<test>>
test
freeing (0,0) <<test>>
freeing (0,1) <<test>>
freeing (0,2) <<test>>
freeing (1,0) <<test>>
freeing (1,1) <<test>>
freeing (1,2) <<test>>
allocating (0,0) <<test>>
allocating (0,1) <<test>>
allocating (0,2) <<test>>
allocating (1,0) <<test>>
allocating (1,1) <<test>>
allocating (1,2) <<test>>
test
freeing (0,0) <<test>>
freeing (0,1) <<test>>
freeing (0,2) <<test>>
freeing (1,0) <<test>>
freeing (1,1) <<test>>
freeing (1,2) <<test>>

您的代码很干净。但是要学习如何像这样进行调试打印。

是的,你必须确保在阅读之前初始化你的记忆。您可以通过跟踪哪些条目正在使用中来管理这一点,因为您已经编写了一个有效的指针(可能需要在结构中添加一个额外的成员),或者通过明确标记未使用的条目NULL(所以你也写了这些)。两种技术都有效;必须使用一个或另一个,因为malloc()realloc()返回的新内存(理论上,虽然在实践中不是calloc()返回的新内存),但是未正确初始化为null。

(为什么calloc()和理论?好吧,从理论上讲,空指针不一定都是零字节,但calloc()将内存设置为所有字节为零。但是,我没有遇到过一台机器其中一个NULL指针并非所有字节都为零 - 并且很多代码会在这样的机器上遇到很多问题。所以,在实践中,calloc()会返回空的内存,但理论上,可能有一台机器在哪里不这样做。)