Soh*_*ine -8 c string indexing
您的字符串长度应该比您希望它能够容纳的最大字符数多一。足够合乎逻辑:字符串以NULL字符结尾。
这是大多数新手都会得到的非常笼统的建议。但是,随着我在编程方面的成长,现在似乎不太正确。
任何类型数组的索引,无论是int还是char,都从0. 因此,大多数数组的最大索引值比其数值小 1。它与字符串相同,但由于它在末尾有一个额外的字符,因此它会增加 1。因此,字符串长度与其中的字符数相同。
要查看我是否正确,请参阅此代码段:
char str[9];
scanf("%s", str);
printf("%d", strlen(str));
Run Code Online (Sandbox Code Playgroud)
使它成为一个成熟的程序,然后运行它。键入123456789,保证 9 个字符的长文本,然后查看结果。它可以容纳字符串,果然,字符串长度是9.
我什至亲眼目睹了许多专家程序员说字符串大小应该加上其容量。这个建议在很大程度上是一个神话,还是我在某个地方出错了?
假设我想创建一个Arr可以容纳x多个元素的整数数组。Arr的最后一个元素的索引值将小于 1,x因为索引值开始于0并且不是1。所以,它的长度是x-1。
那你怎么声明呢?我是这样做的:int Arr[x-1];。我不认为这有任何问题。
现在,如果Arr是一个char类型数组(即字符串),则 的长度Arr将比其int对应的长度多一,因为它在末尾有一个额外的 NULL 字符。这将最终为:(x-1)+1=x。
那么为什么这次声明必须是,char Arr[x+1]而不是简单的char Arr[x]?
小智 6
你是对的索引。然而:
char str[9];
Run Code Online (Sandbox Code Playgroud)
当你以这种方式声明一个字符串时,数字9就是数组长度。减去 NULL,只能有 8 个字符,而不是 9 个。数组的长度是数组中元素的数量,而不是您认为的最大索引值。你混淆了这些术语。
许多其他答案甚至评论已经解释了为什么您的程序有效。
根据C标准相对于转换说明符的描述s(7.21.6.2 fscanf函数)
s 匹配非空白字符序列。279) 如果不存在 l 长度修饰符,则相应的参数应是指向字符数组的初始元素的指针,该元素的大小足以接受该序列和终止空字符,将自动添加。
因此,如果要输入字符序列,123456789则将尝试写入以下字符`
{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '\0' }`
Run Code Online (Sandbox Code Playgroud)
在声明的数组中
char str[9];
Run Code Online (Sandbox Code Playgroud)
可以看出,序列包含 10 个字符,而数组只能容纳 9 个字符。因此数组之外的内存将被覆盖,结果程序具有未定义的行为。
在与 C++ 相对的 C 中,您可以通过以下方式初始化字符数组
char str[3] = "Bye";
Run Code Online (Sandbox Code Playgroud)
在这种情况下,终止零不会用作数组的初始值设定项。那就是数组将不包含字符串而只包含字符
{ 'B', 'y', 'e' }
Run Code Online (Sandbox Code Playgroud)
但是,您可能不会将标准 C 函数strlen应用于此数组,因为该函数会计算字符数,直到遇到终止零并且该数组没有这样的字符。
您应该区分sizeof运算符返回的值和标准 C 函数返回的值strlen。
例如,如果您有这样的声明
char str[10] = "Hello";
Run Code Online (Sandbox Code Playgroud)
然后sizeof运算符sizeof( str )返回 10,即数组有 10 个大小等于 1 的元素(sizeof( char)始终等于 1)。
但是,如果您将应用标准 C 函数,strlen 则返回值将等于 5,因为该函数计算终止零之前的所有字符。
你可以写例如
str[8] = 'A';
Run Code Online (Sandbox Code Playgroud)
尽管如此,如果 ypu 应用该函数,strlen您将再次获得值 5,因为在str[8]具有该值的元素之前'A'有一个终止零。