Если вы не обеспечиваете '\0'
в конце для запятой брекета списка закрытых инициализаторов, технически full_name
не строки, как char
массива не оканчивается нулем.
Просто, чтобы очистить вещи немного, в отличие от инициализатора, являющегося строковым литералом, список, разделенный запятыми, не автоматически считать и положить завершающий нулевой символ в массив.
Таким образом, в случае определения, как
char full_name[] = {
't', 'o', 'a', 'n'
};
размер массива равен 4, и она имеет 't'
, 'o'
, 'a'
, 'n'
в него.
Ото, в случае
char full_name[] = "toan";
full_name
будет иметь размер 5 и будет содержать 't'
, 'o'
, 'a'
, 'n'
и '\0'
в него.
При попытке использовать бывший массив с любой функцией, работающей на строках (т.е. ожидает завершающий нуль char
массива), вы получите undefined behavior как большинство из строковых функций будет выходить из границы в поисках нуль-терминатора.
В вашем конкретном примере, для %s
спецификатора формата с printf()
, цитируя C11
стандарт, глава §7.21.6.1, fprintf()
описания функции (курсив моего)
s
Если нет модификатора l
длины не является present, аргумент должен быть указателем на начальный элемент массива типа символа. 280)Символы из массива: записано до (но не включая) завершающий нулевой символ. Если указана точность , пишется не более чем много байтов. Если точность не указана или больше размера массива, массив должен содержать нулевой символ.
Это значит, printf()
будет искать нуль-терминатором, чтобы отметить/понять конец массива. В вашем примере отсутствие нулевого терминатора приведет к тому, что printf()
выйдет за выделенную память (full_name[3]
) и получит доступ к внешней памяти (full_name[4]
), которая вызовет UB.
@dasblinkenlight Благодарим за редактирование сообщения. – toantruong
Если нет нулевого завершения, то это не строка, касающаяся C. – Lundin