Безопасно ли использовать printf и scanf в этом коде?

#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% безопасным

Хотя вам всегда следует проверять, что возвращает scanf, вам редко, если вообще когда-либо, понадобится проверять результат printf. С учетом сказанного, ваш код, как показано на данный момент, в порядке.

Some programmer dude 02.08.2024 16:27

Это действительно зависит от того, что вы подразумеваете под безопасностью... Здесь у вас точно не будет проблем с безопасностью.

Vladouch 02.08.2024 16:27

чтобы добавить дополнительную безопасность, а также предотвратить ub

unknown 02.08.2024 16:29

На самом деле у вас есть одна проблема: что произойдет, если пользователь введет в a строку, короче 11 символов? Тогда printf вернет значение короче 11. Это считается проблемой или нет? Из кода не ясно.

Some programmer dude 02.08.2024 16:32

Единственная причина проверять возвращаемое значение printf — это убедиться, что базовый write работает, но вряд ли он выйдет из строя до fsync или fclose. В этом случае, если запись не удалась, она не будет обнаружена до завершения программы, когда fclose неявно вызывается. Поскольку вы все равно не выдаете сообщение об ошибке, нет смысла проверять возвращаемое значение.

William Pursell 02.08.2024 16:33

>= означает, что не должно быть больше 11

unknown 02.08.2024 16:33

Также обратите внимание, что стандартные значения C из основной функции — это либо EXIT_SUCCESS (обычно 0), либо EXIT_FAILURE (обычно 1). Поскольку вы только возвращаетесь 0, нет возможности проверить, сработала программа или нет.

Some programmer dude 02.08.2024 16:33

но я не должен возвращать 0 из основного

unknown 02.08.2024 16:39

он должен быть возвращен из оператора if, я знаю, что мне придется добавить описательное сообщение, поскольку это предназначено для целей отладки, я не добавлял сообщение

unknown 02.08.2024 16:40

аа, ок, ок, я понял твою точку зрения, мне нужно вернуть 1, а не 0

unknown 02.08.2024 16:41

Эмпирическое правило: если есть ошибка return EXIT_FAILURE;. Иначе return EXIT_SUCCESS;.

Some programmer dude 02.08.2024 16:41

Проверка printf никогда не может дать сбой. Формат scanf гарантирует, что a будет не длиннее 11, поэтому он не может напечатать больше этого значения.

Barmar 02.08.2024 17:47

Кстати, обычно перед выходом рекомендуется напечатать новую строку. В противном случае командная строка будет находиться в той же строке, что и выходные данные, что может сбить с толку.

Barmar 02.08.2024 17:49

Вам не нужны нулевые операторы после закрывающей скобки операторов if. Удалите эти точки с запятой.

Jonathan Leffler 02.08.2024 20:35

Я хочу сделать код на языке C, на 100% свободный от ошибок. Одна вещь, которая действительно может в этом помочь, — это использование единообразного стиля для вашего кода. Например, в вашем коде, как уже опубликовано, используются разные стили отступов для операторов if. Это затрудняет чтение вашего кода и, следовательно, увеличивает вероятность того, что он будет содержать ошибки.

Andrew Henle 03.08.2024 13:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
15
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Да, здесь безопасно используются вызовы 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 02.08.2024 22:59

@Chris Да, хорошее предложение, и я обдумал его, но оставлю все как есть, чтобы оставаться разумным и близким к тому, что было опубликовано изначально. Пожалуйста, не удаляйте свой комментарий.

Allan Wind 02.08.2024 23:04

Другие вопросы по теме