首页 文章

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

提问于
浏览
1

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

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

== 2286 ==错误:AddressSanitizer:地址0x60200000eeb8上的堆缓冲区溢出,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 回答

  • 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

    首先,根据定义, 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); };
    

    (顺便说一句,总是检查malloc的结果;它可能会失败) .

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

    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 ,您可以使用单个 structflexible array member结尾(并保留其分配和使用的大小) .

  • 2
    • 第一个malloc是错的..甚至'll you get when you derefer cmd by *cmd, before it'甚至分配了什么?

    • 它也使用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;
            }
        }
    }
    

相关问题