【问题标题】:strtol gives segfault when strtok returns NULL当 strtok 返回 NULL 时,strtol 给出段错误
【发布时间】:2012-10-19 15:39:09
【问题描述】:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char* getfield(char* line, int num) {
        const char* tok;
        for (tok = strtok(line, ",");
                tok && *tok;
                tok = strtok(NULL, ",\n"))
        {
            if (!--num)
                return tok;
        }
        return NULL;
    }

    int main()
    {
        FILE* stream = fopen("b.csv", "r");
        char line[1024];
        char *pstr;int num;
         const char* value;

        while (fgets(line, 1024, stream))
        {
            char* tmp = strdup(line);
        //printf("Field 3 would be %s\n", getfield(tmp, 3));    
        value=getfield(tmp, 3);
        num =strtol(value,&pstr,10);
        printf("Field 3 would be %d\n", num);
        // NOTE strtok clobbers tmp
            free(tmp);
        }
    }

/* b.csv

301,36,15
302,88,75

//我的输出

Field 3 would be 15
Field 3 would be 75

*/

问题是:/* b.csv

301,36,15
 302,88,
 ,,,34

如果表被破坏如上“strtok”返回NULL,所以“strtol”给出“segfault”..如何解决它?

这里的主要问题是如果 2nd 不存在,它会将 3rd 视为第二个并给出段错误!例如,在 b.csv “,,,34” 的第三行中是否存在表示第三个值,但它的行为就像“34”是第一个值,第二个和第三个分别是 NULL !!

【问题讨论】:

  • 那么,您是在 NULL 指针上调用 strtol 吗?那永远行不通。检查NULL之前使用该指针调用任何东西。

标签: c csv file-handling strtok strtol


【解决方案1】:

为什么不能只检查从getfield(tmp, 3); 获得的value 是否为NULL,而不是在返回NULL 时调用strtol?另一种解决方法是在getfield 中创建一个static char* not_found = ""; 并返回地址而不是NULL,然后strtol 将不会出现段错误。

更新

因为我发现strtok 在这种情况下真的很无助,所以我尝试编写与strchr 相同的代码:

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

    char* getfield(char* line, int num) {
        char* tok = line;
        char* result;
        if (line)
        {
            do
            {
                if (!--num)
                {
                    tok = strchr(line, ',');
                    if (tok == NULL)
                    {
                        tok = &line[strlen(line)];
                    }
                    size_t fieldlen = tok - line;
                    if (fieldlen)
                    {
                        result = (char*)malloc(fieldlen+1);
                        result[fieldlen] = '\0';
                        strncpy(result, line, fieldlen);
                        return result;
                    }
                    else
                    {
                        break;
                    }
                }
                tok = strchr(line, ',');
                line = tok + 1;
            } while (tok);
        }
        result = (char*)malloc(2);
        strcpy(result, "0");
        return result;
    }

    int main()
    {
        FILE* stream = fopen("b.csv", "r");
        char line[1024];
        char *pstr;int num;
        char* value;

        while (fgets(line, 1024, stream))
        {
            char* tmp = strdup(line);
            //printf("Field 3 would be %s\n", getfield(tmp, 3));    
            value=getfield(tmp, 3);
            num =strtol(value,&pstr,10);
            free(value);
            printf("Field 3 would be %d\n", num);
            // NOTE strtok clobbers tmp
            free(tmp);
        }
    }

这适用于输入文件:

    10,,30
    10,

如果没有找到,代码返回0,你可以改变它,结果是动态分配的。我希望这会有所帮助,对我的教训是 - 解析字符串时避免使用 C:D

【讨论】:

  • 看看,如果缺少任何值,我想将其分配为值“0”,因此如果缺少第二个,它不会将第三个作为第二个......所以我想从调用中分配它功能,但无法正确添加...您知道如何解决它吗?
  • 根据POSIX规范,strtok将两个连续的分隔符视为一个,所以,解决起来有点棘手:你可以使用strchr在线实际查找并提取@之间的东西987654337@,要么使用 C++ 中的正则表达式功能,要么使用 C++ 字符串,...
  • 这就是为什么我问我是否可以从“getfield”本身分配值“0”(作为字符串)。所以它可以返回它并且两个连续分隔符的问题可以得到解决。而且我不能像我想的那样只在 C 中使用 C++。
  • 使用strchr 的解决方案更新了答案,希望可以工作。
  • 值=getfield(tmp, 1); value2=getfield(tmp, 2);value3=getfield(tmp, 3);这意味着我建议您将当前的 3 x getfield() (涉及 malloc + assorted strchr 等) 3 x strtol() 3 x free() 与大量数据进行比较 非常耗时!当我想在每次“重新加载”时将它分配到其他地方时它给了我错误......你能帮助提高这段代码的性能吗??
【解决方案2】:

而不是

num =strtol(value,&pstr,10);
printf("Field 3 would be %d\n", num);

使用这个:

if (value!=NULL) {         
    num =strtol(value,&pstr,10);
    printf("Field 3 would be %d\n", num);
}
else {
    printf("Field 3 does not exist\n");
}

你必须在调用strtol()函数之前检查value!= NULL

编辑修复getfield()函数的返回

在for循环中尝试更改:(我没有测试它但它可以解决你的问题)

 tok = strtok(NULL, ",\n")

通过

 tok = strtok(tok+strlen(tok)+1, ",\n")

【讨论】:

  • 用这种方法无法解决第二个问题...例如。文件中的值在这里是“10,,30” 它把 30 作为第二个值,将 NULL 作为第三个值......所以这里没有段错误,但值最终是错误的
  • 在这种情况下,您必须更新 getfield() 以返回正确的值
猜你喜欢
  • 2023-03-24
  • 1970-01-01
  • 2020-11-18
  • 2020-11-22
  • 1970-01-01
  • 2016-05-21
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多