为什么 C 函数 strlen() 返回错误的 char 长度?

问题描述 投票:0回答:6

我的C代码如下:

char s="MIDSH"[3];
printf("%d\n",strlen(&s));

运行结果是2,这是错误的,因为char s只是一个'S'。

有人知道为什么以及如何解决这个问题吗?

c string strlen
6个回答
10
投票

这实际上是一个非常有趣的问题。让我们分开吧:

"MIDSH"[3]

字符串文字具有数组类型。因此,上面将下标运算符应用于数组并计算出第四个字符“S”。然后将其分配给单字符变量

s

printf("%d\n",strlen(&s));

由于

s
是单个字符,而不是实际字符串的一部分,因此上述代码的行为未定义。


8
投票

strlen
的签名是:

size_t strlen(const char *s);
/* The strlen() function calculates the
   length of the string s, excluding the
   terminating null byte ('\0'). */

strlen
期望输入
const char array
以 null 终止。但是,当您传递
auto
变量的地址时,您无法保证这一点,因此您的程序具有 未定义的行为

有人知道为什么以及如何解决这个问题吗?

sizeof(char)
保证是
1
。因此请使用
sizeof
1


6
投票

声明

printf("%d\n",strlen(&s));  

对于给定的情况没有任何意义。

strlen
需要一个空终止字符串,
s
属于
char
类型,并且
&s
不一定指向字符串。您得到的是程序未定义行为的结果之一。

要获取

s
的大小,您可以使用
sizeof
运算符

printf("%zu\n", sizeof(s)); 

4
投票

strlen
函数将其参数视为指向字符序列的指针,其中该序列以
'\0'
字符终止。

通过将指针传递给单字符变量

s
,您实际上可以说
&s
是此类序列中的第一个字符,但事实并非如此。这意味着
strlen
将继续在错误的前提下在内存中搜索,并且您将有 未定义的行为


1
投票

当您使用 “char s=”你在堆栈上为's'创建了一个新地址,并且这个地址不能被添加或减少!所以虽然你给strlen一个char*但它无法通过添加地址找到''。是错的。 你应该使用 strlen 和 char 的地址,它是一个数组。像:

char* s = "MIDSH";
printf("%d\n", strlen(s)); //print 5
s++;
printf("%d\n", strlen(s)); //print 4

0
投票

常量字符串“MIDSH”末尾有一个不可见的终止符,所以它实际上是 MIDSH0。

[3] 返回从 0 开始的数组中的第四项。

接下来发生的事情取决于编译器,以及“相等”(Lisp 中的 EQUAL)和“相同”(Lisp 中的 EQ)之间的区别。 通常,单个 char 将是不同的内存位置。 'S' 的内容将被复制到 s 中,作为一个“相等”但不同的值。 然后,当您使用 &s 获取变量 char 的地址并将其提供给 strlen 时,strlen 将继续查找该单个 char 之后的下一个内存位置,直到找到 0 字节,然后将该长度返回给您。 这是完全未定义的,可能会导致越界内存段错误。 但是,在这种非常不寻常的情况下,看起来如果您正在使用优化编译器并且没有对此进行其他计算。 显然,编译器没有创建新的内存位置,而是偷懒,只是将第四个字符的地址分配给变量 char 。 在这种情况下, char s 与第四个字符

相同。 然后,当获取 s 的地址时,你得到了第四个字符 S 的地址。获取该地址并将其输入 strlen,你得到 SH0; 0 不计入长度,所以你得出的答案是 2。 这是极其出乎意料且偶然的行为。 自己使用字符串指针进行编码要好得多, char *p = mystring+3; strlen(p); ,而不是尝试获取单个 char 变量的地址,然后将其解释为字符串。

© www.soinside.com 2019 - 2024. All rights reserved.