Работа со структурами в Си

Есть вот такая достаточно простая программа на Си, она заведомо написана с ошибкой, я попытался ее найти, но не понял в чем суть. Я полагаю, что на консоль должно выводиться 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 шт):

Автор решения: Harry

Потому что вы забыли о том, что С-строка (массив char) является строкой с завершающим нулевым символом. В результате, когда вы в 3 байта записываете строку %3d, четвертый символ - нулевой - записывается далее в память и портит следующее поле вашей структуры.

Вам надо указать иной, достаточный размер массива. Ну никак вы не поместите в 3 символа число 1024, например (для него нужно пять). Вобщем, не мелочитесь.

Хотя зачем вам одновременно держать одно и то же число в разном виде - не очень понимаю. Но тогда уж исходите из того, что int может быть и минус 2 миллиарда, т.е. реально нужен char str[12] как минимум...

→ Ссылка
Автор решения: user7860670

Видимо вы не ознакомились с документацией к функции 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));
    }
}

online compiler

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

→ Ссылка