对于家庭作业,我需要实现一个函数,它接受char *s
和char c
并返回c的索引(如果找到),否则返回-1。
这是我的第一次尝试:
int IndexOf(const char *s, char c) {
for (int i = 0; *s != '\0'; ++i, ++s) {
if (*s == c) {
return i;
}
}
return -1;
}
这是一个好的实现,还是有待改进的地方?
编辑 Sry,没有提到我只应该使用指针算术/解除引用,而不是像s [i]。此外,不允许使用标准库。
答案 0 :(得分:3)
是的,没关系,但你只能增加一个变量:
int IndexOf(const char *s, char c) {
for (int i = 0; s[i] != '\0'; ++i) {
if (s[i] == c) {
return i;
}
}
return -1;
}
不会产生任何严重的差异,主要是品味。
答案 1 :(得分:2)
这是一种在不跟踪索引的情况下执行此操作的方法:
int IndexOf(const char *s, char c) {
const char *p = s;
while (*p != '\0') {
if (*p == c) {
return p - s;
}
++p;
}
return -1;
}
这不一定比您的解决方案更好。只是演示了另一种使用指针算法的方法。
FWIW,我会定义函数来返回size_t
而不是int
。此外,对于实际使用(不是家庭作业),如果s
是NULL指针,您可能想要考虑正确的行为。
答案 2 :(得分:2)
对我来说很好,至少给了签名。只是为了增加“许多略有不同的方式”路演:
int IndexOf(const char *s, const char c) {
for (const char *p = s; *p != 0; ++p) {
if (*p == c) return p - s;
}
return -1;
}
轻微问题 - 如果结果足够大,则无法保证p-s
有效,如果正确结果大于INT_MAX
,则肯定会出错。解决这个问题:
size_t IndexOf(const char *s, const char c) {
for (size_t idx = 0; s[idx] != 0; ++idx) {
if (s[idx] == c) return idx;
}
return SIZE_MAX;
}
正如锐齿所说,如果出于某种说法原因你不应该使用s[i]
语法,那么*(s+i)
就是一样。
请注意稍微微妙的一点,因为输入需要以nul结尾,c
的第一次出现不能在索引SIZE_MAX
,除非c
为0(甚至那时候)我们正在谈论一个相当不寻常的C实现)。因此可以使用SIZE_MAX
作为魔术值。
通过返回指向找到的字符(或null)而不是索引(或-1)的指针,可以避免所有大小问题:
char *findchr(const char *s, const char c) {
while (*s) {
if (*s == c) return (char *)s;
++s;
}
return 0;
}
相反,你遇到了const-safety的问题,就像标准函数strchr
与const-safety一样的问题,并且可以通过提供const和非const重载来修复。
答案 3 :(得分:1)
有一个拼写错误(index
而不是i
),但除此之外它看起来很好。我怀疑你能做得比这更好(在效率和代码清晰度方面。)
答案 4 :(得分:1)
答案 5 :(得分:1)
另一种变体,作为一名老派C程序员可以写出来:
int IndexOf(const char *s, char c) {
int i = 0;
while (s[i] && (s[i] != c)) ++i;
return (s[i] == c)?i:-1;
}
好处:简短,只有一个变量,只有一个返回点,不会中断(被某些人视为有害)。
为了清楚起见,我可能会选择下面的那个:
int IndexOf(const char *s, char c) {
int result = -1;
for (int i = 0; s[i] != 0; ++i) {
if (s[i] == c) {
result = i;
break;
}
}
return result;
}
它使用了一个中断,但只有一个返回点,但仍然很短。
您还可以注意到我使用了普通0而不是'\0'
,只是为了提醒char是一种数字类型而简单的引号只是将字母转换为其值的简写。显然,比较0也可以用C中的!
代替。
修改强>
如果只允许指针算术,这不会改变太多......真的s [i] 是指针算术...但如果你愿意,你可以重写它*(s+i)
(如果你喜欢混淆,甚至i[s]
int IndexOf(const char *s, char c) {
int result = -1;
for (int i = 0; *(s+i) != 0; ++i) {
if (*(s+i) == c) {
result = i;
break;
}
}
return result;
}
答案 6 :(得分:1)
对于适用于x86系统上大多数情况的版本,可以使用:
int IndexOf(char *s, char sr)
{
uint_t *x = (uint_t*)s;
uint_t msk[] = { 0xff, 0xff00, 0xff0000, 0xff000000 };
uint_t f[4] = { (uint_t)sr, (uint_t)sr << 8, (uint_t)sr << 16, (uint_t)sr << 24 };
uint_t c[4], m;
for (;;) {
m = *x;
c[0] = m & msk[0]; if (!c[0]) break; if (c[0] == f[0]) return (char*)x - s;
c[1] = m & msk[1]; if (!c[1]) break; if (c[1] == f[1]) return (char*)x - s + 1;
c[2] = m & msk[2]; if (!c[2]) break; if (c[2] == f[2]) return (char*)x - s + 2;
c[3] = m & msk[3]; if (!c[3]) break; if (c[3] == f[3]) return (char*)x - s + 3;
x++;
}
return -1;
}
限制:
msk[]
和f[]
数组的顺序必须颠倒。如果您愿意,所有这些都可以通过更复杂的版本来解决......
为什么你会想做那样奇怪的事情 - 目的是什么? 一个人这样做是为了优化。 char-by-char检查很容易编码和理解,但最佳性能,至少对于超过一定长度的字符串,往往需要对较大的数据块进行操作。出于这个原因,您的标准库代码将包含一些这样的“有趣”的东西。如果您在单个操作中比较较大的块(以及例如SSE2指令,可以将其一次扩展到16个字节),则可以在同一时间完成更多工作。
答案 7 :(得分:1)
就你而言,你的完全没问题。您还应该编写一个简单的测试程序来测试第一个char,最后一个char和一个缺少的char。
回到'其他方法'小组,这里有一个没有break
,一个return
,并且显示指针算术。但是,要注意:如果我对你的作业进行评分,我会把你的成绩高于我的。你的清楚和可维护,我不必要地使用?:和指针减法。
#include <stdio.h>
int IndexOf(const char *s, const char c)
{
const char * const p = s;
while(*s && *s != c) s++;
return (*s) ? s-p : -1;
}
#ifdef TEST
int main()
{
printf("hello, h: %d\n", IndexOf("hello", 'h'));
printf("hello, g: %d\n", IndexOf("hello", 'g'));
printf("hello, o: %d\n", IndexOf("hello", 'o'));
printf("hello, 0: %d\n", IndexOf("hello", 0));
}
#endif
该程序的输出是:
hello, h: 0
hello, g: -1
hello, o: 4
hello, 0: -1