在char * s中找到char c的第一个出现或返回-1

时间:2010-12-07 11:40:52

标签: c++

对于家庭作业,我需要实现一个函数,它接受char *schar 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]。此外,不允许使用标准库。

8 个答案:

答案 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;
}

限制:

  • 如果字符串短于四个字节并且它的地址更接近MMU页面的末尾而不是四个字节,则会中断。
  • 此外,掩码模式是小端,对于大端系统,msk[]f[]数组的顺序必须颠倒。
  • 此外,如果硬件无法进行未对齐的多字节访问(x86可以),那么如果字符串不是以4的倍数开始,那么它也会失败。

如果您愿意,所有这些都可以通过更复杂的版本来解决......

为什么你会想做那样奇怪的事情 - 目的是什么? 一个人这样做是为了优化。 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