В чем причина этого неожиданного дополнительного символа в C?

#c #string #memory

Вопрос:

Когда я запускаю следующий код:

 #include <stdio.h>
#include <string.h>

int main() {
    static char foo[32];
    memset(foo, '0', sizeof(foo));
    printf("%s %dn", foo, sizeof(foo));

    return 0;
}
 

Я получаю следующий вывод:

 00000000000000000000000000000000☺ 32
 

Длина строки 33, а ее размер 32 байта, поэтому кажется, что символ «смайлик» с индексом 32 взят из какого-то фрагмента нераспределенной памяти. Я в замешательстве относительно того, что здесь происходит, и, похоже, я не могу достаточно хорошо сформулировать поисковый запрос, чтобы найти то, что я ищу. Любые предложения будут высоко оценены.

Комментарии:

1. Вопрос: итак, похоже, что символ «смайлик» с индексом 32 происходит из какого-то фрагмента нераспределенной памяти.. Да. Вы инициализировали все 32 символа вашего 32-символьного массива цифрой ASCII «0» … но вы забыли обнулить завершение строки! Последний символ строки C должен быть двоичным «0». Результатом является неопределенное поведение .

2. Спасибо за помощь!

3. «Длина строки 33» —> > foo не является строкой , так как в ней отсутствует нулевой символ .

Ответ №1:

%s в printf() ожидает указатель на строки, что означает «последовательность символов, заканчивающаяся нулевым символом» в C.

Все байты в буфере foo заполнены '0' , поэтому в буфере нет завершающего нуль-символа, и printf() он выйдет за пределы диапазона, чтобы найти завершающий нуль-символ.

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

Также обратите внимание, что sizeof возвращает size_t %d спецификатор формата while и заданную длину (если она указана в качестве аргумента). Передача данных неправильного типа вызывает неопределенное поведение. Правильный спецификатор формата для печати size_t %zu . (Обратите внимание, что size_t это без подписи).

 #include <stdio.h>
#include <string.h>

int main() {
    static char foo[32];
    memset(foo, '0', sizeof(foo));
    printf("%.*s %zun", (int)sizeof(foo), foo, sizeof(foo));

    return 0;
}
 

Комментарии:

1. Спасибо за ответ! Я подозревал, что это как-то связано с завершающим символом в строке, но я не мог точно определить его. Кстати, почему этот ответ отвергается?

2. @SeanXie NMDV, все же я подозреваю, что печать массива символов с "%.*s" помощью необычна для некоторых. Это правильное решение для 32-байтового массива с 32 '0' . Альтернативы включают создание foo[33]; строки и использование "%s" .