Работа со структурами в Си
Есть вот такая достаточно простая программа на Си, она заведомо написана с ошибкой, я попытался ее найти, но не понял в чем суть. Я полагаю, что на консоль должно выводиться str: 102 num: 1025
Выводится: str: 1025 num: 1024
Почему после sprintf изменяется значение в num ? И почему в str записывается 4 цифры а не 3 в момент отладки внутри функции в str хранится '1','0','2', на выходе получаем 1025. Пробовал менять спецификатор с %3d на %d результат не изменился.
#include <stdio.h>
typedef struct
{
char str[3];
int num;
} NumberRepr;
void format(NumberRepr* number)
{
sprintf(number->str, "%3d", number->num);
}
int main()
{
NumberRepr number = { .num = 1025 };
format(&number);
printf("str: %s\n", number.str);
printf("num: %d\n", number.num);
return 0;
}
Ответы (2 шт):
Потому что вы забыли о том, что С-строка (массив char) является строкой с завершающим нулевым символом. В результате, когда вы в 3 байта записываете строку %3d, четвертый символ - нулевой - записывается далее в память и портит следующее поле вашей структуры.
Вам надо указать иной, достаточный размер массива. Ну никак вы не поместите в 3 символа число 1024, например (для него нужно пять). Вобщем, не мелочитесь.
Хотя зачем вам одновременно держать одно и то же число в разном виде - не очень понимаю. Но тогда уж исходите из того, что int может быть и минус 2 миллиарда, т.е. реально нужен char str[12] как минимум...
Видимо вы не ознакомились с документацией к функции sprintf. Число 3 в строке с форматом задает минимальную ширину поля. Соответственно для печати числа 1025 что с форматом %3d, что с форматом %d, требуется 4 + 1 байт. В любом случае происходит переполнение буфера. Вместо этого следовало использовать функцию snprintf и указать размер входящего буфера. При этом также следует не забыть проверить возвращаемое значение на предмет ошибки или усечения вывода:
void format(NumberRepr* number)
{
int const result = snprintf(number->str, 3, "%d", number->num);
if (result <= 0)
{
printf("snprintf failed: %d\n", result);
abort();
}
if ((3 - 1) < result)
{
printf("snprintf truncated output of length %d to %d bytes\n", result, (3 - 1));
}
}
Еще размер буфера следует не хардкодить, а определять через макрос, но это уже другой вопрос.