2016-11-09 3 views
1

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

typedef struct { 
    char name[50]; 
    char p_id[11]; 
    char cel[11]; 
    int by; 
    int id; 
} Person; 

Теперь, есть еще одна структура, которая стоит для списка контактов:

typedef struct { 
    Person * people; 
} lContacts; 

я пытался включить данные человека к ней, и добавьте этого человека в список контактов. Человек добавляется нормально, поэтому я не буду размещать код здесь, но есть что-то не так происходит, когда я прочитал строку:

void include(lContacts * myContacts) 
{ 

    Person p; 

    scanf("%s", p.name); 
    scanf("%d", &p.by); //birth year 
    scanf("%s", p.p_id); 
    printf("TEST P_ID: %s\n\n", p.p_id); 
    scanf("%s", p.cel); 
    printf("TEST P_ID AGAIN: %s\n\n", p.p_id); 

    myContacts->people[index]=p; //don't worry about the index, there is a piece of code I'm omitting to make it easier to read, just assume it is right. 
    } 
} 

Обратите внимание, что у меня есть тест печати там, потому что, когда я перечислил мой контактов, контакт p_id сам был связан с cel, поэтому я напечатал весь код, пока не обнаружил, что ошибка была там.

Вот входной пример:

Name 
1991 
11111111111 
<console prints| TEST P_ID: 11111111111> 
22222222222 
<console prints| TEST P_ID AGAIN: 1111111111122222222222> 

однако, если я печатаю p.cel, он правильно напечатанных

<console prints 22222222222> 

Любые идеи? Может быть, я должен использовать '&' при сканировании строк? (Я читал об этом и о том, как я понял, нет необходимости ... это так?)

+2

Строки в C состоят из массива 'char', завершенного символом NUL, иначе' '\ 0''. Поскольку массив 'p_id' равен 11 байтам, вы можете хранить 10 цифр плюс NUL. Другими словами, у вас есть ошибка переполнения буфера. – user3386109

+1

ie - изменить pid на char [12] (если 11 - максимальная длина pid) – pm100

ответ

1

Это на самом деле очень минутная ошибка. В основном вы испытываете Переполнение буфера в строке p.p_id.

Когда вы вводите значение для p.p_id как 11111111111 (11 раз 1), вы должны понимать, что фактическая емкость для p_id строки объявлена ​​как только 11, который должен включать символ NULL в конце.

Если вы назначили 11111111111 на номер p_id, то для символа NULL в этой строке не останется места, поэтому в конце этого не будет.

Когда вы вводите значение для следующей строки-члена структуры, то же самое происходит и там.

Теперь, когда вы пытаетесь распечатать значение p.p_id, значение будет напечатано до тех пор, пока в строке не появится '\0' (символ NULL). Но здесь их нет, поэтому следующая строка начнет печатать! (Буфер или строка p_id переполнения)

Это происходит из-за выравнивания элементов, выполненного в структурах C. Следующая строка будет сохранена в последовательной ячейке памяти, поэтому печать будет продолжена. (Если был третий последовательный член строки, то из-за переполнения буфера во второй строке он тоже будет печататься!)

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

Чтобы избежать использования большого массива для массива символов или использования динамически распределенных строк.

+0

Спасибо вам большое :) –

0

Как указано в @skrtbhtngr, у вас переполнение буфера. Чтобы предотвратить это в будущем, вы должны использовать fgets вместо scanf на неизвестных строковых вводах. Этот пример будет exit(1), если вход поврежден.

int getsafestring(char* s, int maxlen) 
{ 
    if(fgets(s,maxlen,stdin) == NULL) return 1; // read error 
    if(strlen(s) == 0) return 2; // other read error 
    if(s[strlen(s)-1] !='\n') return 3; // buffer overflow error 
    s[strlen(s)-1]=0; // replace newline with null 
    return 0; 
} 

if(Getsafestring(p.name,sizeof(p.name))) exit(1); 
if(scanf("%d", &p.by) != 1)    exit(1); 
if(getsafestring(p.p_id,sizeof(p.p_id))) exit(1); 
if(getsafestring(p.cel,sizeof(p.cel))) exit(1); 
Смежные вопросы