这可能是一个有点长的问题。我在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)
返回4。
我知道字符串长度为4,插入四个字符就很明显了。但为什么strlen(&t[5])
会返回3?
我猜是
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | \0
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 | '\0'
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
那么为什么strlen(&t[5])
这次会返回5?我已经声明了一个长度为10的字符数组,那么,应该通过上面应用的相同逻辑,结果是4?
我也不应该遇到一些编译器错误,因为NULL终止字符实际上是在第11位?我是C的新手,非常感谢任何人的帮助。
答案 0 :(得分:4)
首先让我告诉你,你的假设"
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | \0
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
不正确。根据您的代码,这些值只有"保证" 直到索引4,而不是超出此范围。
对于第一种情况,在您的代码中
printf("%d\n", strlen(&t[5]));
出于各种原因是错误的,
%zu
使用size_t
类型。 &t[5]
未指向有效的字符串。上述任何(或两者)导致undefined behavior并且无法证明任何输出。
详细阐述,如
这样的定义char t[10];
strcpy(t, "abcd");
您为t
填充了索引0到3,索引4包含空终止符。 t[5]
以后的内容是不确定的。
因此,&t[5]
不是指向字符串第一个元素的指针,因此不能使用strlen()
的参数。
两者同样可能且不太可能,真的。 UB是UB,没有理由这样做。
然后,对于第二种情况,,你说
char t[10];
strcpy(t, "abcdefghij");
再一次,访问内存越界。
你们共有10个数组元素来存储一个字符串,所以你可以有9个其他char
个元素,加上一个空终止符(将char数组限定为字符串)。
但是,您尝试放置10个char
元素,加上一个空字符(在strcpy()
中),这样您就可以一个接一个地访问越界内存,调用UB。
答案 1 :(得分:2)
char t[10];
未初始化,因此它只包含垃圾值 1)。 strcpy(t, "abcd");
使用字符串“abcd”和空终止符覆盖前5个字符。
但是,&t[5]
指向空终止后的第一个字符,这仍然是垃圾。如果从那里调用strlen
,可能会发生任何事情,因为传递的指针不太可能指向空终止字符串。
1) Garbage =不确定值。假设一个合理的2的补码系统,缓冲区t
的地址被采用,因此代码不会调用未定义的行为,直到strlen
开始读取数组t
的边界之外的点为止。 Reference
答案 2 :(得分:1)
问题1:
我猜是
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | \0 Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
这个假设是错误的。
数组未初始化为保持0值,但包含一些"随机"垃圾。
在复制"abcd"
之后,数组的上半部分(t[5]
等)仍然未被触及,导致随机的"由于未定义的行为导致的字符串长度。
问题2:
如果我正确理解了字符数组,那么状态现在应该是
String: a | b | c | d | e | f | g | h | i | j | '\0' Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
又错了。 您的数组只包含10个字符。它们在0..9指数。索引10超出范围。 您的复制操作可能会导致此布局,或者在写出越界时也可能会崩溃。
但是编译器没有检查过。如果遇到问题,那么它将在运行期间出现。