C中结束数组的一般规则

628mspwn  于 2023-04-05  发布在  其他
关注(0)|答案(4)|浏览(199)

所以,我知道字符串的最后一个元素,也就是char数组是NULL,它的值为0。如果我们定义一个包含5个字母的单词的字符串,比如Stack,我们可以按照下面的方法来做。

char word[5] = "Stack";

如果我想访问数组的第一个字母S,我会通过以下方式查找索引0:word[0],同样对于最后一个字母k,我会用word[4]来做索引4。但是这里的一些东西并没有真正进入我的脑海:我们在最初声明数组时使用了数字5。
所以我的第一个问题是,声明中的5是否意味着程序将使用索引0到5,即索引5将包含空字符。
现在,假设我想定义一个int数组,它包含任何内容,但为了这个问题,它应该包含奇数。我通过键入以下内容来实现:

int odds[5] = {1, 3, 5, 7, 9};

这里也是一样,5是否意味着我们将使用索引0到5,索引5将接受NULL值(是的,这是一个愚蠢的问题,因为它是一个int数组,但至少,第五个索引是否包含值0)作为我的第三个问题,为了使它更通用,是否有一个通用规则,即所有数组都将以值0结束?
对于第一个问题,我看了看网络和一些参考资料,并不能真正找到任何答案,点击。
对于第二个,我尝试打印odds[5]的值,它返回0。然后当我尝试打印odds[6]时,它也返回0,所以我怀疑我得到的第一个答案可能是从odds[4]索引的下一个地址中获取的随机值,而不是在初始化时给定的值。
先谢谢你了。

jgzswidk

jgzswidk1#

如果我们定义一个包含5个字母的单词的字符串,比如Stack,我们可以按照下面的方法来做。
不,你应该做:

char word[6] = "Stack";

甚至更好

char word[] = "Stack";

结束数组没有“一般规则”,但最常见的方法是将长度作为附加参数。Sentinel值有一个明显的缺点,即必须从可能的值集合中选择一个Sentinel值,然后该值不能用作值。

lndjwyie

lndjwyie2#

C中的数组不需要以NULL'\0'0或任何其他特殊值结束。因此char数组(类型char[])也不需要。
然而,在C中,如果char[]类型的对象不是以char'\0'结尾(顺便说一下,它完全等同于0),则不会被认为是“字符串”。如果缺少了它,代码就会崩溃。
顺便说一句,您应该改为编写以下内容之一

char word[5+1] = "Stack";
char word[] = "Stack"; // array size computed by compiler

(as另一个answerer和一个评论者已经指出了)。第二种形式是推荐的,如果你改变了你的代码,它更不容易出错。
对于T[N]数组(其中T是任何类型),使用的索引是0N-1
如果使用字符串文字初始化char数组,则会自动将隐式'\0'添加到末尾,因为

char str[] = "hat";
char str[] = { 'h', 'a', 't', '\0' };

第一行与第二行 * 根据定义 * 等价(编译器自动推断数组大小为4)。这种等价性的权威来源是:

  • K&R(2e),p86
  • C17标准草案,6.7.9初始化

它们给予了非常相似的例子。
注意:对于historical reasons,你可以写char str[3] = "hat";(而不是char str[4] = "hat";char str[] = "hat";),但你真的不应该这样做,因为结果在技术上不是C中的“字符串”。
引用一个越界的数组元素是未定义的行为。在你的例子中,odds[5]odds[6]计算为0只是偶然的。

vuktfyat

vuktfyat3#

这里有两个重要的事实:

  1. C语言中的数组是从0开始的。因此,如果数组的大小为N,则有效索引从0到N-1。在slot [N]中没有元素,并且一般来说,试图访问一个元素是错误的。
  2. C中的字符串是char的数组,有一个特殊的约定:它们以空字符结束,空字符肯定是字符串的一部分,但不计入字符串的长度。
    因此,对于一个字符串(但仅限于字符串),如果字符串的长度为n,则数组的大小必须(至少)为n+1。字符串中的实际字符将从索引0到n-1运行,并且element [n]将是空终止符。
    其他类型的数组(比如int数组)* 不 * 必须以特殊字符结束。可以这样做,尽管有点不寻常。
    关于你的问题:
    所以,我知道字符串的最后一个元素,也就是char数组是NULL,其值为0。
    大多数情况下。字符串的最后一个元素是空字符,即ASCII“NUL”,或者在C中,'\0'。在C中,NULL是一个空 * 指针 *,这是一种不同的野兽。
    如果我们定义一个包含5个字母的单词的字符串,比如Stack,我们可以按照下面的方法来做。
    char word[5] = "Stack";
    不,这不会定义一个正确的字符串。要定义一个正确的字符串,你需要做
char word[6] = "Stack";

为空字符留出空间,或者

char word[] = "Stack";

让编译器为你计算出正确的大小。
但有些事我想不起来我们在最初声明数组时使用了数字5。
对-我的意思是,你感到不安是对的,因为,是的,有些不对劲。
所以我的第一个问题是,声明中的5是否意味着程序将使用索引0到5,即索引5将包含空字符。
不,5意味着数组的索引为0到4,并且没有空字符的空间。
现在假设我想定义一个int数组
好吧,但正如我提到的,在这种情况下没有必要暗示会有终结者。
5是否意味着我们将使用索引0到5,而索引5将采用NULL值?
同样,5意味着你将使用索引0到4来初始化数组的五个值。如果你想使用显式终止符(可能是0或-1),你需要使数组更大,大小至少为6。
是否有一个通用规则,即所有数组都将以值0结束?
不,绝对没有这样的规定。
对于第二个问题,我尝试打印odds[5]的值,它返回0。然后当我尝试打印odds[6]时,它也返回0,所以我怀疑第一个答案
C语言通常不做数组边界检查。所以访问[5]和[6]都是错误的,而且也不知道你会得到什么值--唯一的保证是你 * 不 * 保证会得到错误消息或任何东西。如果你访问一个越界的数组,它通常看起来会工作(你不会得到一个错误消息),有时候这个值甚至看起来是合理的,但不能保证。

slmsl1lt

slmsl1lt4#

请看下面的代码:

#include<stdio.h>
#include<string.h>

int main() {
    char string1[4] = "helo";
    char string2[4] = "bye!";
    printf("%d %s", strlen(string1), string1);
}

Try it online
看到这个输出“helobye!"了吗?这是因为字符串在内存中直接相邻,中间没有空字节。注意,它可以打印更多,在第二个字符串的末尾“碰巧”有一个空字节,但也可能没有,这将导致打印更多的随机垃圾。
出于这个原因,总是声明一个字符串比它的文本内容长1个字节来存储空字节:

#include<stdio.h>
#include<string.h>

int main() {
    char string1[5] = "helo";
    char string2[5] = "bye!";
    printf("%d %s", strlen(string1), string1);
}

Attempt This Online!
C语言中的字符串就是任何以空结束符结尾的字节数组。

是否所有数组都以0结尾?

不,对于一些字符串函数来说,它们希望传递一个指向以0结尾的数组开始的指针。然而,其他人并不关心。大多数数组函数只是将长度作为额外的参数。一些字符串函数也可以接受长度,如果是这样,就不需要空终止符。

如果省略null终止符而使用字符串函数会怎么样

该函数将读取和写入随机内存,直到它偶然遇到空字节。这被认为是一个“缓冲区溢出”错误,并可能导致,其中包括:

  • Segfaults和crashes
  • 输出存储在存储器中的重要秘密
  • Nasal Demons

在没有适当限制长度的情况下写入内存甚至更危险。
小心点!

相关问题