为什么数字数组不以'\ 0'或空字符结尾?

时间:2013-10-12 08:00:59

标签: c arrays

为什么数字数组不以空字符结尾?

例如,

char name[] = {'V', 'I', 'J', 'A', 'Y', '\0'};

但是在数字数组的情况下,最后没有空字符的符号......

例如,

int marks[] = {20, 22, 23};

背后的原因是什么?

12 个答案:

答案 0 :(得分:21)

提出的问题包含一个隐藏的假设,即所有char数组都以空字符结尾。事实并非总是如此:必须以空字符结尾的char数组是那些用作字符串的数组,实际上需要终止。

在您的示例中,char数组仅以空字符结尾,因为您已经这样做了。编译器将为您插入空字符的单个位置是从字符串文字声明char数组时,例如:

char name[] = "VIJAY";

在这种情况下,会自动插入空字符,以使结果数组成为有效的C字符串。对于其他数字类型的数组不存在这样的要求,也不能从字符串文字初始化它们。换句话说,将零添加到数值数组将没有任何意义,因为没有代码使用零来查找数组结束,因为零是一个完全有效的数字。

指针数组有时会以NULL指针终止,这是有道理的,因为NULL指针不能与有效指针混淆。由argv接收的main()字符串数组就是这种数组的一个示例。

答案 1 :(得分:5)

字符串以0终结符结尾,但字符串数组不同。我们使用数组来存储字符串,但我们也使用数组来存储字符串的内容。这就是为什么数组一般不会自动附加0。

此外,在int的任何通用数组中,0可能是有效(非哨兵)值。

答案 2 :(得分:4)

数组可以以数组元素类型的有效值结尾。但只有一个\0终止的char数组称为字符串。

例如

char name[]={'V','I','J','A','Y'};

有效但不是字符串,限制是你不能在期望像strlen等字符串的函数中使用它。


为了澄清下面的OP评论,按照C标准,'a''1'等任何字符文字,包括'\0'都是int类型。你可以将'\0'放在int数组的末尾,如下所示:

int arr[] = {20, 22, 23, '\0'};

但人们通常不这样做,因为'\0'仅用于终止字符串是常规的。上面的代码相当于

int arr[] = {20, 22, 23, 0};

答案 3 :(得分:4)

如果您愿意,也可以使用int制作0数组结尾:

int iarray[] = {1, 2, 3, 0};

由于'\0'0完全相同,您甚至可以用0替换上面的'\0'

您的困惑可能是由于'\0'在声明中自动插入,例如:

char s[] = "hello";

在上文中,s的定义等同于char s[] = {'h', 'e', 'l', 'l', 'o', '\0'};。您可以将此视为C标准提供的便捷快捷方式。如果需要,可以通过明确大小来强制非零终止的char数组:

char s[5] = "hello";

在上面的示例中,s不会NUL终止。

另请注意,C中的字符文字属于int,因此'\0'实际上是int。 (另外,char是一个整数类型。)

答案 4 :(得分:2)

您不必在字符数组的末尾加上'\0'个字符!这是一个错误的假设。没有规则说你这么做。字符(char类型)与任何其他类型的数据完全相同。

如果要使用标准printf -family函数打印数组,则必须使用空终止的char数组。但只是因为这些函数依赖于字符数组的结尾 - '\0' char。

函数通常有关于他们期望的数据类型的规则。字符串(char[])函数也不例外。但这不是语言要求,而是您正在使用的具有这些要求的API。

答案 5 :(得分:2)

