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字符,你能看一下(通过将程序输出hexdumphexdump或类似的东西)吗? 如果是这样,我的猜测是正确的。 我只是测试了它,在我的编译器( 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=