【问题标题】:Homework problem using strchr gives me unexpected output使用 strchr 的作业问题给了我意想不到的输出
【发布时间】:2020-04-11 16:07:30
【问题描述】:

我必须编写一个 C 程序来输出文本的单词数,并在下一行输出以元音或辅音开头和结尾的单词。

例如:

input
La bacalaureat la proba de Informatica a fost un subiect cu un sir de caractere
output
15     
bacalaureat Informatica a fost subiect sir

这是我的程序:

#include <iostream>
#include <string.h>

using namespace std;

int main()
{
    int c = 0;
    char sir[100], copie[100];
    cin.get(sir, 100);
    strcpy(copie, sir);
    char* pch = strtok(sir, " ");
    while (pch != NULL)
    {
        c++;
        pch = strtok(NULL, " ");
    }
    cout << c << endl;
    char* pch2 = strtok(copie, " ");
    while (pch2 != NULL)
    {
        if ((strchr("aeiouAEIOU", pch2[0]) && strchr("aeiouAEIOU", pch2[strlen(pch2)-1])) || (strchr("aeiouAEIOU", pch2[0] == NULL) && strchr("aeiouAEIOU", pch2[strlen(pch2)-1] == NULL)))
        {
            cout << pch2<<" ";
        }
        pch2 = strtok(NULL, " ");
    }
}

但它给了我意想不到的输出。我明白了:

15
La bacalaureat la proba de Informatica a fost un subiect cu un sir de caractere

我不明白为什么。显然是因为那个 if,但我觉得没问题。

你能帮我修复我的程序吗?我不明白发生了什么。谢谢。

【问题讨论】:

  • 如果你必须“写一个 C 程序”那你为什么用 C++ 并用“c++”标记问题?
  • 由于您标记为 C++,因此请使用 std::stringstd::cin。输入将首先跳过空格,然后读取字符,直到遇到空格。比使用字符数组容易得多。另外,std::string 会动态增加;不用担心字符数组溢出或可怕的 nul 终止字符。

标签: c++ split count c-strings


【解决方案1】:

if 语句中使用的这个子表达式

strchr("aeiouAEIOU", pch2[0] == NULL) && strchr("aeiouAEIOU", pch2[strlen(pch2)-1] == NULL)

错了。

应该有

strchr("aeiouAEIOU", pch2[0]  ) == NULL && strchr("aeiouAEIOU", pch2[strlen(pch2)-1] ) == NULL

你可以通过以下方式更简单地编写 if 语句

if ( ( strchr( "aeiouAEIOU", pch2[0] ) == NULL ) == 
     ( strchr( "aeiouAEIOU", pch2[strlen(pch2)-1] ) == NULL ) )

但无论如何创建源字符串的副本并使用strtok 都不是一个好方法。

最好使用标准C函数strspnstrcspn在不改变字符串的情况下提取单词。

您可以将满足条件的单词存储在向量中。

这是一个演示程序。

#include <iostream>
#include <utility>
#include <vector>
#include <cstring>
#include <cctype>

int main() 
{
    const char *s = "La bacalaureat la proba de Informatica "
                    "a fost un subiect cu un sir de caractere";

    const char *vowels = "aeiou";
    const char *delim = " \t";

    std::vector<std::pair<const char *, const char *>> v;
    size_t n = 0;

    for ( const char *p = s; *p != '\0'; )
    {
        p += std::strspn( p, delim );
        const char *q = p;

        if ( *q )
        {
            ++n;
            p += std::strcspn( p, delim );

            char c1 = std::tolower( ( unsigned char )q[0] );
            char c2 = std::tolower( ( unsigned char )p[-1] );

            if ( ( std::strchr( vowels, c1 ) == nullptr ) == 
                 ( std::strchr( vowels, c2 ) == NULL ) )
            v.emplace_back( q, p );              
        }
    }

    std::cout << n << '\n';
    for ( const auto &p : v ) std::cout.write( p.first, p.second - p.first ) << ' ';
    std::cout << '\n';

    return 0;
}

它的输出是

15
bacalaureat Informatica a fost subiect sir 

【讨论】:

  • 天哪,我不敢相信我错过了那个 lmao。我看不出我没有关闭括号。我会尽快接受你的回答。谢谢。
【解决方案2】:

这是您的程序的一个版本,使用strchr,但使用std::istringstream 拆分单词:

#include <iostream>
#include <string>
#include <cstring>
#include <sstream>
#include <vector>

bool isvowel(char ch)
{
    return strchr("aeiouAEIOU",ch)?true:false;
}

bool isconsonant(char ch)
{
    return !isvowel(ch);
}

int main()
{
    std::vector<std::string> sVect;
    int word_count = 0;
    std::string test = "La bacalaureat la proba de Informatica a fost un subiect cu un sir de caractere";
    std::istringstream strm(test);
    std::string word;
    while (strm >> word)
    {
        ++word_count;
        if ( (isvowel(word.front()) && isvowel(word.back())) ||
             (isconsonant(word.front()) && isconsonant(word.back())))
            sVect.push_back(word);     
    }
    std::cout << word_count << "\n";
    for (auto& s : sVect)
        std::cout << s << " ";
}

输出:

15
bacalaureat Informatica a fost subiect sir 

请注意,元音或辅音的测试被放置在单独的函数中,使比较更容易。

还要注意使用std::string 类的front()back() 可以轻松获取每个单词的第一个和最后一个字符,而不是在比较中重复调用strlen

【讨论】:

  • 我也会研究你的替代方案。非常感谢您的宝贵时间。
猜你喜欢
  • 2023-03-17
  • 1970-01-01
  • 2019-05-19
  • 2017-01-05
  • 2021-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多