我的C++代码中的Letter计数器工作不正常

The Letter counter within my C++ code is not working properly

本文关键字:计数器 工作 不正常 Letter C++ 代码 我的      更新时间:2023-10-16

所以我的程序按照预期运行,除了一件事,我的函数计数的字母不正确。例如,如果输入"Why hello there!"作为字符串,则显示的字母数为3,而不是13。我不知道我做错了什么,如果有任何帮助,我将不胜感激。谢谢

这是我的代码:

#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
void Count_All(char*, int&, int&, double&, int&); // Function prototype.
double Calc_Average (char*, int, int, double); // Function prototype.
int main()
{
    const int size = 500;
    char userString[size];
    int Word = 0;
    int Pun = 0;
    int Letters = 0;
    double Total_Characters = 0;
    double Average = 0.0;
    cout << "Please enter a string of 500 or less characters: ";
    cin.getline(userString, size);
    int len = strlen(userString);
    char *Dyn_Array = new char[len+1];
    strcpy(Dyn_Array, userString);
    cout << "n";
    Count_All (Dyn_Array, Letters, Word, Total_Characters, Pun);
    cout << "Number of letters in the string: " << Letters << "n";
    cout << "n";
    cout << "Number of words in the string: " << Word << "n";
    cout << "n";
    Average = Calc_Average (Dyn_Array, Word, Pun, Total_Characters);
    cout <<"Average number of letters per word: "<< fixed <<
    showpoint << setprecision(2) << Average << "n" << endl;

    cin.ignore(1);
    delete [] Dyn_Array;
    return 0;
}
void Count_All (char*strptr, int &Letters, int &Word, double &Total_Characters, int &Pun) // Counts all characters and types.
{
    while (*strptr != '')
    {
        if ((isspace(*strptr)) || (ispunct(*strptr)))
        {
            while ((isspace(*strptr)) || (ispunct(*strptr)))
            {
                strptr++;
            }
        }
        for(int x = 0; x < strlen(*strptr); x++)
        {
            if(!isspace(strptr[x]) && !Ispunct(strptr[x]))
            {
                Letters++;
            }
        }
        //if (((*strptr >= 'a') && (*strptr <= 'z')) || ((*strptr >= 'A') && (*strptr <= 'Z')))
            //Letters++;
        if ((isalnum(*strptr)) || (ispunct(*strptr)))
        {
            Word++;
            while ((isalnum(*strptr))||(ispunct(*strptr)))
            {
                strptr++;
                Total_Characters++; // Counting the total printable characters (including digits and punctuation).
                if((ispunct(*strptr)))
                {
                    Pun++; // Counting punctuation.
                }
            }
        }
        strptr++;
    }
}
double Calc_Average(char*strptr, int Word, int Pun, double Total_Characters)  // Calculates the average number of characters per words.
{
    double Average = 0.0;
    Total_Characters = Total_Characters - Pun; // Subtracting punctuation from all of the characters in the string (not including spaces).
    Average = (Total_Characters / Word);
    return Average;
}
for(int x = 0; x < strlen(*strptr); x++)

假设strptrchar *,那么编译器很可能会在这一行大声对您大喊大叫,因为您将char传递给strlen(),而不是char *。即使编译器仍然生成可执行文件,也不能忽略编译器发出的响亮尖叫声。

即使按如下方式修复,这仍然会产生完全错误的结果:

    for(int x = 0; x < strlen(strptr); x++)
    {
        if(!isspace(strptr[x]) && !Ispunct(strptr[x]))
        {
            Letters++;
        }
    }

这是第二个内环。外循环在每个字符上迭代strptr,执行一堆内容,包括这个内循环。

因此,如果有问题的字符串是"hello":

  1. 在外循环的第一次迭代中,strptr指向"h",该内循环将Letters加5。

  2. 在外循环的第二次迭代中,strptr指向"e",该内循环将Letters加4。

  3. 在外循环的第三次迭代中,strptr指向第一个"l",该内循环将Letters加3。

  4. 在外循环的第四次迭代中,strptr指向第二个"l",该内循环将Letters加2。

  5. 在外循环的第五次迭代中,strptr指向"o",该内循环将Letters加1。

