Программа C перестает работать со scanf_s

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

Это код:

    int main(void){
    char a[]= ""; 

    printf("Enter word:\n");
    scanf_s("%s", a);

    return 0;
}

Я попытался указать [] размер 20 и использовал% 19s, как предлагалось в другом вопросе, но это тоже не сработало.

Редактировать 1. Изменил char a[]= ""; на char a[20]= {0};, но это не сработало.

Редактировать 2. Добавлен размер (a), и код заработал. Кроме того, я удалил {0}, но не знаю, повлияло ли это.

Окончательный код:

int main(void){

    char a[20]; 

    printf("Enter word:\n");
    scanf_s("%19s", a, sizeof(a));

    return 0;

}

person CBeginner    schedule 03.05.2015    source источник
comment
Вы объявили и пустой массив.... char a[50] = {0}; возможно?   -  person David C. Rankin    schedule 03.05.2015
comment
В любом случае в текущей структуре это явно не сработает. Показать вариант размером 20   -  person Eugene Sh.    schedule 03.05.2015
comment
Что такое scanf_s? Вы имели в виду scanf правильно?   -  person David C. Rankin    schedule 03.05.2015
comment
Связанный вопрос: stackoverflow.com/questions/21434735 /   -  person pmg    schedule 03.05.2015
comment
В M$ есть scanf_s вариант   -  person Eugene Sh.    schedule 03.05.2015
comment
О... это объясняет путаницу, спасибо.   -  person David C. Rankin    schedule 03.05.2015
comment
Добро пожаловать в Stack Overflow. Пожалуйста, скоро прочитайте страницу О. Пожалуйста, не изменяйте свой вопрос, чтобы отображался только правильный код. Либо оставьте ошибочный код в вопросе и примите один из ответов, которые помогли, либо добавьте исправленный код в вопрос, разумно аннотировав две версии. Важно, чтобы те, кто придет после, увидели то, о чем вы спрашивали.   -  person Jonathan Leffler    schedule 03.05.2015
comment
@DavidC.Rankin scanf_s является частью приложения K документа C11, но предоставляется только несколькими разработчиками не MS реализация   -  person Mgetz    schedule 03.05.2015
comment
Хорошо, извини. Я добавил исходный код и редактирование, которое не сработало.   -  person CBeginner    schedule 03.05.2015


Ответы (2)


Диагноз

В коде есть (как минимум) две проблемы:

  1. Вы не предоставили никакого полезного места для хранения строки. (Исходный вопрос определен: char a[] = "";, который, следует отметить, представляет собой массив длины 1, хотя он может содержать только строку длины 0.)

  2. Вы не сказали scanf_s(), насколько велика строка. Требуется аргумент длины после указателя на строку символов.

Определение Microsoft для scanf_s() указывает:

В отличие от scanf и wscanf, scanf_s и wscanf_s требуют указания размера буфера для всех входных параметров типа c, C, s, S или наборов строковых элементов управления, заключенных в []. Размер буфера в символах передается как дополнительный параметр сразу после указателя на буфер или переменную. Например, если вы читаете строку, размер буфера для этой строки передается следующим образом:

char s[10];
scanf_s("%9s", s, _countof(s)); // buffer size is 10, width specification is 9 

Размер буфера включает завершающий нуль. Вы можете использовать поле спецификации ширины, чтобы убедиться, что считываемый токен помещается в буфер. Если поле спецификации ширины не используется, а прочитанная лексема слишком велика для размещения в буфере, в этот буфер ничего не записывается.

Примечание

Параметр размера имеет тип unsigned, а не size_t.

Оператор _countof() является расширением Microsoft. Это примерно эквивалентно sizeof(s) / sizeof(s[0]), что в данном случае совпадает с sizeof(s), поскольку sizeof(char) == 1 по определению.

Обратите внимание, что параметр размера равен unsigned, а не size_t, как можно было бы ожидать. Это одно из различий между реализацией Microsoft TR 24731-1 функции и Приложение K стандарта ISO/IEC 9899:2011. Размер, указанный в стандарте, технически равен rsize_t, но он определяется как size_t с ограниченным диапазоном (отсюда и r):

Тип rsize_t, который является типом size_t.

но сноска (не показана) относится к определению RSIZE_MAX.

См. также Используете ли вы "безопасные" функции TR 24731?

Исправление кода в вопросе

Пример в цитате от Microsoft во многом показывает, как исправить свой код. Тебе нужно:

int main(void)
{
    char a[4096];
    
    printf("Enter word:\n");
    if (scanf_s("%s", a, (unsigned)sizeof(a)) != 1)  // Note cast!
        fprintf(stderr, "scanf_s() failed\n");
    else
        printf("scanf_s() read: <<%s>>\n", a);
    
    return 0;
}

Обратите внимание, что я проверил результат scanf_s(), а не просто предположил, что он работает, и сообщил об ошибках стандартной ошибки.

person Jonathan Leffler    schedule 03.05.2015
comment
1+ как в основном, однако позвольте мне задать вопрос: Вы делаете это как медитативное упражнение... ;-) - person alk; 03.05.2015
comment
Спасибо. Я попробовал пример, и программа заработала. Хотя мне нужно будет изучить его, потому что я не понимаю большую часть этого. - person CBeginner; 03.05.2015
comment
Большинство из них такие же, как у вас. В вызове scanf_s() есть один дополнительный аргумент — это ключевое исправление для вашего кода. Функции *scanf*() возвращают количество успешных преобразований или EOF в случае ошибки. В этом случае это немного педантично, но рекомендуется проверять каждую операцию ввода на успешность. Если вы не сталкивались с fprintf() и stderr, то вы можете думать о fprintf(stderr, …) как о варианте printf(), используемом для написания сообщений об ошибках. fprintf() можно использовать для записи в любой открытый файловый поток, и есть и другие способы записи в stderr. - person Jonathan Leffler; 03.05.2015
comment
@alk: Я делаю это больше для того, чтобы не заниматься всеми остальными вещами, которые я должен делать вместо этого. - person Jonathan Leffler; 03.05.2015
comment
@JonathanLeffler: :-)) ... - так что этот ответ определенно доказывает, что вы человек! Ваше здоровье ... ;-) - person alk; 03.05.2015
comment
Ой. Теперь я понимаю. Спасибо еще раз. - person CBeginner; 03.05.2015

С использованием

char a[]="";

Создает массив, достаточно большой для одного байта. Вы должны выделить достаточно места, например. как это:

char a[20] = {0}; // Can hold a string length 19 + \0 termination

Используя ваш метод, вы получите переполнение, поскольку scanf_s запишет в память больше, чем вы выделили, что приведет к ошибке сегментации.

person Nidhoegger    schedule 03.05.2015
comment
Я просто хотел указать ему правильное направление. При размере 20 он должен работать для строк длиной 19. - person Nidhoegger; 03.05.2015
comment
Массив имеет длину 1 байт (он содержит '\0'); в C нет объектов нулевого размера. - person Jonathan Leffler; 03.05.2015
comment
Я исправил первоначальную мысль о том, что char a[] = ""; определяет массив нулевого размера. Это не так; он задает массив размера 1. В C нет объектов нулевого размера. Однако это не решает всей проблемы. Функция scanf_s() требует длины целевого массива символов в качестве явного дополнительного аргумента функции, появляющегося сразу после аргумента указателя. - person Jonathan Leffler; 03.05.2015