对 strlen 在 C 中的工作方式感到困惑
Confused with how strlen works in C
最近一直在学习C语言,看到一个strlen的源码,把我搞糊涂了,不得不去其他地方查了下,还是没看懂。
strlen:
#include <stdio.h>
int strlen(const char *str)
{
const char* eos = str; // 1
while (*eos++); // 2
return (eos - str - 1); // 3
}
int main()
{
int len = strlen("Hello");
printf("Len: %d" , len);
return 0;
}
我不明白为什么我们要使用局部变量 eos 以及为什么我们要在一个空的 while 循环中使用它然后从 strlen 函数返回最后一行?
为什么会有一个空的while循环?循环递增eos
,直到它直接指向null终止符之后的位置。表达式 *eos++
是告诉您的计算机获取当前指向的字符值 eos
的非常紧凑的方式,然后递增 eos
使其指向下一个字符。这个while循环不需要body。
为什么要使用局部变量?因为我们是递增一个指针(即eos
),而且我们还需要一个指向字符串开头的指针在最后的计算中(即 str
),我们不能简单地对所有内容使用 str
。我们至少需要一个其他变量来完成这项工作。
最后一行是如何工作的?表达式eos - str
做指针减法,所以它计算这两个指针和returns之间的距离作为一个整数。然后我们减去1使答案正确。
指针eos
用于沿着字符串前进。 EOS 是字符串结尾的缩写。 while
循环是空的,因为它不需要做任何事情——因为只需要推进指针。一旦 eos
指向空终止符,循环就会退出。然后函数的最后一行从开始指针中减去结束指针,得到 eos
移动过去的字符数。最后一个 -1
是为了纠正这样一个事实,即由于 post 递增运算符,eos
总是比应有的提前一个字符。
一个不那么令人困惑的实现是:
int strlen(const char *str)
{
const char* eos = str; // 1
while (*eos)eos++; // 2
return (eos - str); // 3
}
对于初学者来说,函数 return 类型应该是 size_t
。
size_t strlen(const char *str);
如果两个指针指向同一数组的元素,则指向具有较高索引的元素的指针与指向具有较低索引的元素的指针之间的差异产生两个索引之间的元素数。
例如,如果你有一个像
这样的数组
const char s[] = "12";
和两个指针
const char *p1 = &s[0];
const char *p2 = &s[1];
那么差
p2 - p1
产生值 1
。
原函数内的this指针
const char* eos = str;
将在传递的字符串中移动,直到找到终止零字符。
while (*eos++);
这个循环可以改写成
while ( *eos++ != '[=16=]' );
后缀表达式的值*esp++
是指针递增前指向字符的值。
因此,当找到终止零时,指针 eos
将指向终止零字符之后的内存,并且循环停止迭代。
因此现在指针 str
指向传递的字符串的开头,指针 eos
指向终止零字符 '[=24=]'
之后的内存。
所以区别
(eos - str - 1)
给出传递的字符串中终止零字符之前的字符数 '[=24=]'
。
中的字符串是由所谓的空字符终止的字符数组;记住这一点也很有用,因为在 C 中没有明确的字符串类型,如果你想对你作为字符串处理的字符数组进行操作,你需要有一个指向第一个字符的指针。
话虽如此,eos
变量被初始化为指向字符串的开头(通过将其等同于 str
- 请记住,它们都只是指向字符的指针,因此等同于他们意味着他们指向同一件事)。
现在,'empty' while 循环有副作用。因为递增 (++
) 运算符用于评估条件,所以 eos
递增 - 因为它是一个指针,这意味着在循环的每次迭代中,eos
指向连续人物。它基本上是 'walking' 沿着字符串。
这一直持续到循环条件的计算结果为 false
。在 C 语言中,只有空字符的计算结果为假(对于所有可能的字符值;更一般地说,零为假,非零为真)。所以基本上,eos 将在字符串末尾停止递增。
现在进入 return
语句。此时我们有两个变量——一个名为 str
的变量仍然指向字符串的开头,另一个名为 eos
的变量指向字符串的结尾。好吧 - 实际上 eos
由于在循环条件中完成的递增而溢出。这里准确的说是指向字符串末尾空字符后的内存地址。
所以,通过更多的指针运算,如果我们从 eos
中减去 str
,然后减去溢出的 1...那么,我们得到地址的差异最后一个和第一个字符,即字符串的长度。
很奇怪在循环中使用了post-增量运算符。如果它被编码为 while (*++eos);
,即使用 pre-increment 运算符,则递增将发生在 before 评估 eos
这意味着它不会超出字符串的末尾并且不需要在 return
语句中减去额外的 1 。好吧。
最近一直在学习C语言,看到一个strlen的源码,把我搞糊涂了,不得不去其他地方查了下,还是没看懂。
strlen:
#include <stdio.h>
int strlen(const char *str)
{
const char* eos = str; // 1
while (*eos++); // 2
return (eos - str - 1); // 3
}
int main()
{
int len = strlen("Hello");
printf("Len: %d" , len);
return 0;
}
我不明白为什么我们要使用局部变量 eos 以及为什么我们要在一个空的 while 循环中使用它然后从 strlen 函数返回最后一行?
为什么会有一个空的while循环?循环递增eos
,直到它直接指向null终止符之后的位置。表达式 *eos++
是告诉您的计算机获取当前指向的字符值 eos
的非常紧凑的方式,然后递增 eos
使其指向下一个字符。这个while循环不需要body。
为什么要使用局部变量?因为我们是递增一个指针(即eos
),而且我们还需要一个指向字符串开头的指针在最后的计算中(即 str
),我们不能简单地对所有内容使用 str
。我们至少需要一个其他变量来完成这项工作。
最后一行是如何工作的?表达式eos - str
做指针减法,所以它计算这两个指针和returns之间的距离作为一个整数。然后我们减去1使答案正确。
指针eos
用于沿着字符串前进。 EOS 是字符串结尾的缩写。 while
循环是空的,因为它不需要做任何事情——因为只需要推进指针。一旦 eos
指向空终止符,循环就会退出。然后函数的最后一行从开始指针中减去结束指针,得到 eos
移动过去的字符数。最后一个 -1
是为了纠正这样一个事实,即由于 post 递增运算符,eos
总是比应有的提前一个字符。
一个不那么令人困惑的实现是:
int strlen(const char *str)
{
const char* eos = str; // 1
while (*eos)eos++; // 2
return (eos - str); // 3
}
对于初学者来说,函数 return 类型应该是 size_t
。
size_t strlen(const char *str);
如果两个指针指向同一数组的元素,则指向具有较高索引的元素的指针与指向具有较低索引的元素的指针之间的差异产生两个索引之间的元素数。
例如,如果你有一个像
这样的数组const char s[] = "12";
和两个指针
const char *p1 = &s[0];
const char *p2 = &s[1];
那么差
p2 - p1
产生值 1
。
原函数内的this指针
const char* eos = str;
将在传递的字符串中移动,直到找到终止零字符。
while (*eos++);
这个循环可以改写成
while ( *eos++ != '[=16=]' );
后缀表达式的值*esp++
是指针递增前指向字符的值。
因此,当找到终止零时,指针 eos
将指向终止零字符之后的内存,并且循环停止迭代。
因此现在指针 str
指向传递的字符串的开头,指针 eos
指向终止零字符 '[=24=]'
之后的内存。
所以区别
(eos - str - 1)
给出传递的字符串中终止零字符之前的字符数 '[=24=]'
。
中的字符串是由所谓的空字符终止的字符数组;记住这一点也很有用,因为在 C 中没有明确的字符串类型,如果你想对你作为字符串处理的字符数组进行操作,你需要有一个指向第一个字符的指针。
话虽如此,eos
变量被初始化为指向字符串的开头(通过将其等同于 str
- 请记住,它们都只是指向字符的指针,因此等同于他们意味着他们指向同一件事)。
现在,'empty' while 循环有副作用。因为递增 (++
) 运算符用于评估条件,所以 eos
递增 - 因为它是一个指针,这意味着在循环的每次迭代中,eos
指向连续人物。它基本上是 'walking' 沿着字符串。
这一直持续到循环条件的计算结果为 false
。在 C 语言中,只有空字符的计算结果为假(对于所有可能的字符值;更一般地说,零为假,非零为真)。所以基本上,eos 将在字符串末尾停止递增。
现在进入 return
语句。此时我们有两个变量——一个名为 str
的变量仍然指向字符串的开头,另一个名为 eos
的变量指向字符串的结尾。好吧 - 实际上 eos
由于在循环条件中完成的递增而溢出。这里准确的说是指向字符串末尾空字符后的内存地址。
所以,通过更多的指针运算,如果我们从 eos
中减去 str
,然后减去溢出的 1...那么,我们得到地址的差异最后一个和第一个字符,即字符串的长度。
很奇怪在循环中使用了post-增量运算符。如果它被编码为 while (*++eos);
,即使用 pre-increment 运算符,则递增将发生在 before 评估 eos
这意味着它不会超出字符串的末尾并且不需要在 return
语句中减去额外的 1 。好吧。