#include <stdio.h>
int main() {
char a[12];
int b = scanf("%11s", a);
if (b != 1) { return 1; };
if (printf("%s", a) > 11) {
return 1;
};
return 0;
}
1. Безопасно ли здесь используются scanf
и printf
?
2 – мне не хватает каких-то чеков? я хочу сделать код на c на 100% без ошибок
3. Является ли единственной проблемой переполнение буфера сканирования? это исправлено в приведенном выше коде?
цель всего этого — сделать код на 100% безопасным
Это действительно зависит от того, что вы подразумеваете под безопасностью... Здесь у вас точно не будет проблем с безопасностью.
чтобы добавить дополнительную безопасность, а также предотвратить ub
На самом деле у вас есть одна проблема: что произойдет, если пользователь введет в a
строку, короче 11
символов? Тогда printf
вернет значение короче 11
. Это считается проблемой или нет? Из кода не ясно.
Единственная причина проверять возвращаемое значение printf
— это убедиться, что базовый write
работает, но вряд ли он выйдет из строя до fsync
или fclose
. В этом случае, если запись не удалась, она не будет обнаружена до завершения программы, когда fclose
неявно вызывается. Поскольку вы все равно не выдаете сообщение об ошибке, нет смысла проверять возвращаемое значение.
>= означает, что не должно быть больше 11
Также обратите внимание, что стандартные значения C из основной функции — это либо EXIT_SUCCESS
(обычно 0
), либо EXIT_FAILURE
(обычно 1
). Поскольку вы только возвращаетесь 0
, нет возможности проверить, сработала программа или нет.
но я не должен возвращать 0 из основного
он должен быть возвращен из оператора if, я знаю, что мне придется добавить описательное сообщение, поскольку это предназначено для целей отладки, я не добавлял сообщение
аа, ок, ок, я понял твою точку зрения, мне нужно вернуть 1, а не 0
Эмпирическое правило: если есть ошибка return EXIT_FAILURE;
. Иначе return EXIT_SUCCESS;
.
Проверка printf никогда не может дать сбой. Формат scanf гарантирует, что a
будет не длиннее 11, поэтому он не может напечатать больше этого значения.
Кстати, обычно перед выходом рекомендуется напечатать новую строку. В противном случае командная строка будет находиться в той же строке, что и выходные данные, что может сбить с толку.
Вам не нужны нулевые операторы после закрывающей скобки операторов if
. Удалите эти точки с запятой.
Я хочу сделать код на языке C, на 100% свободный от ошибок. Одна вещь, которая действительно может в этом помочь, — это использование единообразного стиля для вашего кода. Например, в вашем коде, как уже опубликовано, используются разные стили отступов для операторов if
. Это затрудняет чтение вашего кода и, следовательно, увеличивает вероятность того, что он будет содержать ошибки.
Да, здесь безопасно используются вызовы scanf()
и printf()
. Я бы не стал проверять возвращаемое значение из printf()
, но, похоже, для вас это обязательно. Однако используйте макросы, чтобы избежать жесткого кодирования двух связанных размеров массива и максимальной ширины поля. Поскольку вы не используете переменную b
ни для чего, я бы выбрал стиль без точек и исключил ее:
#include <stdio.h>
#include <stdlib.h>
#define LEN 11
#define str(s) str2(s)
#define str2(s) #s
int main() {
char a[LEN+1];
if (scanf("%" str(LEN) "s", a) != 1)
return EXIT_FAILURE;
if (printf("%s", a) > 11)
return EXIT_FAILURE;
}
Вместо scanf()
вы также можете использовать getdelim()
, getline()
или fgets()
, чтобы избежать макрошума с помощью sizeof a
. Обратите внимание, что scanf("%s", ...)
читает последовательность символов без пробелов (т. е. слово), тогда как getdelim()
читает строку с указанным пользователем разделителем, а getline()
и fgets()
читают строку. В любом случае вам придется обрабатывать разделитель:
#include <string.h>
// ...
char a[13];
if (!fgets(a, sizeof a, stdin))
return EXIT_FAILURE;
a[strcspn(a, "\n")] = '\0';
stdout
, вероятно, буферизуется по строкам, поэтому рекомендуется напечатать завершающую новую строку. a
может иметь или не иметь новую строку, поэтому вам придется либо удалить ее, как указано выше, а затем безоговорочно добавить новую строку, скажем, в строку формата, либо убедиться, что a
содержит новую строку.
Вы также можете: if (scanf("%" str(LEN) "s", a) != 1 || printf("%s", a) > 11) return EXIT_FAILURE;
@Chris Да, хорошее предложение, и я обдумал его, но оставлю все как есть, чтобы оставаться разумным и близким к тому, что было опубликовано изначально. Пожалуйста, не удаляйте свой комментарий.
Хотя вам всегда следует проверять, что возвращает
scanf
, вам редко, если вообще когда-либо, понадобится проверять результатprintf
. С учетом сказанного, ваш код, как показано на данный момент, в порядке.