1
#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」を返します。これを解決するにはどうすればよいですか。

ここでの主な問題は、2番目が存在しない場合、3番目を2番目として扱い、セグメンテーション違反を発生させることです。たとえば、b.csvの3行目にある ",,, 34"は、3番目の値が存在することを意味しますが、 "34"は1番目の値であり、2番目と3番目はそれぞれNULLであるように動作します。

4

2 に答える 2

3

valueから取得したgetfield(tmp, 3);をチェックして、 が返された場合はNULL呼び出さないのはなぜですか? 回避するもう 1 つの方法は、inを作成し、代わりにアドレスを返すことです。そうすれば、segfault は発生しません。strtolNULLstatic char* not_found = "";getfieldNULLstrtol

アップデート

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

于 2012-10-30T10:09:58.513 に答える
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");
}

関数value!= NULLを呼び出す前に確認する必要がありますstrtol()

getfield()関数の戻りを修正するための編集

forループで変更してみてください:(私はそれをテストしませんでしたが、あなたの問題を解決することができました)

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

 tok = strtok(tok+strlen(tok)+1, ",\n")
于 2012-10-30T10:09:57.113 に答える