如何为C中的字符串数组动态分配内存?

时间:2016-04-14 04:53:45

标签: c malloc dynamic-memory-allocation realloc strtok

我在C中阅读了以前关于动态数组的问题但是我无法将答案与我的问题联系起来。

我正在使用fgets从stdin获取命令,删除换行符,然后想要在动态分配的字符串数组中存储由空格分隔的每个命令。然而,我在分配和重新分配内存的正确方法上遇到了很多麻烦。我正在使用clang进行编译并继续获取分段错误11.然后我使用-fsanitize=address并继续获取:

  

== 2286 ==错误:AddressSanitizer:地址上的堆缓冲区溢出       0x60200000eeb8 at pc 0x000108fb6f85 bp 0x7fff56c49560 sp 0x7fff56c49558       写入大小为8的0x60200000eeb8线程T0

这是我的代码:

// Sets a delimiter to split the input
const char *seperator = " ";

char *token = strtok(line, seperator);

char **cmds = (char **) malloc(sizeof(char) * sizeof(*cmds));
// Adds first token to array of delimited commands
cmds[0] = token;

int count = 1;
while (token != NULL) {
    token = strtok(NULL, sep);
    if (token != NULL) {
        cmds = (char **) realloc(cmds, sizeof(char) * (count + 1));
        // Adds next token array of delimited commands
        cmds[count] = token;
        count++;
    }
}

3 个答案:

答案 0 :(得分:2)

你没有分配足够的内存。 cmds是一个指针数组,因此每个元素都是sizeof(char *)个字节,而不是sizeof(char)个字节。

在您想要的初始分配1 char *上,然后在您想要的后续分配count + 1上。

另外,don't cast the return value of malloc,因为它可以隐藏其他问题,并且不会忘记检查失败。

char **cmds = malloc(sizeof(char *) * 1);
if (cmds == NULL) {
    perror("malloc failed");
    exit(1);
}
...
        cmds = realloc(cmds, sizeof(char *) * (count + 1));
        if (cmds == NULL) {
            perror("reallocfailed");
            exit(1);
        }

答案 1 :(得分:2)

首先,根据定义,sizeof(char)始终为1。编码不会使您的代码更具可读性。

但指向char的指针需要sizeof(char*)个字节(取决于机器和ABI,通常为8或4个字节)。如果使用GCC,我至少建议您使用gcc -Wall -Wextra -g编译代码。

最后,我发现你的代码效率低下。你在每个循环中调用realloc。我会维护一个包含分配大小的变量

 int allocsize = 4; // allocated size in number of elements
 char **cmds = malloc(allocsize*sizeof(char*));
 if (!cmds) { perror("malloc"); exit(EXIT_FAILURE); };

(BTW,始终检查 malloc的结果;

为了避免realloc每次,我会以几何方式增加分配的大小,所以在循环内部:

 if (count>=allocsize) {
    int newallocsize = (4*allocsize)/3+10;
    cmds = realloc (cmds, newallocsize*sizeof(char*));
    if (!cmds) { perror("realloc"); exit(EXIT_FAILURE); };
    allocsize = newallocsize;
 }

或者,不是保留三个变量:cmdscountallocsize,您可以使用单个struct结尾flexible array member(并保留其分配和使用的尺寸)。

答案 2 :(得分:2)

  • 第一个malloc是错误的..当你甚至分配cmd之前你用cmd取消cmd时会得到什么?
  • 它也使用sizeof(char),这是错误的..

正确的方式是......

// strtok modifies the string. So use writable string
char line[80] = "Hello my name is anand";
char *token = strtok(line, sep);
int count = 0;
// Alloc array of char* for total number of tokens we have right now
char **cmds = (char **) malloc(sizeof(char*) * (count + 1));

while (token != NULL) 
{
    /**
     * Alloc memory for the actual token to be stored.. 
     * token returned by strtok is just reference to the existing string 
     * in 'line'
     */
    cmds[count] = malloc(sizeof(char) * ((strlen(token) + 1)));
    // Adds tokens to array of delimited commands
    strcpy(cmds[count], token);
    count++;

    token = strtok(NULL, sep);
    if (token != NULL) 
    {
        // resize array of tokens to store an extra token
        char ** newCmds = (char **) realloc(cmds, sizeof(char*) * (count + 1));
        // only if realloc was successful then use it.
        if (newCmds != NULL)
        {
             cmds = newCmds;
        }
    }
}