Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 数组如何终止?_C - Fatal编程技术网

C 数组如何终止?

C 数组如何终止?,c,C,正如我们所知,字符串以'\0'结尾。 这是因为要知道该字符串结束的编译器,或者要防止垃圾值 但是数组如何终止? 如果使用了'\0',则将其视为0有效整数, 那么编译器是如何知道数组结束的呢?C不会为您提供任何关于“知道数组结束”的保护或保证。作为程序员,您需要记住这一点,以避免访问数组之外的内存。C不会对数组执行边界检查。这就是它快速发展的部分原因。但是,这也意味着您需要确保读写操作不会超过数组的末尾。因此,该语言将允许您执行以下操作: int arr[5]; arr[10] = 4; str

正如我们所知,字符串以
'\0'
结尾。 这是因为要知道该字符串结束的编译器,或者要防止垃圾值

但是数组如何终止? 如果使用了
'\0'
,则将其视为
0
有效整数,
那么编译器是如何知道数组结束的呢?

C不会为您提供任何关于“知道数组结束”的保护或保证。作为程序员,您需要记住这一点,以避免访问数组之外的内存。

C不会对数组执行边界检查。这就是它快速发展的部分原因。但是,这也意味着您需要确保读写操作不会超过数组的末尾。因此,该语言将允许您执行以下操作:

int arr[5];
arr[10] = 4;
struct string {
    unsigned int length;
    char *buffer;
}
但如果你这样做了,你就会调用。因此,您需要跟踪阵列的大小,并确保不会超过末端

请注意,这也适用于字符数组,如果它包含以空字节结尾的字符序列,则可以将其视为字符串。这是一个字符串:

char str[10] = "hello";
这也是:

char str[5] = { 'h', 'i', 0, 0, 0 };
但这不是:

char str[5] = "hello";  // no space for the null terminator.

C语言没有本机字符串类型。在C语言中,字符串实际上是以空字符
'\0'
结尾的一维字符数组

来自C标准#7.1.1p1[强调矿山]

字符串是以第一个空字符结尾的连续字符序列。术语“多字节字符串”有时用于强调字符串中包含的多字节字符的特殊处理,或避免与宽字符串混淆。指向字符串的指针是指向其初始(最低地址)字符的指针字符串的长度是空字符前面的字节数,字符串的值是包含字符的值的顺序。

字符串是字符数组的一种特殊情况,它由空字符
'\0'
终止。所有与库字符串相关的标准函数都会根据此规则读取输入字符串,即读取到第一个空字符

除了C中的字符数组之外,任何类型的数组中的空字符
'\0'
都没有意义

所以,除了字符串之外,对于所有其他类型的数组,程序员都应该显式地跟踪数组中元素的数量

另外,请注意,第一个空字符(
'\0'
)表示字符串终止,但它不会阻止您读取超出它的内容

考虑这个例子:

#include <stdio.h>

int main(void) {
    char str[5] = {'H', 'i', '\0', 'z'};
    printf ("%s\n", str);
    printf ("%c\n", str[3]);
    return 0;
}
您将获得的输出是-
Hi

因为使用
%s
格式说明符,
printf()
将每个字节写入第一个空终止符(注意字符串中使用空字符),但您也可以打印数组的第4个字符,因为它在
char
array
str
的范围内,但超出了第一个
'\0'
字符

printf ("%c\n", str[3]);
您将获得的输出是-
z

附加:

试图访问超出其大小的阵列可能导致程序执行不正确(崩溃或静默生成不正确的结果),或者它可能会意外地完全按照程序员的意图进行操作。

这只是一个惯例问题。如果您愿意,您完全可以编写代码,通过一些sentinel值处理数组终止(对于任何类型的数组)。下面是一个这样的示例,任意使用-1作为哨兵:

int length(int arr[]) {
    int i;
    for (i = 0; arr[i] != -1; i++) {}
    return i;
}
然而,这显然是完全不现实的:你不能再在数组中使用-1了

相比之下,对于C字符串,sentinel值
'\0'
的问题较少,因为一般测试不包含此字符。这种假设是有道理的。但即使如此,显然有许多字符串确实包含
'\0'
作为有效字符,因此空终止绝不是通用的

一种非常常见的替代方法是将字符串存储在结构中,该结构如下所示:

int arr[5];
arr[10] = 4;
struct string {
    unsigned int length;
    char *buffer;
}
也就是说,我们显式地将长度存储在缓冲区旁边。此缓冲区不是以null结尾的(尽管在实践中,为了与C函数兼容,它通常有一个附加的
'\0'
字节)


无论如何,答案归结为:对于C字符串,空终止是一种方便的约定。但这只是一种约定,由C字符串函数(以及C字符串文字语法)强制执行。您可以对其他数组类型使用类似的约定,但这是不可行的。这就是为阵列开发其他约定的原因。值得注意的是,大多数处理数组的函数都需要数组和长度参数。此长度参数确定数组终止的位置。

简短回答-它不确定,除非可能在原始数组声明的范围内。你到底在问什么?你的问题不清楚。对于字符串文本,编译器创建一个
char
数组,并使用文本中的字符对其进行初始化,并添加一个尾随的空字节以标记结束。对于其他字符数组,如果要将其视为字符串,则程序员的工作是确保数组末尾或之前存在空字节。对于其他类型的数组,程序员有责任知道数组的长度。在编译时,编译器知道数组的长度(可以使用
sizeof
运算符访问)。它在运行时是未知的,除非您自己将其存储到变量中。可能令人困惑的是,您不能真正将数组作为函数参数传递。即使函数参数列表中的语法看起来像数组,它们也会转换为指针。因此,如果需要数组的长度作为函数参数,则必须将其作为额外参数传递