遍历字符串和使用switch语句:C++

3

我正在编写一些代码,遇到了一些麻烦。我想编写一个函数来检查字符串是否有任何元音字母,并尝试通过for循环和内部的switch语句来实现。显然,它不起作用,并且出于某种原因从未返回true。

bool scanStr(string userInp) {
    for (int i = 0; i < userInp.size(); i++) {
        switch (userInp[i])
        {
        case 'a':
        case 'A':
        case 'e':
        case 'E':
        case 'i':
        case 'I':
        case 'o':
        case 'O':
        case 'u':
        case 'U':
        case 'y':
        case 'Y':
            return true;
            break;
        default:
            return false;
        }
    }
}

我尝试测试程序是否真正迭代了字符串,确实迭代了,所以我不明白为什么在函数中它总是返回false?

int main() {
    string userInp;
    string pigLatin;

    cout << "Please enter a string to convert to pig Latin: " << endl;
    cin >> userInp;
    cout << endl;

    // tests
    for (int i = 0; i < userInp.size(); i++) { //checking if it actually iterates
        cout << userInp[i];
    }
    cout << endl;

    if (scanStr(userInp))
        cout << "it has a vowel" << endl;
    else
        cout << "no vowel" << endl;

    system("pause");
    return 0;
}

一开始我以为是因为在最后一个case之后有一个break语句,但循环仍然继续执行,但我不确定这是否是原因。

有什么想法吗?


你的代码有问题。我会为你修复它。 - tomascapek
你的循环计数器i应该是std::size_t类型,因为userInp.size()可能不适合有符号的int - jotik
还要注意,在return true;语句后面的break;语句是死代码,永远不会被执行。 - jotik
阅读有关std::string::find_first_of的内容。 - Pete Becker
4个回答

13

我建议您将测试元音逻辑提取到单独的函数中:

bool is_vowel(char x)
{
    switch (x)
    {
    case 'a':
    case 'A':
    case 'e':
    case 'E':
    case 'i':
    case 'I':
    case 'o':
    case 'O':
    case 'u':
    case 'U':
    case 'y':
    case 'Y':
        return true;
    default:
        return false;
    }
}

然后您可以使用标准算法而不是循环:

#include <algorithm>
#include <string>

bool contains_vowel(const std::string& str)
{
    return std::any_of(str.begin(), str.end(), is_vowel);
}

(我将scanStr重命名为contains_vowel,因为这个名称更能描述它的作用。)

(我将scanStr重命名为contains_vowel,因为这个名称更能描述它的作用。)


我在这里完全迷失了,但我有点理解! - Panthy
2
“一个字符串中的所有字符都是元音字母吗?”只是“序列中的所有元素是否满足某个谓词?”的一个具体例子,C++标准库提供了一个算法来解决这个问题。 - fredoverflow
1
作为促进解耦和使用标准算法的唯一答案,希望有更多类似的内容。点赞+1。 - Richard Hodges

5

从您的函数中删除这几行代码:

    default:
        return false;

它们会在函数遇到第一个非元音字母时返回false

只有在循环结束时仍未返回true的情况下,你才想要返回false

bool scanStr(string userInp) 
{
    for (int i = 0; i < userInp.size(); i++) 
    {
        switch (userInp[i])
        {
        case 'a':
        case 'A':
        case 'e':
        case 'E':
        case 'i':
        case 'I':
        case 'o':
        case 'O':
        case 'u':
        case 'U':
        case 'y':
        case 'Y':
            return true;
        }
    }

    return false;
}

在现代 C++ 中更好的方法是:

bool scanStr(const std::string& userInp) 
{
    for (const auto c : userInp) 
    {
        switch (c)
        {
        case 'a':
        case 'A':
        case 'e':
        case 'E':
        case 'i':
        case 'I':
        case 'o':
        case 'O':
        case 'u':
        case 'U':
        case 'y':
        case 'Y':
            return true;
        }
    }

    return false;
}

但是如果你不知道它的意思,现在不用担心,你的书或教程很快就会解释清楚。


1
@Panthy 不,一旦你使用return语句,函数就结束了,并且返回值(如果有的话)将返回给调用者。 - nvoigt
@Panthy 假设你没有犯任何错误,那么这可能会起作用。但是,这将更加复杂和容易出错。尝试一下,这可能是一个不错的练习。 - nvoigt
@nvoigt:在“return”后面不需要加上“break”。好的编译器会发出警告(无法到达的代码)。 - Martin Bonner supports Monica
@MartinBonner 包括了 "for" 和 const 引用参数传递,尽管我认为这对于 OP 来说还太早理解。 - nvoigt
实际上,我不理解你在函数本身中放置的参数,1.为什么我们要将其设置为const?2.如果我们不打算改变它的值或其他任何东西,为什么要使用&? - Panthy
显示剩余7条评论

1
问题在于,如果任何字符不是元音字母,该函数就会立即返回false。另外使用const &const允许您传递常量字符串,引用可以节省一些时间,因为C++不必复制整个字符串。
bool scanStr(const string & userInp) {
    for (int i = 0; i < userInp.size(); i++) {
        switch (userInp[i])
        {
        case 'a':
        case 'A':
        case 'e':
        case 'E':
        case 'i':
        case 'I':
        case 'o':
        case 'O':
        case 'u':
        case 'U':
        case 'y':
        case 'Y':
            return true;
            break;
        }
    }
    return false;
}

我不知道,因为我还是C++新手,所以还不熟悉他们所有的函数。 - Panthy
到目前为止,我能够处理引用的最接近的方法是使用&符号,但是*符号在这一点上似乎更加复杂:P - Panthy
1
这其实很简单。自己查一下吧 :) 希望我能帮到你,我真的很想在这里获得C++徽章... - tomascapek
没有性能问题。我期望开关现在应该更快。 - Lightness Races in Orbit
@RainbowTom 你所说的“没有性能问题”是什么意思?如果在switch语句中使用std::tolower函数并删除大写标签,就会有轻微的性能开销。我在我的系统上用2300MB字符串做了基准测试,使用GCC编译器时开销似乎很小,但是使用Clang编译器时,使用std::tolower函数的版本需要至少12倍的时间。通常,使用常规的switch语句或一些static bool const isLower[255u] = { false, ..., };查找表比调用没有性能约束的外部函数更快。 - jotik
显示剩余2条评论

0

首先编译器会将 switch case 转换成查找表,然后 auto 将根据分配的值(在本例中为 char)由编译器决定为数据类型。

或者直接交给编译器处理,它知道如何做。

bool scanStr(string userInp)
{
    for(auto c : userInp)
    {
        switch (c)
        {
            case 'a': case 'A':
            case 'e': case 'E':
            case 'i': case 'I':
            case 'o': case 'O':
            case 'u': case 'U':
            case 'y': case 'Y':

            return true;
        }
    }

    return false;
}

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