strlen(&string[]) 是如何工作的?
How does strlen(&string[]) work?
这个问题可能有点长。我正在用 C 测试一些字符数组,所以出现了这段代码。
char t[10];
strcpy(t, "abcd");
printf("%d\n", strlen(&t[5]));
printf("Length: %d\n", strlen(t));
现在显然 strlen(&t[5])
产生 3 而 strlen(t)
returns 4.
我知道字符串长度是4,从插入四个字符就可以看出这一点。但是为什么 strlen(&t[5])
return 3?
我的猜测是
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | [=11=]
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
strlen(&t[5])
看6、7、8位组成的字符串的长度(因为第10个字符是NULL终止符对吧)?
好的,那我做了一些实验,稍微修改了一段代码。
char t[10];
strcpy(t, "abcdefghij");
printf("%d\n", strlen(&t[5]));
printf("Length: %d\n", strlen(t));
现在 strlen(&t[5])
产生 5,而 strlen(t)
是 10,正如预期的那样。如果我正确理解字符数组,状态现在应该是
String: a | b | c | d | e | f | g | h | i | j | '[=13=]'
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
为什么这次 strlen(&t[5])
return 5?我已经声明了一个长度为 10 的字符数组,那么,按照上面应用的相同逻辑,结果应该是 4 吗?
此外,我不应该 运行 陷入一些编译器错误,因为 NULL 终止字符实际上位于第 11 位吗?我是 C 的新手,非常感谢任何人的帮助。
首先让我告诉你,你的"assumption"
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | [=10=]
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
不正确。根据您的代码,这些值仅 "guaranteed" 到索引 4,不超过索引 4。
对于第一种情况,在你的代码中
printf("%d\n", strlen(&t[5]));
由于各种原因是错误的,
- 您应该使用
%zu
作为 size_t
类型。
&t[5]
没有指向有效的 string.
以上任何一个(或两者)都会导致undefined behavior并且任何输出都无法证明。
详细说明,定义如
char t[10];
strcpy(t, "abcd");
您为 t
填充了索引 0 到 3,索引 4 包含空终止符。 t[5]
之后的内容是不确定的。
因此,&t[5]
不是指向字符串第一个元素的指针,因此不能用作 strlen()
的参数。
- 它可能 运行 在搜索空终止符时越界并遇到无效的内存访问,并且作为副作用,会产生分段错误,
- 它可能会在边界内找到空终止符(只是另一个垃圾值)并报告 "seemingly" 有效长度。
这两种可能性都是一样的,而且不太可能,真的。 UB就是UB,没有理由。
那么,对于第二种情况,你说的
char t[10];
strcpy(t, "abcdefghij");
再次越界访问内存。
您总共有 10 个数组元素来存储一个字符串,因此您可以有 9 个其他 char
元素,外加一个空终止符(以将 char 数组限定为字符串)。
但是,您正试图放置 10 个 char
元素,外加一个空字符(在 strcpy()
中),所以您是差一个,访问的内存超出限制,调用 UB。
char t[10];
未初始化,因此它仅包含垃圾值 1)。 strcpy(t, "abcd");
用字符串 "abcd" 和空终止符覆盖前 5 个字符。
然而,&t[5]
指向空终止后的第一个字符,这仍然是垃圾。如果你从那里调用 strlen
,任何事情都可能发生,因为传递的指针不太可能指向空终止字符串。
1) 垃圾 = 不确定的值。假设一个健全的 2 的补码系统,缓冲区的地址 t
被采用,因此代码不会调用未定义的行为,直到 strlen
开始读取数组 t
的边界之外. Reference.
问题 1:
My guess is that
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | [=10=]
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
这个假设是错误的。
该数组未初始化为包含 0 个值,但包含一些 "random" 垃圾。
复制 "abcd"
后,数组的上半部分(t[5]
等)仍未触及,由于未定义的行为导致字符串长度为 "random"。
问题 2:
If I understand character arrays correctly, the state should now be
String: a | b | c | d | e | f | g | h | i | j | '[=11=]'
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
又错了。
您的数组仅包含 10 个字符。它们的索引为 0..9。索引 10 超出范围。
您的复制操作可能会导致此布局,也可能会在写越界时崩溃。
但这并没有被编译器检查。如果您 运行 遇到问题,那么它将在 运行 时间内出现。
这个问题可能有点长。我正在用 C 测试一些字符数组,所以出现了这段代码。
char t[10];
strcpy(t, "abcd");
printf("%d\n", strlen(&t[5]));
printf("Length: %d\n", strlen(t));
现在显然 strlen(&t[5])
产生 3 而 strlen(t)
returns 4.
我知道字符串长度是4,从插入四个字符就可以看出这一点。但是为什么 strlen(&t[5])
return 3?
我的猜测是
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | [=11=]
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
strlen(&t[5])
看6、7、8位组成的字符串的长度(因为第10个字符是NULL终止符对吧)?
好的,那我做了一些实验,稍微修改了一段代码。
char t[10];
strcpy(t, "abcdefghij");
printf("%d\n", strlen(&t[5]));
printf("Length: %d\n", strlen(t));
现在 strlen(&t[5])
产生 5,而 strlen(t)
是 10,正如预期的那样。如果我正确理解字符数组,状态现在应该是
String: a | b | c | d | e | f | g | h | i | j | '[=13=]'
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
为什么这次 strlen(&t[5])
return 5?我已经声明了一个长度为 10 的字符数组,那么,按照上面应用的相同逻辑,结果应该是 4 吗?
此外,我不应该 运行 陷入一些编译器错误,因为 NULL 终止字符实际上位于第 11 位吗?我是 C 的新手,非常感谢任何人的帮助。
首先让我告诉你,你的"assumption"
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | [=10=]
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
不正确。根据您的代码,这些值仅 "guaranteed" 到索引 4,不超过索引 4。
对于第一种情况,在你的代码中
printf("%d\n", strlen(&t[5]));
由于各种原因是错误的,
- 您应该使用
%zu
作为size_t
类型。 &t[5]
没有指向有效的 string.
以上任何一个(或两者)都会导致undefined behavior并且任何输出都无法证明。
详细说明,定义如
char t[10];
strcpy(t, "abcd");
您为 t
填充了索引 0 到 3,索引 4 包含空终止符。 t[5]
之后的内容是不确定的。
因此,&t[5]
不是指向字符串第一个元素的指针,因此不能用作 strlen()
的参数。
- 它可能 运行 在搜索空终止符时越界并遇到无效的内存访问,并且作为副作用,会产生分段错误,
- 它可能会在边界内找到空终止符(只是另一个垃圾值)并报告 "seemingly" 有效长度。
这两种可能性都是一样的,而且不太可能,真的。 UB就是UB,没有理由。
那么,对于第二种情况,你说的
char t[10];
strcpy(t, "abcdefghij");
再次越界访问内存。
您总共有 10 个数组元素来存储一个字符串,因此您可以有 9 个其他 char
元素,外加一个空终止符(以将 char 数组限定为字符串)。
但是,您正试图放置 10 个 char
元素,外加一个空字符(在 strcpy()
中),所以您是差一个,访问的内存超出限制,调用 UB。
char t[10];
未初始化,因此它仅包含垃圾值 1)。 strcpy(t, "abcd");
用字符串 "abcd" 和空终止符覆盖前 5 个字符。
然而,&t[5]
指向空终止后的第一个字符,这仍然是垃圾。如果你从那里调用 strlen
,任何事情都可能发生,因为传递的指针不太可能指向空终止字符串。
1) 垃圾 = 不确定的值。假设一个健全的 2 的补码系统,缓冲区的地址 t
被采用,因此代码不会调用未定义的行为,直到 strlen
开始读取数组 t
的边界之外. Reference.
问题 1:
My guess is that
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | [=10=] Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
这个假设是错误的。
该数组未初始化为包含 0 个值,但包含一些 "random" 垃圾。
复制 "abcd"
后,数组的上半部分(t[5]
等)仍未触及,由于未定义的行为导致字符串长度为 "random"。
问题 2:
If I understand character arrays correctly, the state should now be
String: a | b | c | d | e | f | g | h | i | j | '[=11=]' Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
又错了。 您的数组仅包含 10 个字符。它们的索引为 0..9。索引 10 超出范围。 您的复制操作可能会导致此布局,也可能会在写越界时崩溃。
但这并没有被编译器检查。如果您 运行 遇到问题,那么它将在 运行 时间内出现。