C -Strtol会在Strtok返回null时给出Segfault


#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 %sn", getfield(tmp, 3));    
        value=getfield(tmp, 3);
        num =strtol(value,&pstr,10);
        printf("Field 3 would be %dn", 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"。如何解决它?

在这里,主要问题是,如果不存在第二个,它将第三次将其视为第二个,并给出segfault!例如,在B.CSV的第三行中,34"是否存在3个值,但其行为类似于" 34"是第一个值,第2个值分别为NULL!

为什么您不能仅检查getfield(tmp, 3);value,如果返回NULL,并且如果返回NULL,则不能拨打strtol?解决的另一种方法是在getfield中制作static char* not_found = "";并返回地址而不是NULL,然后strtol不会segfault。

update

由于我发现在这种情况下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] = '';
                        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 %sn", getfield(tmp, 3));    
            value=getfield(tmp, 3);
            num =strtol(value,&pstr,10);
            free(value);
            printf("Field 3 would be %dn", num);
            // NOTE strtok clobbers tmp
            free(tmp);
        }
    }

这在输入文件上工作:

    10,,30
    10,

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

而不是

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

使用此:

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

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

编辑修复getfield()功能的返回

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

 tok = strtok(NULL, ",n")

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

最新更新