您需要使用'\0'结束C字符串,因为这是库知道字符串结束位置的方式 NUL - 终止是区分char数组与字符串(一个NUL - 终止的char数组)的区别。大多数字符串操作函数依赖于NUL来知道字符串何时完成(并且其作业已完成),并且不能使用简单的char-array(例如,它们将继续工作超过数组,并继续直到它在内存中找到NUL - 通常会破坏内存。

答案 6 :(得分:2)

Char数组以特殊字符'\0'结尾,因此可以将其视为字符串。 当你操纵字符串时,必须有一些方法来告诉字符串的长度(边界)。

查看strcpy

的函数原型
char * strcpy ( char * destination, const char * source );

如何知道从源到目的地复制多少个字符?答案是通过查看'\0'的位置。

在将字符串作为'\0'处理时,char *字符很突出。如果没有'\0'作为结束标记,您将无法将char *视为字符串。

答案 7 :(得分:2)

有三种,也许四种方法可以跟踪数组的长度,其中只有两种在C中很常见:

  • 自己跟踪长度并将其与指针一起传递。

    这就是数组通常的工作方式。它不需要任何特殊格式,并使子数组视图无法表示。 (添加到指针,从长度中减去,然后就可以了。)

    标准库中与非字符串数组一起使用的任何函数都需要这样。甚至一些混乱字符串的函数(如strncatfgets)也是为了安全起见。

  • 使用一些“sentinel”值终止数组。

    这就是C字符串的工作方式。因为几乎每个字符集/编码都将'\0'定义为不可打印的“无所事事”控制字符,所以它不是文本的典型部分,因此使用它来终止字符串有道理。

    请注意,当您使用char[]作为字节数组时,仍然需要指定长度。那是因为字节不是字符。一旦你处理的是字节而不是字符,0就会失去其作为标记值的含义,并回到普通的旧数据。

    最大的问题是,对于大多数基本类型,sizeof(type)字节的每种可能排列都可能代表有效的有用值。对于积分值,零特别普通;它可能是所有计算中最常用和最有用的数字之一。我完全希望能够将0放入一个整数数组中而不会丢失一半的数据。

    那么问题就变成了,什么是一个好的哨兵价值?在数组中应该禁止哪些合法的数字?这个问题没有好的,普遍的答案;它完全取决于您的数据。所以如果你想做这样的事情,那就是你自己。

    除了缺乏一个不错的标记值之外,由于另一个原因,这种方法与非字符类型相反:表示数组的子集更复杂。为了使递归函数将数组的一部分传递给自身,它必须插入sentinel值,调用自身,然后恢复旧值。要么是,要么它可以传递指向范围的开始和范围的长度的指针。但是等等......这不是你要避免的吗? :P

为完整起见,另外两种方法:

  • 创建一个结构,可以存储数组的长度以及指向数据的指针。

    这是一种更面向对象的方法,它是几乎所有现代语言中数组的工作方式(以及向量如何在C ++中工作)。如果你有一个API来管理这样的结构,它可以在C中正常工作,如果你有宗教信仰使用那个API。 (面向对象的语言提供了一种将API附加到对象本身的方法.C没有,因此您可以坚持使用API​​。)但是任何不适合您的结构的函数都需要使用上述两种方法之一传递指针(可能是长度)。

  • 传递两个指针。

    这是在C ++中传递“范围”的常用方法。您将指针传递给数组的开头,并将指针传递到结尾。但是在C中不太常见,因为使用原始指针,(start,length)(start,end)表示相同的数据 - 而C没有迭代器和模板,这使得它更加有用。

答案 8 :(得分:1)

不必要的char数组以\ 0结尾。

C约定字符串以\ 0结尾。
这对于查找字符串的结尾很有用。

但是如果你只对保持char类型的数据感兴趣,那么你可以得到一个\ 0结尾。

如果您的char数组要用作字符串,则应在其末尾添加\ 0。

编辑:以0结尾的是字符串文字,而不是字符数组。
问题不明确。

答案 9 :(得分:1)

数组本身不必被0\终止,它是以特定方式使用字符数组,需要它们\0终止。作用于字符数组的标准库函数将使用\0来检测数组的结尾,因此将其视为字符串,这种行为意味着这些函数的用户需要遵循\0终止前提。如果您的字符数组使用不使用任何此类功能,则它不需要\0终止符。

答案 10 :(得分:0)

一个例子,指出如果在整数数组中采用\ 0将如何混淆: -

int marks[]={20,22,23,0,93,'\0'};
                      ^  

所以现在你的数组会假设0(标记)是数组的结尾,这是不正确的。

\0通常用于终止字符串。字符串\0被视为字符串的结尾。

在您的示例中,您不需要使用'\ 0'

来终止它

找到了一篇非常有趣的wiki帖子: -

  

当时C(及其衍生的语言)是   开发,内存非常有限,所以只使用一个字节   存储字符串长度的开销很有吸引力。唯一的   当时流行的替代品,通常称为“Pascal字符串”   (虽然早期版本的BASIC也使用过),使用了一个前导字节   存储字符串的长度。这允许字符串包含NUL   并且找到长度只需要一次内存访问(O(1)   (常数)时间)。 然而,C设计师Dennis Ritchie选择了跟随   已经在BCPL中建立的NUL终止惯例   避免因持有而导致的字符串长度限制   计入8位或9位插槽,部分原因是保持计数   根据我们的经验,似乎比使用终结器更不方便。

同时查看相关帖子: - nul terminating a int array

答案 11 :(得分:-3)

我们有一个惯例:带有数字代码'0'的特殊字符0,标记字符串的结尾。

但是如果你想标记int数组的结尾,你怎么知道0是一个有效的数组成员还是数组结尾标记?因此,一般来说,不可能有这样的标记。

换句话说:

字符'\0'(但不是字符'0',代码48在文本字符串的上下文中没有任何意义(按照惯例,它是一个特殊字符,标记结束),因此可以用作数组末尾标记:

整数0\0(相同)是有效整数。它可以有意义,这就是不能用作数组末尾标记的原因:

int votesInThisThread[] = { 0, -1, 5, 0, 2, 0 }; // Zeroes here is a valid numbers of upvotes

如果您尝试通过搜索0来检测此示例数组的结尾,则您将获得0的大小。

那是什么问题?