此代码最终计数为5+4+3+2+1,即字符串"hello"中的15个字母。显然不是正确的结果。

这个内部循环是完全不需要的。扔掉它。

您还应该在计算机上找到一个非常有用的工具,称为"调试器"。使用这个工具,您就可以一次执行一行代码,检查所有变量,并自行确定这个问题。学习如何使用调试器是每个C++开发人员的必备技能。

编辑:字母计数可能应该包含在你的单词检测器中,因为它也可以推进strptr。它不仅扰乱了单独的字母计数逻辑,而且它本身的优点也被打破了,因为它可以将strptr推进到终止的字符,而最终的strptr++将再次推进它,导致未定义的行为,并可能崩溃。整体逻辑有太多问题。它应该从头开始重写。

效率非常高。一次性完成所有操作可能非常棒,但它很少是优雅的,而且通常是真正的[咒骂删除]调试。因此,软件工程中有一个建议,那就是你做一件事,并把它做好。

Count_All同时计算字母、单词和标点符号,并以多种不同的方式出错。很难弄清楚哪一点功能是如何被破坏的,因为bug往往会相互攻击和隐藏。

另一方面,具有三个功能,Count_Punctuation;CCD_ 23和CCD_。每一个都可以单独编写、单独测试和单独调试。编写一个函数。证明它有效。继续写作并证明下一个功能。冲洗,重复。

结果不如高度优化的一体式解决方案快,但您可以更快地对其进行编码和调试。这在学习时非常重要。这意味着你可以花更多的时间学习。

例如:

int Count_Punctuation(char * strptr)
{
    int punc = 0;
    while (*strptr != '')
    {
        if (ispunct(*strptr))
        {
            punc ++;
        }
        strptr++;
    }
    return punc;
}

每个字符一个循环。如果字符是标点符号,则递增计数器。当字符数不足时返回计数器。

Count_Letter几乎相同,但在计算字母。Count_Word有点棘手。

正如Sam所说,您需要成为strlen函数的指针。然后你需要把你的信件柜台移到while循环之外,你应该没事了。类似这样的东西:

for(int x = 0; x < strlen(strptr); x++)
{
   if(!isspace(strptr[x]) && !Ispunct(strptr[x]))
   {
   Letters++;
   }
}
while (*strptr != '')
{
    if ((isspace(*strptr)) || (ispunct(*strptr)))
    {
        while ((isspace(*strptr)) || (ispunct(*strptr)))
        {
            strptr++;
        }
    }
    if ((isalnum(*strptr)) || (ispunct(*strptr)))
    {
        Word++;
        while ((isalnum(*strptr))||(ispunct(*strptr)))
        {
            strptr++;
            Total_Characters++; // Counting the total printable characters (including digits and punctuation).
            if((ispunct(*strptr)))
            {
                Pun++; // Counting punctuation.
            }
        }
    }
    strptr++;
}

我更新了注释以修复问题,就我的测试而言,现在更好了。。。

