Почему нельзя получить доступ к первому строковому элементу, если ограничение считывается с помощью scanf() в c

int main(){
    char str[10][50],temp[50];
    int lim,i,j;
    printf("Enter lim: ");
    scanf("%d",&lim);
    for(i=0;i<lim;++i){
        printf("Enter string[%d]: ",i+1);
        gets(str[i]);
    }

Здесь str[0](Enter string[1]:) не может быть прочитан. Чтение начинается с «Введите строку [2]:» (строка [1]).

Но если вместо lim в цикл передать целое число, как показано ниже, программа выполняется корректно. Что может быть причиной этого сценария?

int main(){
    char str[10][50],temp[50];
    int lim,i,j;
    for(i=0;i<5;++i){
        printf("Enter string: ");
        gets(str[i]);

    }

person stackphish    schedule 15.06.2018    source источник
comment
scanf оставил новую строку во входном потоке. Итак, первый gets просто читает эту новую строку. На SO есть несколько дубликатов этого   -  person 4386427    schedule 15.06.2018
comment
Никогда, никогда, никогда не используйте gets. Он настолько небезопасен и подвержен переполнению буфера, что был полностью удален из библиотеки C в C11. Если ваш профессор предлагает использовать gets, бегите, не ходите и найдите нового профессора — этот человек не знает, о чем говорит.   -  person David C. Rankin    schedule 15.06.2018


Ответы (2)


Ваш scanf() для числа оставил новую строку во входном потоке, который будет передавать первый gets().

Обратитесь за помощью сюда:
http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html
Как читать/разбирать ввод в C? Часто задаваемые вопросы

Кроме того, вы больше не хотите использовать gets().
Почему функция gets настолько опасна, что ее нельзя использовать?

person Yunnosch    schedule 15.06.2018
comment
С удовольствием, подумайте о том, чтобы принять это. stackoverflow.com/help/someone-answers Как вы можете прочитать там, вы не обязаны, но это предназначено обратная связь за ответ, который помог вам лично больше всего. - person Yunnosch; 15.06.2018
comment
Не говоря уже о том, что это также помогает удалить вопрос из очереди без ответа, чтобы он не повторялся постоянно. - person David C. Rankin; 15.06.2018
comment
Формальной ссылки нет, это категория Без ответа с главной страницы. Если вопрос остается без ответа, он остается активным в этой очереди, группе, беспорядке — называйте это как угодно. - person David C. Rankin; 15.06.2018
comment
@DavidC.Rankin Понятно. И об этом я знал. Спасибо. - person Yunnosch; 15.06.2018

Во-первых, не используйте gets() вместо этого используйте fgets(). Со страницы руководства gets()

Никогда не используйте get(). Поскольку невозможно сказать, не зная заранее данных, сколько символов будет считано функцией gets(), и поскольку функция gets() будет продолжать хранить символы после конца буфера, ее использование крайне опасно. Он использовался для взлома компьютерной безопасности. Вместо этого используйте fgets().

Во-вторых, stdin буферизуется строкой, когда вы используете scanf() как scanf("%d",&lim); и нажимаете ENTER, символ новой строки \n остается в потоке stdin, что приводит к тому, что gets() не читает str[0].

Например,

for(i=0;i<lim;++i){

       printf("Enter string[%d]:\n ",i);    

       fgets(str[i],sizeof(str[i]),stdin);

}

Также обратите внимание, что когда вы используете fgets(), в конце будет сохранено \n в буфере. Если вы не хотите \n в конце str[index], вы должны удалить его.

Также не забудьте проверить возвращаемое значение fgets().

Например,

char *ptr = NULL;

ptr=fgets(str[i],sizeof(str[i]),stdin);

 if( ptr != NULL && str[strlen(str[i])-1] == '\n'){

         str[strlen(str[i])-1] = '\0'; /* replace \n with \0 */

}

person Achal    schedule 15.06.2018
comment
scanf() не буферизируется строкой, stdin и ввод терминала буферизуются строкой. Кроме того, gets() действительно читает str[0]: он делает его пустой строкой именно потому, что в stdin есть отложенная новая строка. Предлагаемое вами изменение не устраняет проблему, ожидающая новая строка должна быть прочитана вручную, чтобы fgets() мог прочитать дальнейший ввод от пользователя. - person chqrlie; 15.06.2018
comment
Возможно, также стоит объяснить, где заканчивается '\n' при использовании fgets и как вы можете решить, как его удалить. - person David C. Rankin; 15.06.2018
comment
Придирайтесь, но вы действительно должны проверить, что длина не равна нулю, прежде чем проверять length-1 (если строка пуста - по какой-либо причине вы вызываете неопределенное поведение). Лучше size_t len = strlen (str); if (len && str[len-1] == '\n') {...} - person David C. Rankin; 15.06.2018
comment
Да, настоящий Давид. - person Achal; 15.06.2018
comment
Ничего страшного, стоит отметить, что я был виновен в этом не раз :) - person David C. Rankin; 15.06.2018
comment
Или я могу предложить OP проверить возвращаемое значение fgets(), как я показал ptr!= NULL. - person Achal; 15.06.2018
comment
Давайте продолжим обсуждение в чате. - person Achal; 15.06.2018