这是安全还是UB?
char x[5] = { 'a', 'b', 'c', 'd', 'e' };
printf("%5.5s\n", x);
打印非零终止字符串的正确printf格式是什么? (或者打印c-string的前N个字符的格式是什么?)
答案 0 :(得分:4)
行为定义明确。对应于普通%s
转换说明符的参数必须是指向字符串的指针(根据定义,它表示它包含一个空'\0'
终止符),但如果是如果指定了precision,则参数不必是指向字符串的指针(即,只要数组足够长,就没有空终止符。)
引用C11标准草案,N1570 7.21.6.1p8:
数组中的字符被写入(但不包括) 终止空字符。如果指定了精度,则不再存在 而不是写入多少字节。如果未指定精度或 如果大于数组的大小,则数组应包含null 字符。
如果要打印字符数组的前N个字符,其中N不是常量,可以使用*
指定长度作为单独的参数给出。例如,给定一个已知长度的字符数组,该数组不包含空字符,您可以这样做:
const char s[5] = "hello"; /* no terminating null character */
printf("%.*s\n", (int)sizeof s, s);
请注意,sizeof
仅适用于此s
是一个数组;如果它是一个指针,sizeof
会给你一个指针的大小,而不是数组的大小。另请注意,*
需要类型为int
的参数;由于printf
是一个可变函数,而sizeof
产生的值为size_t
,因此在这种情况下需要使用强制转换。
答案 1 :(得分:1)
printf("%.5s", str);
字符串不必终止NUL。
printf("%.*s", 5, str);
也可以。
答案 2 :(得分:1)
没有C字符串没有空终止。如果是这个解决方案,你可以尝试
printf("%.*s", len, str);
len
是您要打印的字符数,str
是您正在处理的字符串。
另外:
如果将宽度或精度指定为星号' *',则参数列表中的int将用作宽度或精度。如果宽度太小,则字段会扩展。例如:
int len = 5;
char *string = "This is a string"
printf("%*.*s", len, len, "string");
在功能上类似于"%5.5s"的规范字符串。 它最多可以打印5个字符的字符串。