strlen(& string [])如何工作?

时间:2018-01-23 14:03:26

标签: c arrays string char strlen

这可能是一个有点长的问题。我在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的新手,非常感谢任何人的帮助。

3 个答案:

答案 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超出范围。 您的复制操作可能会导致此布局,或者在写出越界时也可能会崩溃。

但是编译器没有检查过。如果遇到问题,那么它将在运行期间出现。