0

この関数のタスクはかなり簡単です。char* の配列、ファイルへのポインター、および最大ワード サイズを指定すると、ファイルを読み取り、各ワードを 1 つずつ char* 配列にコピーします。\nファイルには 1 行に 1 つの単語があるため、単語間の区切りとして使用するのが理にかなっています。そのことを念頭に置いて、コードは非常に簡単に解釈できるはずです。

void loadDictionary(char* strDictionary[], FILE* filePointer, int nMaxLetters)
{
    int nNameCount= 0, nCursor = 0;
    char* strCurrent;
    char cCurrent;

    //allocate space for a word
    strCurrent = malloc(nMaxLetters * sizeof(char));

    while ((cCurrent = fgetc(filePointer)) != EOF) {

        if(cCurrent != '\n')
        {
            strCurrent[nCursor] = cCurrent;
            nCursor++;

        } else { //then we've reached the end of the line (word)

            //add null termination to string
            strCurrent[nCursor] = '\0'; //SEG FAULT

            //copy string to dictionary
            memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1);

            //increment count
            nNameCount++;

            //reset the cursor
            nCursor = 0;
        }
    }
}

このコードは、 を呼び出す行でセグメンテーション違反を生成しますstrCurrent[nCursor] = '\0';。一見すると、この操作は、私が呼び出す他のブロックの操作と変わらないように見えるため、理由はわかりませんstrCurrent[nCursor] = cCurrent;。strCurrent は、必要なすべての文字を格納するのに十分なスペースを割り当てているはずです。だから、私はやや途方に暮れています。これを理解するのを手伝ってください、みんな。

注:このタスクを実行するfgets代わりに、使用する方がおそらく簡単だと思います。fgetc私はそれに切り替えるかもしれません。しかし、理解できないエラーに遭遇したので、理解するまで放置したくありません。

編集:

おそらく不適切に割り当てられているmemcpyために、操作でエラーが発生する可能性があると誰かが指摘しました。が割り当てられるブロックは次strDictionaryのとおりです。おそらく私は間違いを犯しました:mainstrDictionary

int main(int argc, char* argv[])
{
    char** strDictionary;
    FILE* filePointer;
    int nResults = 0, nLines = 0, nNumLines, nMaxChars, i;

    filePointer = fopen("dictionary.txt", "r");

    //obtain the number of lines and the maximum word size of the dictionary
    countLines(filePointer, &nNumLines, &nMaxChars);

    //allocate memory for strDictionary
    strDictionary = malloc(nNumLines * nMaxChars * sizeof(char));
    printf("%d words in dictionary. Longest word is %d letters\n",
            nNumLines, nMaxChars);
    //Output here correctly prints: 1000 and 21

    //reset the file pointer (not sure if this is a necessary step, but oh well)
    filePointer = fopen("dictionary.txt", "r");

    //load dictionary into memory
    loadDictionary(strDictionary, filePointer, nMaxChars);
    for (i=0; i<10; i++)
        printf("%dth element of dictionary: %s\n", i, strDictionary[i]);

    return 0;
}

編集2:

OK、関数を大幅に簡素化するfgets()代わりに使用することにしました。の正しい操作fgetc()だと思ったことも実行しました。ただし、まだセグフォルトが発生しています。更新されたコードは次のとおりです。malloc()strDictionary

void loadDictionary(char* strDictionary[], FILE* filePointer, int nMaxLetters)
{
    printf("Call to loadDictionary. nMaxLetters = %d\n", nMaxLetters);
    int nWordCount= 0, nCursor = 0;
    char* strCurrent;
    char cCurrent;

    strCurrent = malloc(nMaxLetters); //allocate space for a word


    while (fgets(strCurrent, nMaxLetters, filePointer) != NULL)
    {
        memcpy(strDictionary[nWordCount], strCurrent, strlen(strCurrent)+1);
        nWordCount++;
    }
}

