1

私は長い間 C を使っていなかったので、思った以上に忘れていたようです。malloc() を使用して文字列を割り当てようとしているときに、その文字列の古いデータを取得し続けます。これには、要求されたスペースが短い場合の古い、長い長さが含まれます。この状況には、free() されて NULL に設定されている文字列へのポインターが含まれます。これは、私の端末に表示されるサンプルの実行です。

yes, quit, or other            (<-message from program)
oooo                           (<-user input; this will be put to upper case and token'd)

------uIT LENGTH:4             (<-debug message showing length of userInputToken)

preC--tmp:                     (<-contents of tmp variable)

pstC--tmp:OOOO                 (<-contents of temp variable)
bad input                      (<-program response)
yes, quit, or other
yes

------uIT LENGTH:3

preC--tmp:OOOO                 (<-: tmp = malloc(sizeof(char)*(strlen(userInputToken)-1)); )

pstC--tmp:YESO                 (<-: strncpy(tmp,userInputToken,strlen(userInputToken)-1);  )
bad input
yes, quit, or other
yes

------uIT LENGTH:3

preC--tmp:YESO

pstC--tmp:YESO
bad input
yes, quit, or other
quit

------uIT LENGTH:4

preC--tmp:YESO

pstC--tmp:QUIT                 (<-: Successful quit because I only did 4 chars; if 5 were used, this would have failed)

ご覧のとおり、strlen(userInputToken) は正しい長さを取得し、正しい文字数をコピーするために使用されますが、free() または malloc() は気にしていないようです。ここで何が起こっているのかわかりません!これは Python のために C を離れたことに対する罰ですか?

さらに、free() に関係なく tmp 変数をクリアする必要があります。これは、スコープによって制限されているためです。すべてがダウンするコードは次のとおりです。

main.c で:

void run() {
    outputFlagContainer *outputFlags = malloc(sizeof(outputFlagContainer));

    while(true) {
        puts("yes, quit, or other");
        outputFlags = getUserInput(outputFlags);
        if (outputFlags->YES) {
            puts("It was a yes!");
        } else if (outputFlags->QUIT) {
            break;
        } else {
            puts("bad input");
        }
    }

    free(outputFlags);
}

messageParserPieces.h で:

outputFlagContainer *getUserInput(outputFlagContainer *outputFlags) {
    outputFlags = resetOutputFlags(outputFlags);
    char *userInput = NULL;
    char user_input[MAX_INPUT];
    char *userInputToken = NULL;
    char *tmp = NULL;
    char *finalCharacterCheck = NULL;

    // Tokens to search for:
    char QUIT[] = "QUIT";
    char YES[] = "YES";

    userInput = fgets(user_input, MAX_INPUT-1, stdin);
    int i = 0;
    while(userInput[i]) {
        userInput[i] = toupper(userInput[i]);
        i++;
    }

    userInputToken = strtok(userInput, " ");
    if (userInputToken) {
        finalCharacterCheck = strchr(userInputToken, '\n');
        if (finalCharacterCheck) {
            int MEOW = strlen(userInputToken)-1; // DEBUG LINE
            printf("\n------uIT LENGTH:%d\n", MEOW); // DEBUG LINE

            // The problem appears to happen here and under the circumstances that
            // userInput is (for example) 4 characters and then after getUserInput()
            // is called again, userInput is 3 characters long. 
            tmp = malloc(sizeof(char)*(strlen(userInputToken)-1));
            if (tmp == NULL) {
                exit(1);
            }

            printf("\npreC--tmp:%s\n", tmp); // This shows that the malloc DOES NOT use the given length.

            strncpy(tmp,userInputToken,strlen(userInputToken)-1);

            printf("\npstC--tmp:%s\n", tmp); // Copies in the correct number of characters.

            userInputToken = tmp;
            free(tmp);
            tmp = NULL;
        }
    }

    while (userInputToken != NULL) { // NULL = NO (more) tokens.
        if (0 == strcmp(userInputToken, YES)) {
            outputFlags->YES = true;
        } else if (0 == strcmp(userInputToken, QUIT)) {
            outputFlags->QUIT = true;
        }

        userInputToken = strtok(NULL, " ");
        if (userInputToken) {
            finalCharacterCheck = strchr(userInputToken, '\n');
            if (finalCharacterCheck) {
                tmp = malloc(sizeof(char)*(strlen(userInputToken)-1));
                if (tmp == NULL) {
                    exit(1);
                }
                strncpy(tmp,userInputToken,strlen(userInputToken)-1);
                userInputToken = tmp;
                free(tmp);
                tmp = NULL;
            }
        }
    }
    return outputFlags;
}

これは何らかの明らかなエラーだと思いますが、今夜は約 2 時間グーグルで検索してみました。malloc() チュートリアルが表示されないこれを検索する方法が思いつきません。すでにいくつか見てきました。

どんな洞察でも大歓迎です!

4

4 に答える 4

2
tmp = malloc(sizeof(char)*(strlen(userInputToken)-1));
if (tmp == NULL) {
    exit(1);
}

printf("\npreC--tmp:%s\n", tmp); // This shows that the malloc DOES NOT use the given length.

strncpy(tmp,userInputToken,strlen(userInputToken)-1);
printf("\npstC--tmp:%s\n", tmp); // Copies in the correct number of characters.

tmpこのスニペットは、何かで初期化されることを期待していることを示しています。本当じゃない。割り当てた後、メモリを初期化する必要があります。それはあなたがすることですstrncpy

%s文字列を保持するのに十分なバイトを割り当てていないため、プレーンフォーマット指定子で表示できないため、問題もあります。バイトを割り当てstrlen(userInputToken)-1、同じ番号をコピーしています。これは、ヌル文字の余地がないことを意味し、strncpyその結果、文字列を終了しません。常にもう1バイト追加する必要があります。それまでにヌル文字がコピーされない場合は、strncpy自分で設定する必要があります。

size_t length = strlen(userInputToken)-1;
tmp = malloc(length + 1);
strncpy(tmp, userInputToken, length);
tmp[length] = 0;

したがって、明確にするために、3つの問題があります。

  1. 初期化する前に、新しく割り当てられた「文字列」を表示します。
  2. 文字列を保持するのに十分なメモリを割り当てていません
  3. 文字列を終了しません(またstrncpy、許可されたバイト数内で文字列ターミネータが検出されなかったため、終了しません)。

私はあなたのループで何か他のものを見つけましたwhile (userInputToken != NULL)...あなたはいつもループの始めに使用して文字列比較をuserInputTokenしますが、ループの内側(そしてループの上の部分でも)あなたはこれをします:

userInputToken = tmp;
free(tmp);

つまりuserInputTokenダングリングポインタです。解放されたメモリを指しているため、使用しないでください。あなたはあなたのアプローチを再考し、それがもはや必要とされなくなるまでそれが生きることを許さなければならないでしょう。

于 2013-01-16T04:19:47.283 に答える
1

おそらくcallocを使用する必要があります。また、このような初期化されていないメモリを使用しないでください。Mallocはメモリをチャンクに割り当てます。チャンクを解放すると、再利用される場合があります。正確なサイズは取得できません。mallocでメモリをmsetするまで、そのバイトの値がどうなるかは保証されません。あなたが知っているのは、少なくともあなたが要求したサイズと同じ大きさの使用するメモリのチャンクがあるということだけです。したがって、この例では、メモリチャンクに書き込む前に、メモリチャンクの古い内容を出力しています。

于 2013-01-16T04:19:03.357 に答える
1

この行で割り当てられた長さの検証は正しくありません:

printf("\npreC--tmp:%s\n", tmp); // This shows that the malloc DOES NOT use the given length.

malloc要求されたバイト数が割り当てられますが、割り当てられたメモリは初期化されません。したがって、で終わるはずの文字列として印刷しよ'\0'うとすると、メモリ内で見つかるまですべての文字を印刷しようとし'\0'ます。終了文字は、同じメモリ ブロックからのものではない可能性があります。の存在'\0'は非決定論的です。

于 2013-01-16T04:23:39.110 に答える
0

これが役立つことを願っています

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

#define MAX_INPUT 128
#define true 1
#define false 0

typedef struct _outputFlagContainer{

int  YES, QUIT;

}outputFlagContainer;


void run();
outputFlagContainer *getUserInput(outputFlagContainer *outputFlags);
outputFlagContainer *resetOutputFlags(outputFlagContainer *outputFlags);

int main(int argc, char *argv[]){

run();      
return 0;
}    

void run() {

    outputFlagContainer *outputFlags = malloc(sizeof(outputFlagContainer));

    while(true) {       

        puts("yes, quit, or other");

        outputFlags = getUserInput(outputFlags);

        if (outputFlags->YES) 
        {
            puts("It was a yes!");
        }
        else if (outputFlags->QUIT) 
        {
            break;
        }
        else
        {
            puts("bad input");
        }

    }

    free(outputFlags);
}

outputFlagContainer *resetOutputFlags(outputFlagContainer *outputFlags) {

    if(outputFlags!= NULL){

        outputFlags->YES = false;
        outputFlags->QUIT = false;      

    }

    return outputFlags;

}

outputFlagContainer *getUserInput(outputFlagContainer *outputFlags) {

    int len;
    char user_input[MAX_INPUT]={0};     // Zero Initialization

    char *userInput = NULL;
    char *userInputToken = NULL;
    char *tmp = NULL;
    char *finalCharacterCheck = NULL;

    // Tokens to search for:        // Immutable Strings
    char *QUIT = "QUIT";
    char *YES = "YES";

    // Reset The Structure
    outputFlags = resetOutputFlags(outputFlags);

    userInput = fgets(user_input, MAX_INPUT, stdin);        // it copies one less than MAX_INPUT 

    // Converting to Upper Case
    int i = 0;
    while(userInput[i]) {
        userInput[i] = toupper(userInput[i]);
        i++;
    }

    userInputToken = strtok(userInput, " ");

    if (userInputToken) {

        finalCharacterCheck = strchr(userInputToken, '\n');

        if (finalCharacterCheck) {

            len = strlen(userInputToken);

            printf("\n------uIT LENGTH:%d\n", len); // DEBUG LINE

            tmp = malloc(sizeof(char)*(len+1));
            if (tmp == NULL)
                exit(1);

            strncpy(tmp,userInputToken,len);
            tmp[len]='\0';

            printf("\npstC--tmp:%s\n", tmp); // Copies in the correct number of characters.

            strcpy(user_input,tmp);
            userInputToken = user_input;
            free(tmp);
            tmp = NULL;
        }
    }

    while (userInputToken != NULL) { // NULL = NO (more) tokens.

        if (0 == strcmp(userInputToken, YES)) {

            outputFlags->YES = true;

        } 
        else if (0 == strcmp(userInputToken, QUIT)) {

            outputFlags->QUIT = true;

        }

        userInputToken = strtok(NULL, " ");

        if (userInputToken) {

            finalCharacterCheck = strchr(userInputToken, '\n');

            if (finalCharacterCheck) {

                len = strlen(userInputToken);        
                tmp = malloc(sizeof(char)*(len+1));
                if (tmp == NULL) {
                    exit(1);
                }

                strncpy(tmp,userInputToken,len);
                tmp[len]='\0';

                strcpy(user_input,tmp);
                userInputToken = user_input;                                                
                free(tmp);
                tmp = NULL;
            }
        }
    }

    return outputFlags;
}
于 2013-01-16T12:41:56.497 に答える