2

形式で時間を表す char 配列を指定して計算を実行するプログラムに取り組んでいますHH:MM:SS。個々の時間単位を解析する必要があります。これは、時間だけに焦点を当てた、私のコードの短縮バージョンです。

unsigned long parseTime(const char *time)
{
    int base = 10;                    //base 10
    long hours = 60;                  //defaults to something out of range
    char localTime[BUFSIZ]            //declares a local array
    strncpy(localTime, time, BUFSIZ); //copies parameter array to local
    errno = 0;                        //sets errno to 0

    char *par;                        //pointer
    par = strchr(localTime, ':');     //parses to the nearest ':'
    localTime[par - localTime] = '\0';  //sets the ':' to null character

    hours = strtol(localTime, &par, base); //updates hours to parsed numbers in the char array
    printf("errno is: %d\n", errno);       //checks errno
    errno = 0;                             //resets errno to 0
    par++;                                 //moves pointer past the null character
}

問題は、入力が無効な場合 (たとえばaa:13:13)、に更新されstrtol()ていないために明らかにエラーを検出しないため、エラー処理を行うことができないことです。私は何を間違えていますか?errno1

4

4 に答える 4

1

他の人が説明したように、変換を実行できない場合strtolは更新されない場合があります。errnoC 標準は、変換された値が整数に収まらない場合errnorに設定されることのみを文書化しています。ERANGElong

あなたのコードには他の問題があります:

  • で文字列をコピーするのstrncpyは正しくありません: ソース文字列が より長い場合BUFSIZlocalTimenull で終了しません。strncpy目的に適合することはほとんどなく、よく理解されていない関数である を避けてください。
  • この場合、 to をクリアする必要はありません:'\0'最初strtolの数字以外の文字で停止します。localTime[par - localTime] = '\0';複雑な書き方です*par = '\0';

はるかに単純なバージョンは次のとおりです。

long parseTime(const char *time) {
    char *par;
    long hours;

    if (!isdigit((unsigned char)*time) {
        /* invalid format */
        return -1;
    }
    errno = 0;
    hours = strtol(time, &par, 10);
    if (errno != 0) {
        /* overflow */
        return -2;
    }
    /* you may want to check that hour is within a decent range... */
    if (*par != ':') {
        /* invalid format */
        return -3;
    }
    par++;
    /* now you can parse further fields... */
    return hours;
}

戻り値の型を に変更したlongので、無効な形式を簡単にチェックでき、負の戻り値からどのエラーが発生したかを判断することもできます。

さらに単純な代替手段として、次を使用しますsscanf

long parseTime(const char *time) {
    unsigned int hours, minutes, seconds;
    char c;

    if (sscanf(time, "%u:%u:%u%c", &hours, &minutes, &seconds, &c) != 3) {
        /* invalid format */
        return -1;
    }
    if (hours > 1000 || minutes > 59 || seconds > 59) {
        /* invalid values */
        return -2;
    }
    return hours * 3600L + minutes * 60 + seconds;
}

1: 1: 1このアプローチでは、またはなどの誤った文字列を受け入れます12:00000002:1。手で文字列を解析することは、最も簡潔で効率的な解決策のようです。

于 2016-02-07T23:22:41.747 に答える
0

ステートメントの後hours = strtol(localTime, &par, base);、最初に errno の値を保存する必要があります。printf()このステートメントの後に、それに応じて設定されたステートメントを呼び出すためですerrno

printf("errno is: %d\n", errno); 

したがって、このステートメントでは、"errno" はprintf()not forのエラー表示を示しstrtol()ます ... そのためには、ライブラリ関数を呼び出す前に "errno" を保存します。これは、ほとんどのライブラリ関数が "errno" と対話するためです。正しい使い方は次のとおりです。

hours = strtol(localTime, &par, base);
int saved_error = errno;       // Saving the error...
printf("errno is: %d\n", saved_error);

今すぐチェックしてください。確かに正しい出力が得られます...そして、これerrnoを意味のある文字列に変換してエラーを表すもう1つのことは、strerror()関数を次のように使用します。

printf("Error is: %s\n", strerror(saved_error)); 
于 2016-03-29T19:07:49.143 に答える