我已经看到strlen的标准实现使用指针:
int strlen(char * s) {
char *p = s;
while (*p!='\0')
p++;
return p-s;
}
我得到了这个功能,但是当我尝试使用另外3种方法(现在学习指针算法)时,我想知道它们有什么问题吗?
这有点类似于本书的内容。这是错的吗?
int strlen(char * s) {
char *p = s;
while (*p)
p++;
return p-s;
}
我虽然如果我传递一个空字符串但仍然给我0,那会是错误的,有点令人困惑,因为p是预增量:(现在它返回给我5)
int strlen(char * s) {
char *p = s;
while (*++p)
;
return p-s;
}
想出这个,后期增加并返回+1。
int strlen(char * s) {
char *p = s;
while (*p++)
;
return p-s;
}
答案 0 :(得分:1)
1)对我来说很好看。我个人更喜欢与'\ 0'进行显式比较,因此很明显你并不意味着(例如)在从上下文中不清楚的情况下将p
与NULL指针进行比较。
2)程序运行时,称为堆栈的内存区域未初始化。局部变量存在于那里。你编写程序的方式是将p
放入堆栈中(如果你使用const
或使用malloc
,它几乎肯定会在其他地方生活)。当你看*p
时会发生什么,然后你会看到堆栈。如果字符串的长度为0,则与char p[1] = {0}
相同。预递增会在\0
之后立即查看字节,因此您正在查看未定义的内存。这是龙!
3)我不认为那里有一个问题:)如你所见,它总是返回一个而不是正确的答案。
附录:如果您更喜欢这种风格,也可以使用for循环编写:
size_t strlen(char * s) {
char *p = s;
for (; *p != '\0'; p++) {}
return p - s;
}
或(更容易发生错误)
size_t strlen(char * s) {
char *p = s;
for (; *p != '\0'; p++);
return p - s;
}
此外,strlen不能返回负数,因此您应该使用无符号值。 size_t
甚至更好。
答案 1 :(得分:0)
第1版很好 - while (*p != 0)
相当于while (*p)
,相当于p
。
在原始代码和版本1中,如果,指针*p
会提前,且仅当 0
不是p
时(IOW,你不是在字符串的末尾)。
版本2和3提前*p
,无论 0
是否为*p++
。 p
评估字符p
指向,副作用指数*++p
。 p
评估字符p
指向后的字符,并且副作用会提前p
。因此,版本2和版本3将始终超过字符串末尾{{1}},这就是您的值已关闭的原因。
答案 2 :(得分:-1)
比较strlen
替换函数的性能时遇到的一个问题是,与长字符串的实际strlen
函数相比,它们的性能会受到影响吗?为什么? strlen
在搜索字符串结尾时每次迭代处理超过一个字节。如何实现更有效的替代?
这并不困难。基本方法是查看每次迭代4个字节,并根据找到 nul-byte 的4个字节内的位置调整返回值。您可以执行以下操作(使用数组索引):
size_t strsz_idx (const char *s) {
size_t len = 0;
for(;;) {
if (s[0] == 0) return len;
if (s[1] == 0) return len + 1;
if (s[2] == 0) return len + 2;
if (s[3] == 0) return len + 3;
s += 4, len += 4;
}
}
你可以使用指针和掩码做同样的事情:
size_t strsz (const char *s) {
size_t len = 0;
for(;;) {
unsigned x = *(unsigned*)s;
if((x & 0xff) == 0) return len;
if((x & 0xff00) == 0) return len + 1;
if((x & 0xff0000) == 0) return len + 2;
if((x & 0xff000000) == 0) return len + 3;
s += 4, len += 4;
}
}
无论哪种方式,您都会发现4字节的比较,每次迭代都会为您提供与strlen
本身相当的性能。