简体   繁体   English

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

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

so my program runs like it is supposed to except for one thing, the letters counted by my function are not correct. 因此我的程序运行正常,除了一件事,函数计数的字母不正确。 For example, if you enter "Why hello there!" 例如,如果输入“为什么在那里”! as the string, the number of letters displayed is three as opposed to 13. I am not sure what I am doing wrong, any help would be appreciated. 作为字符串,显示的字母数是3,而不是13。我不确定我做错了什么,将不胜感激。 Thanks! 谢谢!

Here is my code: 这是我的代码:

#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 != '\0')
    {
        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++)

Given that strptr is a char * , your compiler is most likely yelling at you, very loudly, on this line, because you're passing a char to strlen() instead of a char * . 鉴于strptrchar * ,您的编译器很可能会大声地对您大喊大叫,因为您是将char传递给strlen()而不是char * Loud screams from your compiler must not be ignored, even if the compiler still produces an executable. 即使编译器仍生成可执行文件,也不能忽略来自编译器的大声尖叫。

Even if this is fixed as follows, this will still produce completely wrong results: 即使按以下方式解决此问题,仍然会产生完全错误的结果:

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

This is a second inner loop. 这是第二个内部循环。 The outer loop iterates strptr over every character, executing a bunch of stuff, including this inner loop. 外循环在每个字符上迭代strptr ,执行一堆东西,包括这个内循环。

So, if the string in question is "hello": 因此,如果所讨论的字符串是“ hello”:

  1. On the first iteration of the outer loop, strptr points at the ' h ', and this inner loop adds 5 to Letters . 在外循环的第一次迭代中, strptr指向“ h ”,并且该内循环将5加到Letters

  2. On the second iteration of the outer loop, strptr points at the ' e ', and this inner loop adds 4 to Letters . 在外循环的第二次迭代中, strptr指向“ e ”,并且该内循环将4加到Letters

  3. On the third iteration of the outer loop, strptr points at the first ' l ', and this inner loop adds 3 to Letters . 在外部循环的第三次迭代中, strptr指向第一个“ l ”,并且此内部循环将3加到Letters

  4. On the fourth iteration of the outer loop, strptr points at the second ' l ', and this inner loop adds 2 to Letters . 在外循环的第四次迭代中, strptr指向第二个“ l ”,并且该内循环将2加到Letters

  5. On the fifth iteration of the outer loop, strptr points at ' o ', and this inner loop adds 1 to Letters . 在外循环的第五次迭代中, strptr指向' o ',并且该内循环将1加到Letters

This code ends up counting 5+4+3+2+1, or 15 letters in the string "hello". 该代码最终计数字符串“ hello”中的5 + 4 + 3 + 2 + 1或15个字母。 Obviously not the correct result. 显然不是正确的结果。

This inner loop is completely unneeded. 完全不需要此内部循环。 Get rid of it. 摆脱它。

You should also find a very useful tool on your computer, called a "debugger". 您还应该在计算机上找到一个非常有用的工具,称为“调试器”。 Using this tool, you would've been able to step through the execution of your code, one line at a time, examine all the variables, and determine this problem all by yourself. 使用此工具,您将能够一步一步地执行代码,检查所有变量,并自行确定此问题。 Learning how to use a debugger is a required skill for every C++ developer. 学习如何使用调试器是每个C ++开发人员的必备技能。

EDIT: the letter counting should probably be incorporated at your word detector, since it advances strptr as well. 编辑:字母计数可能应该合并在您的单词检测器中,因为它也可以提高strptr Not only does it mess up the separate letter counting logic, it is also broken on its own merits, because it could advance strptr to the terminating \\0 character, and the final strptr++ will advance it once more, resulting in undefined behavior, and a likely crash. 它不仅搞乱了单独的字母计数逻辑,而且还因其自身的优点而被打破,因为它可能会将strptr推进到终止\\0字符,而最终的strptr++将再次推进它,导致不确定的行为,并且可能会崩溃。 There are too many problems with the overall logic. 总体逻辑有太多问题。 It should be rewritten from scratch. 应该从头开始重写它。

Efficiency is great. 效率很棒。 Doing everything in one pass can be awesome, but it is rarely elegant and is often a real [expletive deleted] to debug. 一次完成所有操作可能会很棒,但是它很少优雅,并且经常是真正的[删除专有内容]进行调试。 As a result there is a recommendation in software engineering that you do one thing and do it well. 结果,在软件工程中建议您做一件事并做好。

Count_All counts letters, words, and punctuation all at once and gets it wrong several different ways. Count_All计算字母,单词和标点符号,并通过几种不同的方式将其弄错。 It is hard to figure out which bit of functionality is broken how because bugs tend to feed off and hide each other. 很难弄清楚哪一部分功能被破坏了,因为错误倾向于相互滋养并相互隐藏。

On the other hand, with three functions, Count_Punctuation ; 另一方面,具有三个函数Count_Punctuation ; Count_Letters and Count_Words , each does exactly one thing. Count_LettersCount_Words各自Count_Words一件事。 Each can be written separately, tested separately, and debugged separately. 每个都可以分别编写,分别测试和调试。 Write one function. 编写一个函数。 Prove that it works. 证明它有效。 Move onto writing and proving the next function. 继续写作并证明下一个功能。 Rinse, repeat. 冲洗,重复。

What results is not as fast as a highly optimized, all-in-one solution, but you can code and debug it a lot faster. 产生的结果并不像高度优化的多合一解决方案那样快,但是您可以更快地进行编码和调试。 This is very important when learning. 这在学习时非常重要。 It means you can spend more time doing the learning. 这意味着您可以花费更多时间进行学习。

For example: 例如:

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

One loop through each character. 每个字符一个循环。 If the character is punctuation, increment the counter. 如果字符是标点符号,则增加计数器。 when out of characters return the counter. 当字符不足时返回计数器。

Count_Letter is nearly identical, but counting letters. Count_Letter几乎相同,但计数字母。 Count_Word is a bit trickier. Count_Word有点棘手。

As Sam said, you need to be the pointer into the strlen function. 正如Sam所说,您需要成为strlen函数的指针。 Then you need to move your letter counter outside of your while loop and you should be okay. 然后,您需要将字母计数器移到while循环之外,并且应该可以。 Something like this: 像这样:

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

while (*strptr != '\0')
{
    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++;
}

I updated to fix the problem on comments, is better now as far as I tested... 我已更新以解决评论中的问题,据我测试,现在更好了...

#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]='\0';
    while (strptr[0] != '\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] == '\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;
}

Loop through the string character-by-character once, using a finite-state machine to keep track of whether we are in a word or not and to count the number of words. 使用有限状态机循环遍历字符串中的每个字符,以跟踪我们是否在一个单词中,并计算单词的数量。

#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 = '\0';

    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() */

OUTPUT: OUTPUT:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM