数组中由strtok解析出的最后一个字符串含有垃圾数据。

3

我有点困惑,主要在这里:

int main() {
    char **symbols = (char **) malloc(3 * sizeof(char *)); // allocate 3 (char *)'s
    for (int i = 0; i < 3; i++)
        symbols[i] = (char *)malloc(3); // allocate string of length 3

}

然后用户在同一行上输入三个以空格分隔的字符串符号:
111 010 101

我将这个缓冲字符串解析成字符串数组,方法如下:
void parseSymbols(char *line, int k, char **symbols) {
    // k == 3
    // Ignore leading spaces
    while (*line != '\0' && is_whitespace(*line))
            line++;

    char *p = strtok(line, " ");
    int cnt = 0;
    symbols[cnt++] = p;
    while (p) {
            p = strtok(NULL, " \n");
            symbols[cnt++] = p;
    }

    // Let's call this FOOBAR
    //for (int i = 0; i < k; i++)
    //        printf("%d. %s\n", i, symbols[i]);

在主函数中,当我打印symbols中的3个字符串时,输出结果如下:

0. '111'
1. '010'
2. ' s'

但是,当我取消parseSymbols中最后两行的注释时,会出现以下情况:
0. '111'
1. '010'
2. '101'

为什么FOOBAR块“修复”了我的字符串数组,更重要的是,我如何让parseSymbols正常工作而不必打印任何东西?symbols[2]是否需要使用'\0'结束?(但是strtok难道不是为我做这个吗?)

2
请在您的问题中包含一个完整且可运行的程序。 - NPE
@NPE 我认为这并不必要。已知模拟行为所需的一切... - junix
在C语言中,不需要对malloc的返回值进行强制类型转换。请确保使用C编译器来编译C代码,而不是C++编译器。 - autistic
1个回答

1
你的第一个问题是将 strtok 的结果指针分配给符号表,从而导致内存泄漏。这是因为你只是复制了下一个标记的开始位置的引用,而没有复制这些行中得到的字符串:symbols[cnt++] = p; 接下来,你应该确保在将结果分配给符号表时不会超过 k。你的代码总是在符号表的最后一个位置写入 NULL。一旦解析了 3 个符号,你就会写入未分配的内存,导致未定义的行为。
我建议先纠正这些问题,然后再尝试。
请注意,strtok 通过在标记的末尾用 '\0' 替换分隔符来修改原始缓冲区,因此无需复制字符串。请还要注意,strtok 跳过连续出现的一个分隔符。因此,你的第一个循环可以替换为检查第一个标记的长度是否 >0(或者换句话说,结果字符串的第一个字节是否为 != '\0')。
请注意,C-Strings始终需要比您想要存储的空间多1个字节。这个额外的字节用于'\0'终止符。在您的示例中,您正在解析3个字节的块,同时每个块只分配3个字节(应该是4):symbols[i] = (char *)malloc(3); // 分配长度为3的字符串

代码不足以确定是否存在内存泄漏,而你所给出的“内存泄漏”解释是错误的。在我看来,你最后的错误是最重要的,为什么这么晚才提到它呢? - autistic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接