我的C代码如下:
char s="MIDSH"[3];
printf("%d\n",strlen(&s));
运行结果是2,这是错误的,因为char s只是一个'S'。
有人知道为什么以及如何解决这个问题吗?
这实际上是一个非常有趣的问题。让我们分开吧:
"MIDSH"[3]
字符串文字具有数组类型。因此,上面将下标运算符应用于数组并计算出第四个字符“S”。然后将其分配给单字符变量
s
。
printf("%d\n",strlen(&s));
由于
s
是单个字符,而不是实际字符串的一部分,因此上述代码的行为未定义。
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
。
声明
printf("%d\n",strlen(&s));
对于给定的情况没有任何意义。
strlen
需要一个空终止字符串,s
属于 char
类型,并且 &s
不一定指向字符串。您得到的是程序未定义行为的结果之一。
要获取
s
的大小,您可以使用 sizeof
运算符
printf("%zu\n", sizeof(s));
strlen
函数将其参数视为指向字符序列的指针,其中该序列以'\0'
字符终止。
通过将指针传递给单字符变量
s
,您实际上可以说 &s
是此类序列中的第一个字符,但事实并非如此。这意味着 strlen
将继续在错误的前提下在内存中搜索,并且您将有 未定义的行为。
当您使用 “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
常量字符串“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 变量的地址,然后将其解释为字符串。