#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
void Count_All(char*, int&, int&, double&, int&); // Function prototype.
double Calc_Average (char*, int, int, double); // Function prototype.
int main()
{
    const int size = 500;
    char userString[size];
    int Word = 0;
    int Pun = 0;
    int Letters = 0;
    double Total_Characters = 0;
    double Average = 0.0;
    cout << "Please enter a string of 500 or less characters: ";
    cin.getline(userString, size);
    int len = strlen(userString);
    char *Dyn_Array = new char[len+1];
    strcpy(Dyn_Array, userString);
    cout << "n";
    Count_All (Dyn_Array, Letters, Word, Total_Characters, Pun);
    cout << "Number of letters in the string: " << Letters << "n";
    cout << "n";
    cout << "Number of words in the string: " << Word << "n";
    cout << "n";
    Average = Calc_Average (Dyn_Array, Word, Pun, Total_Characters);
    cout <<"Average number of letters per word: "<< fixed <<
    showpoint << setprecision(2) << Average << "n" << endl;

    cin.ignore(1);
    delete [] Dyn_Array;
    return 0;
}
void Count_All (char*strptr, int &Letters, int &Word, double &Total_Characters, int &Pun) // Counts all characters and types.
{
    // sorry this was a test: strptr[strlen(strptr)+1]='';
    while (strptr[0] != '')
    {
        while (isspace(strptr[0]))
        {
            strptr++;
        }
        if(!isspace(strptr[0]) && !ispunct(strptr[0]))
        {
            cout << strptr[0] << " ";
            Letters++;
            Total_Characters++; // Counting the total printable characters (including digits and punctuation).
            strptr++;
            if(strptr[0] == '' || isspace(strptr[0]) || ispunct(strptr[0]))
            {
                Word++;
            }
        }
        if ((isalnum(strptr[0])) || (ispunct(strptr[0])))
        {
            if((ispunct(strptr[0])))
            {
                Pun++; // Counting punctuation.
                Total_Characters++; // Counting the total printable characters (including digits and punctuation).
                strptr++;
            }
        }
    }
}
double Calc_Average(char*strptr, int Word, int Pun, double Total_Characters)  // Calculates the average number of characters per words.
{
    double Average = 0.0;
    Total_Characters = Total_Characters - Pun; // Subtracting punctuation from all of the characters in the string (not including spaces).
    Average = (Total_Characters / Word);
    return Average;
}

使用有限状态机逐字符循环字符串一次,以跟踪我们是否在一个单词中,并计算单词的数量。

