0

私は本当にこれに困惑しています。

ユーザーのキーボード入力から名、姓、YOB(生年月日)を取得する簡単なプログラムをcで作成しました(年齢を整数に解析することはまだできていません)。最大文字数を設定しました入力用。

しかし、フィールドの最大文字数を 50 以上にすると、戻り値は常に空白になります。

これはコード (60 行) で、出力は次のとおりです。問題の原因となっている関数は、最後から 2 番目の関数 getInputNoNewLine です。

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

void flushBuffer();
char *getInput(int max, char message[]);
char *getInputNoNewline(int max, char message[]);

typedef struct Person {
    char *firstName;
    char *lastName;
    int yob;
} Person;

void flushBuffer() {
    int ch; 
    while ((ch = getchar()) != '\n' && ch != EOF); //flush the input buffer
}

char *getInput(int max, char message[]) {
    char in[max];
    char *input;
    do {
        printf("%s", message);
        input = fgets(in, max + 2, stdin); //max + 2 accounts for characters fgets adds
        if (input[strlen(input)-1] != '\n') {
            printf("Sorry, maximum %d characters\n", (max));
            flushBuffer();
        }
    } while (input[(strlen(input)-1)] != '\n');
    printf("input: %s", input); //debug
    return input;
}

//OFFENDING FUNCTION
char *getInputNoNewline(int max, char message[]) {
    char *input;
    input = getInput(max, message);
    printf("raw input : %s", input); //debug
    if (input[strlen(input) - 1] == '\n') { //strip new line character
        input[strlen(input) - 1] = '\0';
    }
    printf("final input: '%s'\n", input); //debug
    return input;
}

int main(int argc, char *argv[]) {
    int numPlayers = 3;
    char *intIn;
    int i = 0;
    Person players[numPlayers]; 
    printf("Hello world Game\n");
    for (i = 0; i < numPlayers; ++i) {
        players[i].firstName = getInputNoNewline(50, "What is your first name: "); //50 will return blank
        players[i].lastName = getInputNoNewline(49, "What is your last name: "); //49 will return fine
        intIn = getInputNoNewline(4, "What is your YOB: "); //TODO: convert number to integer with sscanf
        printf("-----------------------------------\n");
    }
    printf("Finished\n");
    return 0;
}

これは出力です。jim の最初の入力が fgets から受信されていることがわかりますが、戻り値は空白です (生の入力 : )。姓フィールドの場合のように、最大​​値を 50 から 49 に減らすと、問題なく動作します。何かご意見は?

Hello world Game
What is your first name: jim
input: jim
raw input : final input: ''
What is your last name: smith
input: smith
raw input : smith
final input: 'smith'
What is your YOB: 1984
input: 1984
raw input : 1984
final input: '1984'
-----------------------------------
4

3 に答える 3

3

コードに未定義の動作があります。
ローカルに割り当てられた配列へのポインターを返しています。

char *getInput(int max, char message[])
{
    char in[max];
    ....
    ....
    return input;
}

in関数のローカルな配列であり、関数のスコープまでのみ有効であることが保証されています{``}。関数の範囲を超えてこの配列の内容にアクセスできるようにするには、次の方法で配列の寿命を延ばす必要があります。

  • mallocまたはを使用して動的に割り当てる
  • それstaticまたはグローバルにする

使用する場合mallocは、呼び出して使用後に配列の割り当てを解除することを忘れないでください。そうしないfreeと、メモリ リークが発生します。

于 2013-02-11T04:07:45.923 に答える
2

50 文字の長さに割り当てin、52 文字を読み取れるようにすると、問題が発生します。使いたい

static char* in;
if(in!=NULL) free(in);
in = (char*)malloc(max + 2);

これは、Alok が提起したポイント (関数が戻るとローカル スコープ ポインターが定義されないことについて) と、関数がbuffer に文字fgetsを書き込むことを許可するという事実の両方に対処します。max+2in

于 2013-02-11T04:08:27.813 に答える
0

多くのメモリ管理の問題が発生しています。fgets 呼び出しは、割り当てられたメモリよりも 2 バイト大きい長さを渡しているため、クラッシュを求めています。また、 fgets から返された char * を返し、割り当てられたメモリのように扱っています。

fgets から返されたバッファをコピーして、 Person 構造体に格納する必要があります。

本当に、基本的な C メモリの割り当てと破棄を確認する必要があると思います。

于 2013-02-11T04:13:07.870 に答える