2013-02-11 3 views
0

Я на самом деле туман на этом.C - переменная возврата всегда пустая, если максимальная длина больше 50

Я написал простую программу в c, чтобы получить имя пользователя, фамилию и YOB (год с момента рождения) с ввода пользовательской клавиатуры (я еще не получил парсинг возраста в целое число), и я установил максимальное количество символов для ввода.

Но всякий раз, когда я допускаю, чтобы максимальные символы для поля были равны 50 или более, возвращаемое значение всегда пустое.

Это код (60 строк), вывод которого следует следовать. Функция вызывает проблемы является вторым по последней функции, 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; 
} 

Это выход, как вы можете увидеть первый вход Джима принимаются от 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' 
----------------------------------- 

ответ

2

Поскольку вы назначаете in длиной до 50 символов, и вы позволяете читать 52 символа, у вас возникнут проблемы! Вы хотите использовать

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

Это касается как точки, Alok поднятой (о локальной области видимости указателя не определен, как только функция возвращает), а также тот факт, что ваша функция позволяет fgets писать max+2 символов в буфер in.

+0

Спасибо. Я изменил или изменил строки, где это необходимо, и теперь он работает. 2 вопроса, 1) max + 2 не кажется отличным методом для работы с терминаторами и символами новой строки fgets add, есть ли лучший способ?если я оставлю строки для чтения ** in = (char *) malloc (max) ** и ** input = fgets (in, max, stdin) **, тогда, когда я пытаюсь разрешить 4 символа как максимальную длину , он фактически допустит только 2 символа ... 2) Мне все еще интересно, почему он возвращает только пустое значение, когда max = 50 или больше, если max = 49 или меньше, он возвращает правильное значение. вы знаете, почему? –

+1

Добавление некоторой «защиты» никогда не будет плохой идеей - если вам нужна строка с 15 символами, вам также нужно назначить 16 для учета символа \ 0 ... Если вы ожидаете \ r \ n в конце своего string, вам действительно нужны три символа '\ r \ n \ 0' пространства ... В зависимости от того, как распределены блоки данных, я могу представить, что они выровнены по четырем байтовым границам, поэтому 50 байтов могут« сидеть »на 52 байта ... в этом случае, если вам нужны три дополнительных пространства, вам повезло с 49, но не с 50. Просто угадайте здесь. – Floris

+0

Cheers мат. Спасибо за вашу помощь. –

3

Ваш код имеет Неопределенное поведение.
Вы возвращаете указатель на локально выделенный массив.

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

in является массив местной функции и гарантированно будет жив только до области видимости функции {``}. Для того, чтобы иметь возможность получить доступ к содержимому этого массива выходит за рамки функции вам необходимо увеличить срок службы массива по:

  • расПредеЛения динамически с помощью malloc или
  • делают его static или глобальный

Если вы используете malloc, не забудьте освободить массив после использования, позвонив по номеру free или вы получите утечку памяти.

0

У вас есть проблемы с управлением памятью. Вызов fgets выпрашивает о сбое, так как вы передаете длину на 2 байта больше, чем выделенная память. Вы также возвращаете char *, возвращаемый из fgets, и рассматриваете его как выделенную память.

Вы должны скопировать буфер, возвращенный из fgets, и сохранить его в вашей структуре Person.

Действительно, я думаю, вам следует рассмотреть основные распределения и уничтожения памяти.