c编程书说我的字符串必须为空终止才能使用printf打印它,但是仍然以下程序打印字符串尽管它是非空终止的!
#include <stdio.h>
#include <stdlib.h>
int main(){
int i ;
char str[10] ;
for(i = 0 ; i < 10 ; i++ ) {
str[i] = (char)(i+97) ;
}
printf("%s",str) ;
}
我正在使用codeblocks IDE。
答案 0 :(得分:10)
未定义的行为读取超出数组的范围,你实际上运气不好它没有崩溃,如果你运行足够的时间或者在一个函数可能(或可能不)崩溃,你应该总是终止字符串,或使用宽度说明符:
printf("%.10s", str);
答案 1 :(得分:5)
str
的第10个元素恰好是null后的任何内容。该null超出了数组的已定义边界,但C没有数组边界检查。在你的情况下,运气就好了。
答案 2 :(得分:1)
根据C标准,printf函数在字符串中打印字符,直到找到空字符。否则,在定义的数组索引之后,它将执行的操作未定义。我已经测试了你的代码。并且在打印“abcdefghij之后它打印出一些垃圾值。
答案 3 :(得分:0)
因为在调试模式下,*(str+10)
和整个未使用的空间都有一个初始化值'0',所以看起来它已经被终止了。
bash-3.2$ clang -O0 t.c -o t #compile in debug mode
bash-3.2$ ./t
abcdefghij
bash-3.2$ clang -O2 t.c -o t #compile with optimization
bash-3.2$ ./t
abcdefghij2÷d=
答案 4 :(得分:0)
如果您在该呼叫之前执行其他操作,则堆栈区域将包含除未使用的数据之外的其他数据。想象一下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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<END>",str); // have a line break before <END>? 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
个,而printf()
将会看到它们。
在您的情况和您的环境中,堆栈在程序启动时同时“干净”。
编辑:这可能会也可能不会发生。如果编译器将变量i
紧跟在数组之后,那么您的数据仍将是NUL
- 终止,因为第一个字节是i
的值(您恰好也会打印出来) -it可能是你的情况下的libne中断 - 第二个字节是NUL
字节。即使是这种情况,你的代码也会调用UB(未定义的行为)。
如果您的输出包含hexdump
字符,您可以查看(通过将程序输出汇总到0A
或类似)吗?如果是这样,我的猜测是正确的。我只是测试了它,我的编译器(gcc
)就好了。
如上所述,你不应该依赖它。
EDIT2:如果您在<END>
之前看到换行符,我的猜测是正确的。如果你看看现在正在打印的指针,你可以比较它们在内存中的地址。