printf如何打印非空终止字符串?
c编程书说我的字符串必须为空终止以使用printf打印它,但仍然以下程序打印字符串尽管它是非空终止!
#include #include int main(){ int i ; char str[10] ; for(i = 0 ; i < 10 ; i++ ) { str[i] = (char)(i+97) ; } printf("%s",str) ; }
我正在使用codeblocks IDE。
读取超出数组边界的未定义行为 ,实际上是不幸的是它没有崩溃,如果你运行足够多次或者在函数中调用它可能(或可能不)崩溃,你应该总是终止字符串,或使用宽度说明符:
printf("%.10s", str);
无论在str
的第10个元素之后是什么,它都是空的。 该null超出了数组的已定义边界,但C没有数组边界检查。 在你的情况下,这就是运气的原因。
根据C标准,printf函数在字符串中打印字符,直到找到空字符。 否则,在定义的数组索引之后,将不会定义它将执行的操作。 我已经测试了你的代码。 打印后“abcdefghij打印出一些垃圾值。
如果在调用之前执行其他操作,则堆栈区域将包含除未使用的数据之外的其他数据。 设想:
#include #include #include int use_stack(void) { char str[500]; memset(str, 'X', sizeof(str)); printf("Filled memory from %p to %p.\n", &str, &str+sizeof str); } void print_stuff() { int i; char str[16]; // changed that so that 10..15 contain X for(i = 0; i < 10; i++) { str[i] = (char)(i+97); } printf("%s",str); // have a line break before ? Then it comes from i. printf("&str: %p\n", &str); printf("&i: %p\n", &i); // Here you see that i follows str as &i is &str + 16 (0x10 in hex) } int main() { use_stack(); print_stuff(); }
你的堆栈区域将充满X
es, printf()
将会看到它们。
在您的情况和您的环境中,堆栈在程序启动时巧合地“干净”。
编辑:这可能会也可能不会发生。 如果编译器将变量i
紧跟在数组之后,那么你的数据仍将是NUL
终止的,因为第一个字节是i
的值(你碰巧也打印出来) – 在你的情况下可能是一个libne中断 – 并且第二个字节是NUL
字节。即使是这种情况,您的代码也会调用UB(未定义的行为)。
如果输出包含0A
字符,你能看一下(通过将程序输出hexdump
到hexdump
或类似的东西)吗? 如果是这样,我的猜测是正确的。 我只是测试了它,在我的编译器( gcc
)上似乎就是这样。
如上所述,你应该依靠什么。
编辑2:如果你在
之前看到一个换行符,我的猜测是正确的。 如果你看看现在正在打印的指针,你可以比较它们在内存中的地址。
因为在调试模式下, *(str+10)
和整个未使用的空间都有一个初始化值’0’,所以看起来它终止了0。
bash-3.2$ clang -O0 tc -ot #compile in debug mode bash-3.2$ ./t abcdefghij bash-3.2$ clang -O2 tc -ot #compile with optimization bash-3.2$ ./t abcdefghij2÷d=