我正在尝试逐个比较字符。我正在从类的赋值中模拟 strcmp 函数。这是我的想法。不幸的是,我一直得到 0,因为所有字符都匹配,直到它到达最后一个。我假设它只检查第一个字符并停止。我将 i++ 添加到下一个字符中,但我认为它不起作用。
strComp("abc", "abcd");
int strComp(char a[], char b[]) {
int i = 0;
if (strLen(a) == strLen(b)) {
while (a[i] != NULL && b[i] != NULL) {
if (a[i] == b[i]) {
return 0;
} else if(a[i] > b[i]) {
return 1;
} else {
return -1;
}
}
i++;
} else if (strLen(a) > strLen(b)) {
return 1;
} else {
return -1;
}
}
注意
-
NULL
不同于' '
-
char[]
真的腐烂成char*
- 在 C/C++ 中,任何可以
const
的东西都应声明const
- 在这样的基本函数中使用
strlen
效率低下
这是一个非常快速的解决方案:
inline int compare(char const* const a, char const* const b)
{
/* Return -1 less than, 0 equal, 1 greater than */
if (!a[0] && b[0])
return -1;
else if (a[0] && !b[0])
return 1;
register int i = 0;
for (; a[i] && b[i]; i++) {
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
#if 1 /* this addition makes this code work like std::strcmp */
if (!a[i] && b[i])
return -1;
else if (a[i] && !b[i])
return 1;
#endif
return 0;
}
这个我在 20 年前编码了更多,作为 386 汇编程序的原型。对于不区分大小写的字符串,比较#include <locale>
并修改 for 循环:
.
.
for (; a[i] && b[i]; i++) {
if (std::toupper(a[i]) < std::toupper(b[i]))
return -1;
if (std::toupper(a[i]) > std::toupper(b[i]))
return 1;
}
Put
++i;
在 while 循环内
上面只有 2 行...
只要看到两个不同的字符,就可以检测到不匹配 - 但是在到达字符串末尾并且字符仍然相同之前,您无法检测到匹配项。
至少在我看来,大多数尝试都是向后获得基本思想,试图立即比较字符(一个或两个字符串的一些特殊大小写为空)。相反,通常最好从跳过相等的非零字节开始。然后,您要么位于(至少一个)字符串的末尾,要么发现两个字符串中的字节不匹配。无论哪种方式,此时您都可以整理出正在发生的事情,并返回正确的值。
int cmp_str(char const *a, char const *b) {
while (*a && *a == *b) {
++a;
++b;
}
if (*b < *a)
return 1;
if (*b > *a)
return -1;
return 0;
}
这使得循环非常简单,条件很少,因此可以快速执行。所有更复杂的比较来计算实际顺序都发生在循环之外,它们只发生一次,对速度几乎没有影响。
我可能应该补充一个警告:这并没有试图正确处理国际字符。为此,您只需要添加定义字符相对顺序的整理表,因为(至少在许多代码页中)字符的值与字符的排序顺序不对应。
对于它的价值,这里有一个快速测试,将结果和速度与Andreas的compare
和标准库中的strcmp
进行比较:
int cmp_str(char const *a, char const *b) {
while (*a && *a == *b) {
++a;
++b;
}
if (*b < *a)
return 1;
if (*b > *a)
return -1;
return 0;
}
inline int compare(char const* const a, char const* const b)
{
/* Return -1 less than, 0 equal, 1 greater than */
if (!a[0] && b[0])
return -1;
else if (a[0] && !b[0])
return 1;
register int i = 0;
for (; a[i] && b[i]; i++) {
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
#if 1 /* this addition makes this code work like std::strcmp */
if (!a[i] && b[i])
return -1;
else if (a[i] && !b[i])
return 1;
#endif
return 0;
}
#ifdef TEST
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
int main(){
char *s1 [] = { "", "a", "one", "two", "three", "one", "final" };
char *s2 [] = { "x", "b", "uno", "deux", "three", "oneone", "" };
for (int i = 0; i < 7; i++) {
printf("%dt", cmp_str(s1[i], s2[i]));
printf("%dt", compare(s1[i], s2[i]));
printf("%dn", strcmp(s1[i], s2[i]));
}
// Test a long string:
static const int size = 5 * 1024 * 1024;
static char s3[size];
for (int i = 0; i < size - 1; i++)
s3[i] = (rand() % 254) + 1;
s3[size - 1] = ' ';
static char s4[size];
strcpy(s4, s3);
s3[size - 5] = (s3[size - 5] + 4) % 255;
clock_t start = clock();
int val1 = cmp_str(s3, s4);
clock_t t1 = clock() - start;
start = clock();
int val2 = compare(s3, s4);
clock_t t2 = clock() - start;
start = clock();
int val3 = strcmp(s3, s4);
clock_t t3 = clock() - start;
double v1 = (double) t1 / CLOCKS_PER_SEC;
double v2 = (double) t2 / CLOCKS_PER_SEC;
double v3 = (double) t3 / CLOCKS_PER_SEC;
printf("Jerry: %d, %fnAndreas: %d, %fnstdlib: %d, %fn", val1, v1, val2, v2, val3, v3);
}
#endif
结果:
-1 -1 -1
-1 -1 -1
-1 -1 -1
1 1 1
0 0 0
-1 -1 -1
1 1 1
Jerry: 1, 0.007000
Andreas: 1, 0.010000
stdlib: 1, 0.007000
由于 Andreas 已经更正了他的代码,所有三个测试都产生了相同的结果,但这个版本和标准库比 Andreas 的版本快 30% 左右。不过,这确实因编译器而异。使用 VC++,我的代码几乎与标准库中的代码匹配(但是如果我使用一个巨大的字符串,例如 200 兆字节,则标准库中的版本要好得多。使用 g++,标准库中的代码似乎比 VC++ 标准库中的代码慢一点,但它为 Andreas 的代码或我的代码生成的结果比 VC++ 为他们生成的要差得多。在 200 MB 的字符串上,我使用 VC++ 得到以下结果:
Jerry: 1, 0.288000
Andreas: 1, 0.463000
stdlib: 1, 0.256000
。但是使用 g++ (MinGW),我得到这样的结果:
Jerry: 1, 0.419000
Andreas: 1, 0.523000
stdlib: 1, 0.268000
尽管无论哪种方式的排名都保持不变,但标准库和我的代码之间的速度差异使用 g++ 比使用 VC++ 要大得多。
关于你的代码,我必须说两件事:
-
i++
需要进入循环内部,但你应该使用++i
,这取决于编译器i++
可能比++i
慢。 - 它足够
while (a[i])
而不是while (a[i] != NULL && b[i] != NULL)
,因为a
和b
长度相等。
只是因为你回来得太早了。在函数中执行返回后,控件将返回到调用它的位置。
在这种情况下,您将在 while 循环中返回,这是一个逻辑错误。让我们在这里举个例子。首先,它将比较 a[0] 和 b[0],它将根据您的代码在所有三种情况下返回。即 a[0]b[0] 返回 1,否则返回 0...你必须改变整个功能。我会根据需要编辑您的函数,请稍候
int strComp(char a[], char b[]) {
int i = 0;
if (strLen(a) == strLen(b)) {
while (a[i] != NULL && b[i] != NULL) {
if (a[i] == b[i]) {
return 0;
} else if(a[i] > b[i]) {
return 1;
} else {
return -1;
}
}
i++;
} else if (strLen(a) > strLen(b)) {
return 1;
} else {
return -1;
}
}
编辑的代码(PS:请检查我没有尝试过):
int strComp(char a[], char b[])
{
int i = 0;
while (a[i]!=' '&&b[i]!=' ')
{
if(a[i] > b[i])
{
return 1;
}
else if (a[i] < b[i])
{
return -1;
}
i++; //place i++ here
}
if(a[i]==b[i])
return 0; //if string are equal
if(a[i]==' ')
return -1;
else
return 1;
}