我试图理解字符串中的数组概念。
char a[5]="hello";
这里,数组a是一个大小为5的字符数组。"你好"从0到4占用数组索引。因为我们已经将数组大小声明为5,所以没有空格在字符串的末尾存储空字符。
所以我的理解是当我们尝试打印a时,它应该打印直到遇到空字符。否则它也可能会遇到分段错误。
但是,当我在我的系统中运行时,它总是会打印#34;你好"并终止。
所以任何人都可以澄清我的理解是否正确。或者它取决于我们执行的系统。
答案 0 :(得分:4)
一如既往,答案是:
未定义的行为未定义 。
这意味着,尝试将此字符数组提供给处理字符串的函数错误。这是错误的,因为它不是字符串。 C中的字符串是一个以\0
字符结尾的字符序列。
C标准会告诉您这是未定义的行为。所以,任何事都可能发生。在C中,您没有运行时检查,代码只是执行。如果代码具有未定义的行为,则必须为任何效果做好准备。这包括像你预期的那样工作,只是偶然。
在数组恰好是\0
字节之后,内存中跟随的字节很可能。在这种情况下,它将查找处理此“字符串”的任何函数,就像您传递了一个有效字符串一样。崩溃只是等待对代码进行一些看似无关的更改。
您可以尝试在数组定义之前或之后添加一些char foo = 42;
,很可能您会在输出中看到它。但是,当然,不能保证,因为未定义的行为是未定义的:)
答案 1 :(得分:1)
您所做的是未定义的行为。显然,你使用的任何编译器都会在数组之后将内存初始化为0。
这里,数组a是一个大小为5的字符数组。"你好"从0到4占用数组索引。因为我们已经将数组大小声明为5,所以没有空格在字符串的末尾存储空字符。
所以我的理解是当我们尝试打印a时,它应该打印直到遇到空字符。
是的,当你使用printf("%s",a)时,它会打印字符,直到它到达' \ 0'字符(或段错误或其他不良事件发生 - 未定义的行为)。我可以用一个简单的程序来证明:
#include <stdio.h>
int main()
{
char a[5] = "hello";
char b[5] = "world";
int c = 5;
printf("%s%s%d\n", a, b, c);
return 0;
}
输出:
$ ./a.out
helloworldworld5
您可以看到printf函数在读取了数组a
中的所有字符后继续读取字符。但是,我不知道什么时候会停止阅读字符。
我稍微修改了我的程序,以演示这种未定义的行为如何产生不良问题。
#include <stdio.h>
#include <string.h>
int main()
{
char a[5] = "hello";
char b[5] = "world";
int c = 5;
printf("%s%s%d\n", a, b, c);
char d[5];
strcpy(d, a);
printf("%s", d);
return 0;
}
结果如下:
$ ./a.out
helloworld��world��5
*** stack smashing detected ***: <unknown> terminated
helloworldhell�p��UAborted (core dumped)
由于未定义的行为,这是堆栈溢出(双关语)的经典案例。
编辑:
我需要强调:这是不明确的行为。根据您的编译器,体系结构,库等,您可能会或可能不会发生此示例中发生的事情。您可以根据您对不同平台上各种库和编译器的不同实现的理解来猜测会发生什么,但是您永远不能肯定会说会发生什么。我的例子是使用gcc版本7的Ubuntu 17.10。我的猜测是,如果我在具有不同编译器的嵌入式平台上尝试这种情况会发生一些非常不同的事情,但我不能肯定地说。事实上,如果我在同一台机器上的一个更大的程序中有这个例子,就会发生不同的事情。