您的字符串长度应该是您希望它能够容纳的最大字符数。足够逻辑:字符串以NULL
字符终止。
这是大多数新手得到的一般建议。然而,随着我在编程方面的发展,现在似乎并不是那么正确。
任何类型的数组(int
或char
)的索引从0
开始。因此,大多数数组的最大索引值比其数值小1。它与字符串相同,但由于它在末尾有一个额外的字符,它会增加1。因此,字符串长度与其中的字符数相同。
要查看我是否正确,请参阅以下代码段:
char str[9];
scanf("%s", str);
printf("%d", strlen(str));
使这个成为一个完整的程序,然后运行它。输入123456789
,保证9个字符的长文本,然后查看结果。它可以保存字符串,当然,字符串长度为9
。
我甚至目睹了许多专家程序员说字符串大小应该加上其容量。这个建议在很大程度上是一个神话,或者我在某个地方出错了?
我想说我想创建一个可以容纳Arr
个元素的整数数组x
。由于索引值从Arr
开始而不是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]
?
答案 0 :(得分:4)
根据C标准相对于转换说明符s
的描述(7.21.6.2 fscanf函数)
s匹配一系列非空白字符.279)如果没有l长度 修改器存在,相应的参数应为指针 字符数组的初始元素足以接受 序列和一个终止空字符,将被添加 自动强>
因此,如果要输入字符序列123456789
,则会尝试编写以下字符“
{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '\0' }`
声明为的数组中的
char str[9];
如图所示,序列包含10个字符,而数组只能容纳9个字符。因此,数组之外的内存将被覆盖,因此程序具有未定义的行为。
在与C ++相反的C中,您可以通过以下方式初始化字符数组
char str[3] = "Bye";
在这种情况下,终止零将不会用作数组的初始值设定项。也就是说,数组不包含字符串,只包含字符
{ 'B', 'y', 'e' }
但是,您可能不会将标准C函数strlen
应用于此数组,因为该函数会对字符进行计数,直到遇到终止零并且数组没有这样的字符。
您应该区分sizeof
运算符返回的值和标准C函数strlen
返回的值。
例如,如果您有这样的声明
char str[10] = "Hello";
然后sizeof
运算符sizeof( str )
返回10,即数组有10个大小等于1的元素(sizeof( char)
总是等于1)。
但是,如果您将应用标准C函数strlen
,则返回的值将等于5,因为该函数会在终止零之前计算所有字符。
您可以编写例如
str[8] = 'A';
然而,如果ypu应用函数strlen
,您将再次获得值5,因为在元素str[8]
之前,值为'A'
,存在终止零。
答案 1 :(得分:4)
你对索引是正确的。但是:
char str[9];
以这种方式声明字符串时,数字9
是数组长度。减去NULL,只能有8个字符,而不是9.数组的长度是数组中元素的数量,而不是您认为的最大索引值。你会混淆这些条款。
为什么你的程序可以解释许多其他答案甚至评论。
答案 2 :(得分:2)
任何类型的数组(无论是int还是char)的索引都从0开始。
是的,那是真的。
因此,所有数组大小都比它们的数值小一个。
没有。用于索引的第一个值仅影响索引,而不是大小。例如,1大小的数组只有一个索引0.它是最大索引值,比索引大小小一个,而不是相反。
在声明char str[9];
中,值9是数组大小,而不是最大索引值。
您的示例似乎起作用的原因是,未定义的行为不会 导致崩溃或错误消息。
答案 3 :(得分:1)
你是对的,数组索引从0开始,但是一个char str [9]的长度为9,所以最高的索引是8.你的例子似乎有效,但它很容易造成错误。您也可以在代码中键入1234567890,它将输出10,因为程序无法知道数组的长度。
当您定义该char数组时,您在堆栈上为它创建一个9字节的空间,但是当您将它传递给scanf时,char []会转换为char *指向数组中第一个元素的指针。因此,scanf无法知道数组的长度,并将输入写入内存,从str指向的位置开始。它将\ 0字符写在为数组保留的空间之外!但是当它再次传递给strlen时,它无法看到数组的大小并继续扫描内存中的\ 0,它在10个字节后找到,所以它假设长度为10。
像@Ajay一样,Brahmakshatriya在他的回答中表明这可能导致错误,因为字符串外部的空间可以用于另一个变量,例如另一个字符串,然后可以将不同的数据写入\ 0的字节。
答案 4 :(得分:0)
看到这个 - > Ideone
int main(void) {
char a[16];
char b[16];
scanf("%s",a);
b[0]='a';
b[1]='\0';
printf("%s %d %p %p", a, strlen(a), a, b);
return 0;
}
这几乎是您展示的代码的副本。对于16长度的给定输入(数组大小也为16),打印的长度为17。
现在我们已经确定你所说的不正确,我们将看看为什么它为你打印9而不是我发布的例子。
您创建了大小为9的数组(分配了9个字节)。
然后,您将9个字节的数据存储到其中,并通过在第十个字节上写入的'\0'
终止它。由于任何(幸运的)重要的是没有使用该空间,因此数据适合。
然后当你打电话给strlen
时,它给了你9个。
现在我创建了一个16字节的数组,然后跟着另一个放在它后面的数组。现在当它读取16个字节并用'\0'
终止它时,它写入了b。
我写信给b再次覆盖了它。
由'\0'
撰写的scanf
已经消失。
然后strlen
计算长度溢出到b并在看到'\0'
b[1]
时停止。
所有这些都是未定义的行为。
答案 5 :(得分:0)
...因此,字符串长度与其中的字符数相同。
如果我们将终止null视为字符,则此语句是正确的。但是,保存字符串所需的存储空间比其中的字符数多一个。 (强调'字符串'是因为作为数据类型的字符串需要额外的终止空值,这需要存储。)
答案 6 :(得分:-1)
试图证明我的观点:
#include <stdio.h>
#include <string.h>
int main()
{
char str[23];
scanf("%s", str);
printf("String length = %d\n", strlen(str));
printf("String element --- Index number");
int index=0;
while (str[i]!='\0')
{
printf("\n%c --- %d", str[i], index);
i++;
}
printf("\nNULL === %d", index);
return 0;
}
graphing
String length = 8
String element --- Index number
g --- 0
r --- 1
a --- 2
p --- 3
h --- 4
i --- 5
n --- 6
g --- 7
NULL === 8