Sscanf дал мне неожиданный результат

Я изучаю язык Си. Это мой код, работающий в Linux.

#include <stdio.h>

int main(int argc, char *argv[]){
    char string[] = "Rudolph is 12 years old";
    char str[20] = {0}
    char i;
    sscanf(string, "%s %*s %d", str, &i);
    printf("%s -> %d\n", str, i);

    return 0;
}

Мой ожидаемый результат:

Rudolph -> 12

Но я получил результат:

 -> 12

Я хочу знать, что произошло и почему? Я попробовал заменить char i на int i и получил ожидаемый результат.

Но я не знаю, почему с char i я не получаю ожидаемого результата.

Итак, вы уже знаете ответ? char — это один байт, а int, вероятно, 4. Итак, когда sscanf сохраняет значение, куда идут 3 дополнительных байта?! Может ли это перезаписать какое-то другое значение?

BoP 23.05.2024 09:38

Вероятно, у вас есть предупреждение для %d и char i. Почему ты игнорируешь это?

i486 23.05.2024 09:39

Соврите компилятору (вы обещали дать sscanf адрес int (%d), но вместо этого отправили адрес char (&i)) и он отомстит!

pmg 23.05.2024 09:47

Это не ваша текущая ошибка, но: НИКОГДА не игнорируйте возвращаемое значение любой из функций семейства scanf(). Это единственный способ узнать, удалось ли преобразование или нет. Кроме того, НИКОГДА не используйте преобразование %s без спецификатора ширины в реальном коде — это просто запрос на переполнение буфера.

Toby Speight 23.05.2024 10:13

«sscanf дал мне неожиданный результат» кажется хорошим названием для мемуаров.

Retired Ninja 23.05.2024 10:25

Голосуем за то, чтобы закрыть это как простую опечатку, поскольку это не представляет никакой ценности для будущих читателей, и у нас на сайте уже есть тысячи вопросов о несоответствии строк формата printf/scanf.

Lundin 23.05.2024 11:06
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
83
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

%d в функциях scanf предназначен для int, а не char. При вызове неопределенного поведения три дополнительных байта, вероятно, перезапишут что-то еще. Дезинфицирующее средство адресов находит проблему, и компилятор предупреждает о ней: https://godbolt.org/z/YPKv111r9

%hhd для signed char, %hhu для unsigned char, когда вы хотите прочитать число, а не символ.

https://godbolt.org/z/o7WYGYfzK

Вам следует использовать %hhd вместо %d, поскольку sscanf рассматривает %d как ожидающее 4-байтовое целое число. При использовании %d sscanf предполагает, что предоставленная область памяти достаточно велика для хранения целого числа (обычно 4 байта). Это может привести к неопределенному поведению, поскольку sscanf может перезаписать соседнюю память. В вашем конкретном случае эта соседняя память, скорее всего, является частью массива str, что приводит к потенциальному повреждению его содержимого. Использование %hhd гарантирует, что sscanf правильно интерпретирует местоположение целевой памяти как символ (1 байт).

Вот фрагмент кода с исправлением:

#include <stdio.h>

int main(int argc, char* argv[]) {
 char string[] = "Rudolph is 12 years old";
 char str[20] = {0};
 char i;
 sscanf(string, "%s %*s %hhd", str,&i);
 printf("%s -> %d\n", str, i);

 return 0;
}

Это изменение позволит правильно проанализировать входную строку и сохранить проанализированное значение в переменной char.

«Использование %hhd гарантирует правильность sscanf» --> имеет смысл, когда char подписано, но не тогда, когда char не подписано, где ожидается "%hhu".

chux - Reinstate Monica 23.05.2024 10:49

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