将 char * 转换为 char ** 时出现分段错误

BLS*_*SPR 2 c valgrind

我试图将一个句子 (char *) 拆分为一个单词数组 (char **)。问题是我的函数有时不会返回有效的 char ** 。

char **get_words(char *buffer, char delimiter)
{
    char **words = malloc(sizeof(char *) * 4096);
    for (int i = 0; i < 4096; i++)
        words[i] = malloc(sizeof(char) * 4096);
    int word_count = 0;
    int l = 0;
    for (int i = 0; buffer[i] != '\0' && buffer[i]  != '\n'; i++, l++) {
        if (buffer[i] == delimiter) {
            words[word_count][l] = '\0';
            word_count++;
            l = -1;
        }
        else
            words[word_count][l] = buffer[i];
    }
    words[word_count][l] = '\0';
    return (words);
}
Run Code Online (Sandbox Code Playgroud)

我首先这样使用它:

char *buffer = malloc(sizeof(char) * 50);
buffer = "/login test\n";
char **words = get_words(buffer, ' ');
printf("Words[0] = %s", words[0]);
Run Code Online (Sandbox Code Playgroud)

而且效果很好。

但是,当我以同样的方式这样做时:

char **reply = get_words("502 Command doesn't exist.\n", ' ')
Run Code Online (Sandbox Code Playgroud)

我什至无法在没有分段错误的情况下打印回复[0][0](见下文)。此外,我尝试使用 valgrind 进行调试,但是当我使用它时,程序不会崩溃并且一切正常,所以我找不到问题所在。

printf("Reply[0][0] = %d\n", reply[0][0]);

printf("Reply[0][0] = %c\n", reply[0][0]);

编辑:这是一个可重现的示例。

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>

char **get_words(char *buffer, char delimiter)
{
    printf("buffer = %s\n", buffer);
    char **words = malloc(sizeof(char *) * 100);
    if (words == NULL) {
        printf("Malloc Error\n");
        exit(84);
    }
    for (int i = 0; i < 100; i++) {
        words[i] = malloc(sizeof(char) * 100);
        if (words[i] == NULL) {
            printf("Malloc Error\n");
            exit(84);
        }
    }
    int word_count = 0;
    int l = 0;
    for (int i = 0; buffer[i] != '\0' && buffer[i]  != '\n'; i++, l++) {
        if (buffer[i] == delimiter) {
            words[word_count][l] = '\0';
            word_count++;
            l = -1;
        }
        else
            words[word_count][l] = buffer[i];
    }
    words[word_count][l] = '\0';
    return (words);
}

int main()
{
    char *buffer = malloc(sizeof(char) * 100);
    buffer = "hello world !\n";
    char **words = get_words(buffer, ' ');
    printf("words[0]= %s\n", words[0]);
    free (buffer);
    char **reply = get_words("Second call\n", ' ');
    printf("reply[0] = %s\n", reply[0]);
}
Run Code Online (Sandbox Code Playgroud)

And*_*pov 5

如果您在学习编程时需要帮助,可以尝试静态分析器。这是一个执行代码审查并发现可疑代码片段的程序。静态分析器无法取代队友执行的代码审查。然而,分析器补充了代码审查,并有助于在最早阶段发现许多错误。

\n

让我们为问题所附的代码示例运行在线版本的 PVS-Studio 分析器。第一个有趣且重要的警告是以下警告:V1031malloc未声明。将此函数传入或传出的数据可能会受到影响。

\n

如果没有声明该malloc函数,程序就会以一种奇怪的方式运行。根据C语言,如果函数没有声明,则返回int。但实际上,它是一个指针。您可以在这里了解为什么这很危险。让我们通过添加来解决这个问题#include <stdlib.h>

\n

现在分析器发出另一个警告 \xe2\x80\x94 我们遇到了一个更严重的问题:\n43:1: 注意:V773 “buffer”指针被赋值两次而没有释放内存。内存泄漏是可能的。

\n

问题出在以下代码片段中:

\n
char *buffer = malloc(sizeof(char) * 100);\nbuffer = "hello world !\\n";\n....\nfree (buffer);\n
Run Code Online (Sandbox Code Playgroud)\n

指针值被覆盖。要将字符串复制到缓冲区,程序员应该使用特殊函数,例如strcpy. 让我们解决这个问题。

\n

这是固定代码

\n
#include <unistd.h>\n#include <stdio.h>\n#include <string.h>\n#include <fcntl.h>\n#include <assert.h>\n#include <stdlib.h>\n\nchar **get_words(char *buffer, char delimiter)\n{\n    printf("buffer = %s\\n", buffer);\n    char **words = malloc(sizeof(char *) * 100);\n    if (words == NULL) {\n        printf("Malloc Error\\n");\n        exit(84);\n    }\n    for (int i = 0; i < 100; i++) {\n        words[i] = malloc(sizeof(char) * 100);\n        if (words[i] == NULL) {\n            printf("Malloc Error\\n");\n            exit(84);\n        }\n    }\n    int word_count = 0;\n    int l = 0;\n    for (int i = 0; buffer[i] != \'\\0\' && buffer[i]  != \'\\n\'; i++, l++) {\n        if (buffer[i] == delimiter) {\n            words[word_count][l] = \'\\0\';\n            word_count++;\n            l = -1;\n        }\n        else\n            words[word_count][l] = buffer[i];\n    }\n    words[word_count][l] = \'\\0\';\n    return (words);\n}\n\nint main()\n{\n    char *buffer = malloc(sizeof(char) * 100);\n    if (buffer == NULL)\n        exit(84);\n    strcpy(buffer, "hello world !\\n");\n    char **words = get_words(buffer, \' \');\n    printf("words[0]= %s\\n", words[0]);\n    free (buffer);\n    char **reply = get_words("Second call\\n", \' \');\n    printf("reply[0] = %s\\n", reply[0]);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我不能说这段代码是完美和安全的,但它可以运行。因此,使用静态分析器来查找错误,可以改进您的学习过程。

\n