K&R练习2-5

3

"编写函数any(s1, s2),它返回字符串s1中来自字符串s2的任何字符第一次出现的位置,如果s1不包含来自s2的任何字符,则返回-1。(标准库函数strpbrk执行相同的工作但返回指向位置的指针。)"

"我想知道在循环中使用返回语句而不是像我在这里所做的那样使用“char_match = YES”是否是一个坏习惯。"

#define YES 1
#define NO 0
int char_seek(char string[], char string2[])
{
    int i, j;
    int char_match = NO;

    for (i = j = 0; string[i] != '\0' && char_match == NO; ++i){
        while (string2[j] != '\0' && string[i] != string2[j])
            ++j;
        if (string2[j] == '\0')
            j = 0;
        else if (string[i] == string2[j])
            char_match = YES;
    }
    if (char_match == NO)
        return -1;
    else
        return i-1;
}
return i-1有什么问题吗?需要找到其他方法来解决这个问题吗?

1
为了提高可读性,最好在while(..)语句中使用括号{...}来包含代码部分。 - ryyker
1
简化版的代码如下:ssize_t any(const char *s1, const char *s2) { const char *p1 = s1; for (;;) { const char *p2 = s2; do { if (*p1 == *p2) { return *p1 ? (p1 - s1) : -1; } } while (*p2++ != '\0'); p1++; } }。顺便说一句,多个返回并不是一个坏习惯,但如果方便的话应该避免使用多个返回。 - chux - Reinstate Monica
3个回答

4

回答你的问题:

  1. 拥有多个返回语句是可以的。
  2. 作为一个可能的返回语句:return i-1; 是可以的。

因此,你可以将代码重写为:

int char_seek(char string[], char string2[])
{
    int i, j;

    for (i = j = 0; string[i] != '\0'; ++i){
        while (string2[j] != '\0' && string[i] != string2[j])
            ++j;
        if (string2[j] == '\0')
            j = 0;
        else if (string[i] == string2[j])
            return i;
    }

    return -1;
}

或者,我可能会写出这样的东西:

int char_seek(const char *string, const char *string2) {
    for (int i = 0; string[i] != '\0'; ++i)
        for (int j = 0; string2[j] != '\0'; ++j)
            if (string[i] == string[j])
                return i;
    return -1;
}

我认为这种写法更易读。

通常来说,在实现搜索功能时,我认为在循环内部使用return语句是首选的表示方法。

另外,虽然我知道这是一个学习练习,但值得注意的是,在string.h中有一个非常类似的函数名为strpbrk()它可以代替你完成几乎所有工作。


2

只有一个原因会导致多个return语句不好,那就是如果你需要在退出函数之前进行任何清理工作。例如,如果您在特定函数中为多个指针分配内存,则需要确保在这些语句之前将它们全部释放。在您的情况下,在循环内部使用return是完全可以的,因为您不会遇到任何内存管理问题。


0

关于是否使用多个返回更好,没有有效的答案,但请记住-如果您选择多个返回路径-您必须考虑资源回收(FILE句柄,malloc等),因为您在C中没有像其他语言(C ++,Java等)那样的设施。

下面是使用多个返回的代码,并且我返回i而不是i-1(这是正常的,因为在循环结束前刚执行了++i)。

int char_seek(char string[], char string2[])
{
    int j = 0;
    for (int i = 0; string[i] != '\0'; ++i) {
        while (string2[j] != '\0' && string[i] != string2[j]) {
            ++j;
        }
        if (string2[j] == '\0') {
            j = 0;
        } else if (string[i] == string2[j]) {
            return i;
        }
    }
    return -1;
}

虽然使用多个返回值并没有错,但你应该始终使用 {} 来分隔块(比如你的 "else if")。而且你真的应该避免多个变量初始化,比如 i = j = 0


K&R练习2-5,标签==C应该可以缩小您的答案文本几行。 - ryyker
使用大括号来分隔代码块,比如我的 else if 语句中是什么意思? 我的 else if 块中没有大括号。 - Spellbinder2050
请查看我的帖子,以及我如何重新格式化else if块和while循环。 - NoDataFound

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接