int main(int argc, char* argv[])
{
    char** strDictionary;
    FILE* filePointer;
    int nResults = 0, nLines = 0, nNumLines, nMaxChars, i;
    filePointer = fopen("dictionary.txt", "r");

    //count the lines in the file (works fine)
    countLines(filePointer, &nNumLines, &nMaxChars);

    //allocate space for the dictionary
    strDictionary = malloc(nNumLines * sizeof(char*));
    for (i = 0; i<nLines; i++)
        strDictionary[i] = malloc(nMaxChars * sizeof(char));
    printf("%d words in dictionary. Longest word is %d letters\n",
            nNumLines, nMaxChars);

    //load dictionary into array
    filePointer = fopen("dictionary.txt", "r");
    loadDictionary(strDictionary, filePointer, nMaxChars);
    for (i=0; i<10; i++)
        printf("%dth element of dictionary: %s\n", i, strDictionary[i]);

    return 0;
}
4

1 に答える 1

1

ここ:

char cCurrent;
...
while ((cCurrent = fgetc(filePointer)) != EOF) {

fgetc()タイプの の値を に切り捨てていintますchar。これにより、while 条件が正しく認識されない可能性がありEOFます。cCurrentでなければなりませんint

ここ:

//allocate space for a word
strCurrent = malloc(nMaxLetters * sizeof(char));

nMaxLetters文字列 NUL ターミネータを表す 1 つの余分な文字を考慮する必要があります。それは説明されていますか?

ところで、sizeof(char)常に 1 です。

さて、このパラメータ宣言:

char* strDictionary[]

これと同等です:

char** strDictionary

または、IOW、へのポインターへのポインターchar。これは、C では配列がパラメーターとして渡されることはなく、最初の要素へのポインターのみが渡されるためです。これは、何かが配列であることを示唆する括弧を使用した欺瞞的な構文にもかかわらずです。

この行:

memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1);

nNameCounta への 'th ポインタを取りchar、それが指す場所に文字データを書き込みます。

しかし、呼び出し元の関数は、少なくともnMaxLettersファイル内の行と同じ数の文字列バッファー (長さ) を割り当てますか? この配列をに渡す前に、これらのバッファーへのポインターを使用して、char へのポインターの配列を設定しloadDictionary()ますか? IOW、このコードは呼び出し元が次のようなことをすることを期待しています:

#define nMaxEntries 1000

char* dictionary[nMaxEntries];
int i;
FILE* f;

...

for (i = 0; i < nMaxEntries; i++)
  dictionary[i] = malloc(nMaxLetters);

loadDictionary(dictionary, f, nMaxLetters);

上記のコードでメモリ割り当ての失敗をチェックする必要があります。また、ファイルnMaxEntriesに. を超えて成長してはなりません。loadDictionary()nMaxEntriesnNameCountnMaxEntries

更新された質問に更新...

ここ:

char** strDictionary;
...
strDictionary = malloc(nNumLines * nMaxChars * sizeof(char));

上記の分析で予想さcharれるように、へのポインターの配列を作成していません。 の 2 次元配列を作成しています。そのため、セグメンテーション違反はおそらくこの行では発生しません。loadDictionary()char

 strCurrent[nCursor] = '\0'; //SEG FAULT

しかし、非常に次のものでは、ズームインしてコードの逆アセンブリを見るまで、デバッガーで明らかにならない場合があります。

 //copy string to dictionary
 memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1);

更新 2:

nNumLinesポインターにスペースを割り当てる理由がわかりません。

strDictionary = malloc(nNumLines * sizeof(char*));

しかし、これらのポインターのうち、nNumLinesポインターを初期化nLinesします(nLines最新のコードを正しく読んでいれば、0以外になることはありません):

for (i = 0; i<nLines; i++)
    strDictionary[i] = malloc(nMaxChars * sizeof(char));

トリックは何ですか?打ち間違え?

于 2012-10-10T21:17:11.487 に答える