C编程中对字符串的困惑

时间:2014-08-02 11:00:15

标签: c printf string-literals c-strings array-initialization

所以我正在学习使用编译器Dev C ++编程c。 问题1:

#include <stdio.h> 
#include <conio.h> //for the getch() function
#include <string.h> 

int main(void) 
{ 
    char line[3]; 
    strcpy(line, "Hello world"); 
    printf("%s", line); 
    getch(); 
} 

输出: 你好世界

为什么当我声明我的字符串只能容纳3个字符时,它会显示所有“Hello world”?

问题2:

char line[3] = "Hello world"; 
printf("%s", line); 

输出: 赫尔

为什么显示“Hel”?它不应该只显示“He”,因为行[0] = H,行[1] = e和行[2] ='\ 0'? %s的工作原理是搜索'\ 0'?

请帮助我了解最新情况。谢谢!

4 个答案:

答案 0 :(得分:11)

  

请帮助我了解最新情况。

未定义的行为!

执行此操作时,您需要buffer overrun

char line[3]; 
strcpy(line, "Hello world"); 
  

为什么当我声明我的字符串只能容纳3个字符时,它会显示所有“Hello world”?

您复制的数量超过了已分配数组的大小。这是未定义的行为,因此任何输出都是可能的,包括但不限于调用阿姨Tilda,格式化硬盘等。:) See here以获取更多信息。


char line[3] = "Hello world"; 
printf("%s", line); 

这里有buffer over-read!有关为何只将3个字符复制到line的原因,请参阅alk's answer

  

为什么显示“Hel”?它不应该只显示“他”

不,它可以显示任何内容,因为未定义的行为。看看我的机器输出了什么:

  

Hel☻

这是未定义的行为,因为printf期望你有一个以null结尾的字符串,是的,但这并不意味着你可以访问超出数组的大小,即你在内存中有这样的数组

                 [0] [1] [2]
-----------------------------------------------
. . . █ | █ | █ | H | e | l | █ | █ | █ | . . .
-----------------------------------------------
                <-- line --->

上面写的任何东西都是未知的值,不是你的权力,因此访问它们是不明确的。但是,%s中的printf需要一个以空字符结尾的字符串,因此,在您的命令下,它会超出允许的范围(允许的是只有三个元素,直到l)。在我的情况下,\0l之后出现了一个元素(笑脸),而在你的情况下,它恰好在l之后出现正确,但只有运气,它可能会出现1000个元素。


如果你真的想打印{null}终止的char数组,只能达到允许的限制,你可以在不遇到任何未定义的行为的情况下执行其中一个。

printf("%.3s", line);       // length specified at compile-time

printf("%.*s", 3, line);    // length fed at run-time

See here了解更多信息。

答案 1 :(得分:3)

参考问题2:

当使用“string”-literal作为初始化时,0 - 终结符仅在有空间时才会应用。

来自C99-Standard

  

6.7.8初始化

     

[...]

     

14可以选择使用字符串文字初始化字符数组   用括号括起来。字符串文字的连续字符(包括   如果有空间或数组的大小未知,则终止空字符)初始化   数组的元素。

答案 2 :(得分:1)

程序的两个示例都有未定义的行为。 在第一个示例中,您将覆盖数组之外的内存。 在第二个示例中,C不允许使用比对象可以接受的更多的初始化器。

  

2初始化程序不应尝试为对象提供值   包含在正在初始化的实体中。

对于允许忽略终止零

的字符数组,唯一的排除是完成的
  

14字符串数组可以用字符串初始化   文字或UTF-8字符串文字,可选择用大括号括起来。   字符串文字的连续字节(包括终止空值)   字符,如果有空间或数组的大小未知)   初始化数组的元素。

因此不应编译第二个代码片段,或者至少编译器应发出诊断消息。

答案 3 :(得分:0)

  

为什么当我声明我的字符串只能容纳3个字符时,它会显示所有“Hello world”?

因为printf()读取一个字符串直到null终止符。它不知道存储有多大,strcpy()也不知道;如果您想确保副本不超过存储空间的长度,请使用strncpy()(注意中间的n。)

  

为什么显示“Hel”?

没有必要对此进行解释,因为你已经溢出了缓冲区 - 这可能对程序产生任何奇怪的后果。您可能已经覆盖了其他内容(相反,您的数据可能会被覆盖)。如果违反规则,则很可能会调用“未定义的行为”。

在这种情况下,编译器只能编写3个字符,因为初始化的形式,但这不是值得信赖的事情 - 当你违反规则时,不一定有规则。< / p>