#include <iostream>
#include <cstring>
#include <iomanip>
#include <string>
using namespace std;
const int STATE_WITHOUT = 1;
const int STATE_IN_WORD = 2;
class TestInput {
    public:
        string m_s_input;
        int m_i_expected_words;
        int m_i_expected_punctuation_marks;
        int m_i_expected_letters;
        int m_i_expected_total_printable_characters;
    TestInput(
        string s_input,
        int i_expected_words,
        int i_expected_punctuation_marks,
        int i_expected_letters,
        int i_expected_total_printable_characters
    ):  m_s_input(s_input),
        m_i_expected_words(i_expected_words),
        m_i_expected_punctuation_marks(i_expected_punctuation_marks),
        m_i_expected_letters(i_expected_letters),
        m_i_expected_total_printable_characters(i_expected_total_printable_characters)
    {}
}; /* class TestInput */
// Counts all characters and types. 
void Count_All (const string& str, int &Letters, int &Words, int &Total_Printable_Characters, int &Punctuation_Marks) {
    // Clear all these "out params" so the caller can call this
    // method multiple times without having to theirself
    // clear them...
    Letters = 0;
    Words = 0;
    Total_Printable_Characters = 0;
    Punctuation_Marks = 0;
    int i_state = STATE_WITHOUT;
    char c = '';
    for( size_t i = 0; i < str.length(); i++ ){
        c = str[i];
        if( isalpha(c) )
        {
            Letters++;
        }
        if( isalnum(c) || ispunct(c) )
        {
            Total_Printable_Characters++; // Counting the total printable characters (including digits and punctuation).
        }
        if( ispunct(c) ) 
        {
            Punctuation_Marks++;
        }
        /* Use finite-state machine to count words... */
        switch( i_state ){
            case STATE_WITHOUT:
                if( ispunct(c) || isalnum(c) )
                {
                    i_state = STATE_IN_WORD;
                    Words++;
                }
                break;
            case STATE_IN_WORD:
                if( isspace(c) )
                {
                    i_state = STATE_WITHOUT;
                }
                break;
        }/* switch( i_state ) */
    }/* for( size_t i = 0; i < str.length(); i++ ) */
}/* Count_All() */
// Calculates the average number of characters per words.
double Calc_Average(int Word, int Pun, int Total_Characters){
    double Average = 0.0;
    Total_Characters = Total_Characters - Pun; // Subtracting punctuation from all of the characters in the string (not including spaces).
    if( Word == 0 ){
        // Avoid divide by zero error...
        return 0.0;
    }
    Average = ((double)Total_Characters / (double)Word);
    return Average;
}/* Calc_Average() */
int main()
{
    int Words = 0;
    int Punctuation_Marks = 0;
    int Letters = 0;
    int Total_Printable_Characters = 0;
    double Average = 0.0;
    TestInput test_inputs[] = {
        // s_input, i_expected_words, i_expected_punctuation_marks, i_expected_letters, i_expected_total_printable_characters 
        TestInput("", 0, 0, 0, 0 ) 
        ,TestInput(" ", 0, 0, 0, 0 ) 
        ,TestInput("Why, hello there!", 3, 2, 13, 15 ) 
        ,TestInput("I am sam.", 3, 1, 6, 7 ) 
        ,TestInput("I'll take 1 bagel.", 4, 2, 12, 15 ) // Counting both contraction "I'll" and numerical "1" as one word each...as "wc" utility seems to do...
        ,TestInput("I'll be back, Bennett!", 4, 3, 16, 19) 
        ,TestInput("Let off some steam, Bennett!", 5, 2, 22, 24) 
        ,TestInput("Supercalifragilisticexpyalidocious", 1, 0, 34, 34 )
        ,TestInput("'ere, what'cha doin' 'ere, guv'nor?", 5, 8, 23, 31 )
        ,TestInput(" 'ere, what'cha doin' 'ere, guv'nor?", 5, 8, 23, 31 )
        ,TestInput("That's one small step for a man, one giant leap for mankind.", 12, 3, 46, 49 )
    };
    for( size_t i = 0; i < sizeof(test_inputs)/sizeof(TestInput); i++ ){
        cout << "i = " << i << ": Running Count_All( "" << test_inputs[i].m_s_input << "" )n" 
               << "t" << "(length of input = " << test_inputs[i].m_s_input.length() << ")..." << endl;
        Count_All( test_inputs[i].m_s_input, Letters, Words, Total_Printable_Characters, Punctuation_Marks );
        cout << "i = " << i << ": Letters = " << Letters << " (Expected " << test_inputs[i].m_i_expected_letters << ")..."
            << (( Letters == test_inputs[i].m_i_expected_letters ) ? "PASSED" : "FAILED" ) << "..." << endl;
        cout << "i = " << i << ": Words = " << Words << " (Expected " << test_inputs[i].m_i_expected_words << ")..."
            << (( Words == test_inputs[i].m_i_expected_words ) ? "PASSED" : "FAILED" ) << "..." << endl;
        cout << "i = " << i << ": Total_Printable_Characters = " << Total_Printable_Characters << " (Expected " << test_inputs[i].m_i_expected_total_printable_characters << ")..."
            << (( Total_Printable_Characters == test_inputs[i].m_i_expected_total_printable_characters) ? "PASSED" : "FAILED" ) << "..." << endl;
        cout << "i = " << i << ": Punctuation_Marks = " << Punctuation_Marks << " (Expected " << test_inputs[i].m_i_expected_punctuation_marks << ")..."
            << (( Punctuation_Marks == test_inputs[i].m_i_expected_punctuation_marks ) ? "PASSED" : "FAILED" ) << "..." << endl;
        Average = Calc_Average ( Words, Punctuation_Marks, Total_Printable_Characters);
        cout << "i = " << i << ": Average number of letters per word: " << fixed 
            << showpoint << setprecision(2) << Average << "n" << endl;
    }
    return 0;
}/* main() */

输出:

i = 0: Running Count_All( "" )
    (length of input = 0)...
i = 0: Letters = 0 (Expected 0)...PASSED...
i = 0: Words = 0 (Expected 0)...PASSED...
i = 0: Total_Printable_Characters = 0 (Expected 0)...PASSED...
i = 0: Punctuation_Marks = 0 (Expected 0)...PASSED...
i = 0: Average number of letters per word: 0.00
i = 1: Running Count_All( " " )
    (length of input = 1)...
i = 1: Letters = 0 (Expected 0)...PASSED...
i = 1: Words = 0 (Expected 0)...PASSED...
i = 1: Total_Printable_Characters = 0 (Expected 0)...PASSED...
i = 1: Punctuation_Marks = 0 (Expected 0)...PASSED...
i = 1: Average number of letters per word: 0.00
i = 2: Running Count_All( "Why, hello there!" )
    (length of input = 17)...
