printf如何打印非空终止字符串?

时间:2012-12-01 04:33:18

标签: c

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。

5 个答案:

答案 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>之前看到换行符,我的猜测是正确的。如果你看看现在正在打印的指针,你可以比较它们在内存中的地址。