2017-12-08 2 views
-3

私はCでAdvent of Codeの問題を解決していましたが、私は理解できないことにヒットしました。私のCは非常に錆びており、私はこれがCコードの素晴らしい例ではないことを知っています。私は、このプログラムを、私を混乱させるような行動を示す最小のセクションまで切り離しました。なぜstrtokは間違った数のトークンを返しますか?

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

int ae_load_file_to_memory(const char *filename, char **result) 
{ 
    int size = 0; 
    FILE *f = fopen(filename, "rb"); 
    if (f == NULL) 
    { 
     *result = NULL; 
     return -1; 
    } 
    fseek(f, 0, SEEK_END); 
    size = ftell(f); 
    fseek(f, 0, SEEK_SET); 
    *result = (char *)malloc(sizeof(char) * (size + 1)); 
    if (size != fread(*result, sizeof(char), size, f)) 
    { 
     free(*result); 
     return -2; 
    } 
    fclose(f); 
    (*result)[size] = 0; 
    return size; 
} 

int main(void) 
{ 
    const char delim = '\n'; 
    int fill_index = 0; 
    char *token = NULL; 
    char *content = NULL; 

    ae_load_file_to_memory("input.txt", &content); 

    token = strtok(content, &delim); 

    while (token != NULL) 
    { 
     fill_index++; 
     token = strtok(NULL, &delim); 
    } 
    printf("Fill index %d\n", fill_index); 
} 

このコードは、ディスクからファイルを読み取り、改行文字を区切り文字として使用してトークンに分割します。トークンの最終printf戻って正しい番号、しかし1044

、私はfill_indexの宣言に移動するmain方法の開始を変更する場合:

int main(void) 
{ 
    int fill_index = 0; 
    const char delim = '\n'; 

...今strtok戻って1050個のトークンを、それは間違っている。これが2つのファイルの唯一の違いです。私はMac OS X Sierraで動作しています。gcc --versionはそのApple LLVM version 9.0.0 (clang-900.0.38)を報告しています。

私はどこかの記憶を踏みにじっていると確信しています。最初のバージョンは偶然にしか動作しません。しかし、私はその宣言を動かすことでそのような違いが生じるのではないかと思っています。誰でも何が起こっているのか説明できますか?

+3

[ 'strtok'](第2引数http://en.cppreference.com/w/c/ string/byte/strtok)は、***ヌル終了**バイト文字列*です。単一の文字へのポインタではありません。 –

+0

すべてのコンパイラの警告が有効になっていることを確認し、それを読んでください。これはまったくまったくコンパイルすべきではありません。 – unwind

+0

@unwind 'gcc -Wall'はきれいにコンパイルされました。 – TarkaDaal

答えて

4

delimを正しく使用していません。 const char delim[] = "\n";(1文字ではないNull終了文字配列)になります。

以前は、誤ったパラメータを渡して未定義の動作を呼び出していました。

標準§7.24.5.8

char *strtok(char * restrict s1,const char * restrict s2); 

から

そして、いくつかの例

static char str[] = "?a???b,,,#c"; 
     char *t; 
     t = strtok(str, "?");   // t points to the token "a" 
     t = strtok(NULL, ",");  // t points to the token "??b" 
     t = strtok(NULL, "#,");  // t points to the token "c" 
     t = strtok(NULL, "?");  // t is a null pointer 
関連する問題