i = 2: Letters = 13 (Expected 13)...PASSED...
i = 2: Words = 3 (Expected 3)...PASSED...
i = 2: Total_Printable_Characters = 15 (Expected 15)...PASSED...
i = 2: Punctuation_Marks = 2 (Expected 2)...PASSED...
i = 2: Average number of letters per word: 4.33
i = 3: Running Count_All( "I am sam." )
    (length of input = 9)...
i = 3: Letters = 6 (Expected 6)...PASSED...
i = 3: Words = 3 (Expected 3)...PASSED...
i = 3: Total_Printable_Characters = 7 (Expected 7)...PASSED...
i = 3: Punctuation_Marks = 1 (Expected 1)...PASSED...
i = 3: Average number of letters per word: 2.00
i = 4: Running Count_All( "I'll take 1 bagel." )
    (length of input = 18)...
i = 4: Letters = 12 (Expected 12)...PASSED...
i = 4: Words = 4 (Expected 4)...PASSED...
i = 4: Total_Printable_Characters = 15 (Expected 15)...PASSED...
i = 4: Punctuation_Marks = 2 (Expected 2)...PASSED...
i = 4: Average number of letters per word: 3.25
i = 5: Running Count_All( "I'll be back, Bennett!" )
    (length of input = 22)...
i = 5: Letters = 16 (Expected 16)...PASSED...
i = 5: Words = 4 (Expected 4)...PASSED...
i = 5: Total_Printable_Characters = 19 (Expected 19)...PASSED...
i = 5: Punctuation_Marks = 3 (Expected 3)...PASSED...
i = 5: Average number of letters per word: 4.00
i = 6: Running Count_All( "Let off some steam, Bennett!" )
    (length of input = 28)...
i = 6: Letters = 22 (Expected 22)...PASSED...
i = 6: Words = 5 (Expected 5)...PASSED...
i = 6: Total_Printable_Characters = 24 (Expected 24)...PASSED...
i = 6: Punctuation_Marks = 2 (Expected 2)...PASSED...
i = 6: Average number of letters per word: 4.40
i = 7: Running Count_All( "Supercalifragilisticexpyalidocious" )
    (length of input = 34)...
i = 7: Letters = 34 (Expected 34)...PASSED...
i = 7: Words = 1 (Expected 1)...PASSED...
i = 7: Total_Printable_Characters = 34 (Expected 34)...PASSED...
i = 7: Punctuation_Marks = 0 (Expected 0)...PASSED...
i = 7: Average number of letters per word: 34.00
i = 8: Running Count_All( "'ere, what'cha doin' 'ere, guv'nor?" )
    (length of input = 35)...
i = 8: Letters = 23 (Expected 23)...PASSED...
i = 8: Words = 5 (Expected 5)...PASSED...
i = 8: Total_Printable_Characters = 31 (Expected 31)...PASSED...
i = 8: Punctuation_Marks = 8 (Expected 8)...PASSED...
i = 8: Average number of letters per word: 4.60
i = 9: Running Count_All( " 'ere, what'cha doin' 'ere, guv'nor?" )
    (length of input = 36)...
i = 9: Letters = 23 (Expected 23)...PASSED...
i = 9: Words = 5 (Expected 5)...PASSED...
i = 9: Total_Printable_Characters = 31 (Expected 31)...PASSED...
i = 9: Punctuation_Marks = 8 (Expected 8)...PASSED...
i = 9: Average number of letters per word: 4.60
i = 10: Running Count_All( "That's one small step for a man, one giant leap for mankind." )
    (length of input = 60)...
i = 10: Letters = 46 (Expected 46)...PASSED...
i = 10: Words = 12 (Expected 12)...PASSED...
i = 10: Total_Printable_Characters = 49 (Expected 49)...PASSED...
i = 10: Punctuation_Marks = 3 (Expected 3)...PASSED...
i = 10: Average number of letters per word: 3.83