>我正在实现strcmp(char *s, char *t)
,它通过比较两个字符串之间不同的拳头值来实现<0,如果s<t
,则返回0,s>t
如果s==t
,则返回>0。
通过分离后缀增量和关系等于运算符来实现:
for (; *s==*t; s++, t++)
if (*s==' ')
return 0;
return *s - *t;
但是,将后缀增量和关系等于运算符分组不起作用(如下所示):
while (*s++ == *t++)
if (*s==' ')
return 0;
return *s - *t;
后者始终返回 0。我认为这可能是因为我们过早地增加了指针,但即使索引 5/10 处出现的两个字符串存在差异,仍然会产生相同的结果。
示例输入:strcomp("hello world", "hello xorld");
返回值:0
我的预感是这是因为运算符优先级,但我并不肯定,如果是这样,我无法准确指出原因。
谢谢你的时间!
因为在for
循环中,如果条件(在您的情况下*s==*t
)为假,则不会调用增量(在您的情况下s++, t++
)。但是在你的while
循环中,在这种情况下也会调用增量,所以对于strcomp("hello world", "hello xorld")
,两个指针最终都指向字符串中的o
s。
由于您在测试中总是递增s
和t
,因此在字符串相等的情况下,您应该参考终止s[-1]
,如果字符串不同,则应参考s[-1]
和t[-1]
。
另请注意,顺序由比较确定为unsigned char
。
这是一个修改版本:
int strcmp(const char *s, const char *t) {
while (*s++ == *t++) {
if (s[-1] == ' ')
return 0;
}
return (unsigned char)s[-1] - (unsigned char)t[-1];
}
根据 LLchux的评论,这里有一个完全符合的反常架构的实现,具有非二进制补码表示和/或CHAR_MAX > INT_MAX
:
int strcmp(const char *s0, const char *t0) {
const unsigned char *s = (const unsigned char *)s0;
const unsigned char *t = (const unsigned char *)t0;
while (*s++ == *t++) {
if (s[-1] == ' ')
return 0;
}
return (s[-1] > t[-1]) - (s[-1] < t[-1]);
}
每个人都给出了正确的建议,但仍然天生在比较表达式中内联这些增量运算符,并做了 1 件奇怪的事情。
以下内容感觉更简单,更容易阅读。任何指针都不会递增或递减到无效地址。
while ((*s == *t) && *s)
{
s++;
t++;
}
return *s - *t;
为了完整性,除了已经很好地回答了减法过程中的错误偏移量:
当*s, *t
为负数时,*s - *t;
不正确。
标准 C 库指定字符串函数的比较就像char
unsigned char
一样。 因此,当字符为负数时,通过char *
减去的代码会给出错误的答案。
对于此子句中的所有函数,每个字符都应解释为具有类型
unsigned char
(因此每个可能的对象表示都是有效的并且具有不同的值)。 C17DR § 7.24.1 3
int strcmp(const char *s, const char *t) {
const unsigned char *us = (const unsigned char *) s;
const unsigned char *ut = (const unsigned char *) t;
while (*us == *ut && *us) {
us++;
ut++;
}
return (*us > *ut) - (*us < *ut);
}
该代码还解决了非 2 的补码访问 -0 和char
范围超过int
的模糊问题。