Solved

c++ cctype help required

Posted on 2013-10-25
45
560 Views
Last Modified: 2013-10-29
Hello,

I have been trying to figure out how to count different aspects of a string for days now. Everytime I think I'm getting close I get another error. What I need to happen here is make choice E in my case menu display the following statistics about a user entered string. The things I need to display are the number of alpha characters in string, the number of numeric char in strings, the number of spaces, the number of vowels, the number of end marks and finally the most frequent character used in string. I am assuming they are all relatively similar in nature. I know c++ has isalpha, isdigit, isspace which I need to use. The others I am thinking I need to create a short array with the vowels and end marks in then loop through and count.

The problem is I don't know how exactly. My code is to follow. Note: Everything else works and each of the statistics needs to be there own function then called the way I did the length in case E

Thanks in advance for any help

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
#include <cstdlib>

using namespace std;

void myMenu();
string enterText();
long myLength(string myText);
string mySort(string text);
int myAlpha(string myText);

int main()
{
    char myChoice;
	string myText;
	string appendText;
    
    myMenu();
    
	do
	{
		

        cout << "Choice: ";
        cin >> myChoice;
        
        
        switch (toupper(myChoice))
        {
            case 'A':
                cin.ignore();
                cout << "\nEnter text: ";
                
                getline(cin, myText);
                
                cout << endl << "(Press Enter key to continue)" << endl;
                cin.get();
                
                myMenu();
                
                break;
                
            case 'B':
                cin.ignore();
                cout << "\nText: " << myText << "\n" << endl;
                cout << "\nEnter some text to append: ";
                getline(cin,appendText);
                cout << "\nAppended Text: " << myText.append(appendText) << "\n" << endl;
                
                cout << endl << "(Press Enter key to continue)" << endl;
                cin.get();
                
                myMenu();
                
                break;
                
            case 'C':
                cin.ignore();
                cout << "\nText: " << myText << "\n" << endl;
                
                cout << endl << "(Press Enter key to continue)" << endl;
                cin.get();
                
                myMenu();
                
                break;
                
                
            case 'D':
                cin.ignore();
                
                
                
                cout << "\nText: " << mySort(myText) << "\n" << endl;
                
                cout << endl << "(Press Enter key to continue)" << endl;
                cin.get();
                
                myMenu();
                
                break;
                
                
            case 'E':
                cin.ignore();
                cout << "\n Length is " << myLength(myText) << "\n" << endl;
                
                cout << "\n Alpha Characters " << myAlpha(myText) << "\n" << endl;
                
                cout << endl << "(Press Enter key to continue)" << endl;
                cin.get();
                
                myMenu();
                
                break;
                
                
            case 'F':
                cin.ignore();
                return EXIT_SUCCESS;
                break;
                
                
            default: cout << "\n You didnt select and option \n" << endl;
                myMenu();
                break;
        }
	}
	while(myChoice != 'F');
    
    
	
    
    return EXIT_SUCCESS;
}

void myMenu()
{
    cout << "-------------------------------- \n\n";
	cout << "Text Edit \n\n";
    
    cout << "A - New Text \n";
    cout << "B - Append To Text \n";
    cout << "C - Display Text \n";
    cout << "D - Display Text Sorted \n";
    cout << "E - Display Text Statistics \n";
    cout << "F - Exit \n\n";
}

string mySort(string text)
{
    sort(text.begin(), text.end());
    
    return text;
}

long myLength(string myText)
{
    return myText.length();
}

int myAlpha(string myText)
{
    
    for(int i = 0; i < myText.length(); i++)
    {
        if (isalpha(myText.at(i++))
        {
            return i++;
        }
    }
    
}

Open in new window

0
Comment
Question by:joedfuse
  • 19
  • 19
  • 7
45 Comments
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
This looks like a good homework problem to teach you the method of handling strings.  Are you looking for someone to do the work for you?  That's not really what EE is all about. Instead, let's help you find the path to the right answer.  As you have surmised, each function will work the same way, and you merely need to write them, then start outputting values.  This is the easy part.

So, let's look at your myAlpha function that is already written.  Reading the code, we see that you are iterating i from 0 to the length of the string -- all good.  You then perform a test to see if the character at i is an alpha or not.  Perfect thus far.  

What I do not understand is why you opt to increment i again here.  This effectively increments i twice for each iteration, so it will end up checking only every other character.  Even more confusing is what you decide to do with that information -- when you find an alpha character, you return i, and then increment it once again for some reason.

My understanding is that this function should be counting the number of alpha characters, right?  Perhaps you would be best served by creating a counter variable, properly initialized, that you can use to keep track of how many characters are alpha.  Then, it would probably be best to return that AFTER counting all of the characters, not just after you find the first one.

Try that & see what you can do with it...
0
 

Author Comment

by:joedfuse
Comment Utility
First off I never asked anyone to do anything for me, I asked for help. Secondly, I pay for this subscription so i will decide what I use EE for. Honestly, in all the years I have been using this service I have never encountered such a fool. Thats right, its a pay for service website. Am I missing something with that?

I posted code and don't know how to do something. You can either help or not. But you making me feel like I'm trying to cheat or something is out of order. I have been a paying member since 2004. I don't think the people who get paid to run this site based on my and the rest of the people I recommended paying for this service would appreciate you alienating me.

For anyone else that wants to help and not talk smack... all I'm looking for is help on doing it not write the code for me. I want to learn how to do this. If I wanted someone to do this for me I would just hire someone. I am having a problem understanding looping through strings and basic arrays where it applies to checking for the most common used character.
0
 
LVL 28

Accepted Solution

by:
Bill Bach earned 350 total points
Comment Utility
So you read my first paragraph and ignored the rest of it?  If you read JUST a bit further, you'll see that I did provide guidance on what needs to be fixed. This is the spirit of EE.  

1) Create a counter variable to count the number of alpha chartacters.
2) Init the counter to 0 outside the loop.
3) Don't use i++ in the IF statement -- you already have an incrementor for the loop index, and this doubles the incrementing.
4) Don't "return i++" inside the IF statement -- increment the counter variable instead.
5) Return the counter variable as the result, which is what you want back, not i++.
6) When you get the function right for isalpha(), you'll be in a better position to write the other functions.

Is that explicit enough?  Beyond this, I can write the entire code fragment for you -- for all the functions. I can also optimize them for you so that they run faster, too. Do you want an answer or do you want to learn how this works?
0
 

Author Comment

by:joedfuse
Comment Utility
OK, so if I under stand what your saying but am confused about the loop. Can you explain which loop I would use in this instance and how do i write the loop.

For example, should I use for loop and how would I loop through the string so i can count the is alpha bool.

Thanks
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
Your FOR loop is perfectly correct -- this is what I am saying. You created an interator (i) which allows you to look over each character of the string. The problem is your IF statement. You are trying to increment the iterator again -- get rid of the "++" in there. The second problem is inside the IF statement. Again, don't mess with the iterator here, but increase your counter variable (which also needs to be declared and initialized). When the FOR loop exits, return the counter variable.
0
 

Author Comment

by:joedfuse
Comment Utility
Ok heres my shot at what I think your saying. Im getting an error above the if statement saying expecting ')' Not what I'm doing wrong here. Thanks for bearing with me. Our professor gives us assignments and doesn't actually teach us how to do any of it. We have yet to have a class were we talk about for loops.

int myAlpha(string myText)
{
    int countAlpha = 0;
    
    for(int i = 0; i < myText.length(); i++) // counts all chars in string myText
    {
        if (isalpha(myText.at(i)) // checks for alpha char and returns true if there is one
        {
            countAlpha++ // adds the char to the total
        }
            
    }
            return countAlpha; //outputs total alpha char
}

Open in new window

0
 

Author Comment

by:joedfuse
Comment Utility
Ok so i got it working... here is the code. Now how would I use this type of thing to get the most common occurring character, and count the vowels?  Thanks

int myAlpha(string myText)
{
    
    int countAlpha = 0;
    
    for (size_t i = 0; i!=myText.length(); i++) {
        
        if (isalpha(myText[i])) {
            
            countAlpha++;
            
        }
    }
    
    return countAlpha;
    
}

Open in new window

0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
That is it -- exactly.  Your error is a simple one -- you are missing a ")" in the IF statement.  Count them up -- you have three "(" and only two ")".  Add one more ) before the comment (and a semicolon after "countAlpha++") and it will compile and run perfectly.

The next 4 (numerics, spaces, vowels, endmarks) are identical to this, with simply a different IF statement.  

For vowels, you can use a simple IF statement like:
  if (myText.at(i)='a' || myText.at(i)='A' || myText.at(i) = 'e' ...  )
However, this de-references the array many times in the same line, which is not very efficient.  It would be more efficient to assign the character from the string to a variable and check that against the letters you are looking for.  Further, you can use _toupper() when you do the assignment and cut the number of terms in your IF statement down to only 5.  

The last one is, of course, the most difficult.  It is designed to see who can put together the various constructs they have learned thus far.  There are several approaches to handling this:
1) Sort the input string alphabetically, then count repeating characters, saving the character and the repeat count that occurs most often.  
2) Create an array, one INT for each ASCII character, count the number of each character in the string, then find the highest number in the counter.
There may be more approaches than this, too.  Again, some approaches may be far more efficient than others.  Go ahead & get the first ones working, then post your first-cut solution to the last one and we'll see how you do.
0
 

Author Comment

by:joedfuse
Comment Utility
Here is the end marks and vowel adaptation. I applied what I learned from there for loop. Now I don't even know where to start with what you said about finding the most frequent used characters.

int myVowel(string myText)
{
    
    int countVowel = 0;
    
    for (size_t i = 0; i!=myText.length(); i++) {
        
        if ((myText.at(i) == 'a')||(myText.at(i) == 'A')||(myText.at(i) == 'e')||
            (myText.at(i) == 'E')||(myText.at(i) == 'i')||(myText.at(i) == 'I')||
            (myText.at(i) == 'o')||(myText.at(i) == 'O')||(myText.at(i) == 'u')||
            (myText.at(i) == 'U')||(myText.at(i) == 'y')||(myText.at(i) == 'Y'))
        {
            countVowel++;
        }    }
    
    return countVowel;
    
}

int myEndMark(string myText)
{
    
    int countEndMark = 0;
    
    for (size_t i = 0; i!=myText.length(); i++) {
        
        if ((myText.at(i) == '.')||(myText.at(i) == '!')||(myText.at(i) == '?'))
        {
            countEndMark++;
        }    }
    
    return countEndMark;
    
}

Open in new window

0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
That all looks correct. Is the output right, too?  One thought -- using != in the for loop might be a problem if you inadvertantly increment the counter variable twice -- could cause an infinite loop. It is customary to use < instead.

Have you learned arrays yet?  If not, you can use brute force -- a counter for each character type. Otherwise, use an array of INT values and count them up. Get that code working and print out the resulting list for now, and I'll help with the rest when I have some more time.
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
Stopped atthe office for a minute.  Remember that a char is simply a byte value, and that you can use this as an offset into an array.  A short form of this idea would be:
1) Define an array of 256 integers and initialize to 0 values.
2) Loop over your string. You already have this down pat.
3) Use the char value as the offset into the array, and add one:
     myarray[myText.at(i)]++;
4) When done with the string, loop over the array and print out the count for each of the 256 values (0-255).
5) Finding the largest value of this array is an exercise for the reader.
0
 

Author Comment

by:joedfuse
Comment Utility
I actually found this in my readings which works when I type the string in the char a[] line. How would I get my user defined string into this char array? Also, is this the best way ti get the char frequency

char mostFrequent(string myText)
{
    char a[]= "Here is my text string";
    int max=0;
    int count=0;
    char maxCharcter;
    for(char q='a';q<='z';q++)
    {
        count = 0;
        for(int i=0; i<strlen(a);i++)
        {
            if(a[i]==q)
                count++;
        }
        
        if(count>max)
        {
            max=count;
            maxCharcter=q;
        }
    }
    
    return maxCharcter;

}

Open in new window

0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
As I said, there are MANY ways to code this algorithm.  This is the first one I mentioned in post 39602893.

First off, you need to use myText instead of a.  This is actually easy.  Replace all occurrences of strlen(a) with myText.length().  I believe C++ strings allow the use of the [] operator, so replace a[] occurrences with myText[], too.  Having done this, you'll be parsing your string instead of "a".

Second, notice that the outer FOR loop (Line 7) is iterating over the lower case characters ONLY.  You need to look at your program specs better -- is it looking for a case insensitive comparison?  If so, then you need to add a _tolower() call in Line 15 so that "a" and "A" are treated the same for comparison purposes.  If you want upper and lower case different, then you need to iterate over a larger range.  Consult your ASCII chart to figure out the bounds you might want.  

Further, as this is iterating over letters only, it is ignoring all special characters, digits, punctuation, and more.  If you are supposed to count these in your analysis, then Line 7 definitely needs to be changed.  However, looping over *all* ASCII characters (from 0 through 255) would likely cover it.

Third, how should you treat it when MULTIPLE characters have the same occurrence -- such as when the character "E" and "T" are both used 12 times?  Do you report the first one with the highest count (E)?  The last one(T)?  All of them(E,T)?  Because of line 16, this algorithm will report the FIRST one that has the highest count.  Change > to >= to report the LAST one.  If you want to report ALL, then you'll need to build a string -- a bit more code, but not too difficult from here.  You'll need to check the spec sheet for the program to know for sure how to proceed...
0
 

Author Comment

by:joedfuse
Comment Utility
Ok, so i got that bad boy working (well sort of. Only letters count)....

Also, I want to loop over all ascii like you said and not sure how to change the for loop.

char mostFrequent(string myText)
{
    int max=0;
    int count=0;
    char maxCharcter;
    for(char q='a';q<='z';q++)
    {
        count = 0;
        for(int i=0; i<myText.length();i++)
        {
            if(myText[i]==q)
                count++;
        }
        
        if(count>max)
        {
            max=count;
            maxCharcter=q;
        }
    }
    
    return maxCharcter;

}

Open in new window

0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
Awesome.  Change:
    for(char q='a';q<='z';q++)
to:
    for(char q=0;q<=255;q++)

This will loop over the entire range of possible values.  (You could probably skip 0, because this is an end-of-string marker.)  Note that this looks at EVERY character 256 times, so it is far less efficient (for large data sets) than something that looks at each character and counts each one one time, then deals with the result set.  However, since you are working with strings, my guess is that they are short, and overall performance should be irrelevant.
0
 

Author Comment

by:joedfuse
Comment Utility
I changed the range to what you said and it broke the function. Weird cause there was no error or anything. Just when I selected statistic option it showed all statistics up to the most frequent. Then no cursor or anything. I had to stop process and reload.

Maybe I have to add something that tells it to look of rthe ascii range?

Thanks again
0
 

Author Comment

by:joedfuse
Comment Utility
Ok, so I think I solved the range problem by using the range ' ' to '~' this covers the full ascii range.

Now, I can't seem to figure out how to handle ties. If 2 characters have the same frequency it defaults to the first in the ascii range.

I am assuming I would have to make the function output a string then use some sort of decision to add delimiter.

Unfortunately I don't know how to do this.
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
Sorry -- I didn't read it carefully enough.  Your original statement was:
    for(char q=0;q<=255;q++)
However, notice that q is defined as a char field, which is, by default, signed.  Thus, when it got to 127, it rolled to -128, and NEVER equalled 255, thus created an infinite loop.  Try this:
    for(unsigned char q=0;q<255;q++)
This changes it to the unsigned char, which means that we'll be able to cover the entire range, but we DO still need a stopping point.  So, we sacrifice character 255, which this algorithm will not detect.  That's OK, because this is not a common character anyway.
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
What does your spec sheet say about ties -- do you need to show ALL?  Or only ONE of the highest?
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
Sorry for the multi-post -- was trying to do in stages.

Obviously, the part that must change is here:
        if(count>max)
        {
            max=count;
            maxCharcter=q;
        }

If you use my last thought -- change maxCharcter from a CHAR value to a STRING value so that you can amass the values.  Change the first line to "count>=max" so that duplicates are caught.  Then change the last line in the IF statement to append "q" to the string, instead of replacing it, and you're done.
0
 

Author Comment

by:joedfuse
Comment Utility
It just says most occurring character. However, I think I should know how to use as string. In the real world I would have to output all valid results.

The above solution looks good. I will give it a shot. Should I change the entire function from char to string as well?
0
 

Author Comment

by:joedfuse
Comment Utility
Ok, so I converted the function to string and all is well. Not sure how to display all the max results. This still only displays the first max count in the range.

Thanks for all your help thus far. I am learning a ton through this process.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:joedfuse
Comment Utility
Here is the function in string form

string mostFrequent(string myText)
{
    int max=0;
    int count=0;
    string maxCharcter;
    for(char q=' ';q<='~';q++)
    {
        count = 0;
        for(int i=0; i<myText.length();i++)
        {
            if(myText[i]==q)
                count++;
        }
        
        if(count>max)
        {
            max=count;
            maxCharcter=q;
        }
    }
    
    return maxCharcter;

}

Open in new window

0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
Need two changes:
Change line 15 to:  if(count>=max)
Change line 18 to APPEND the character (q) to the string if count==max.
0
 

Author Comment

by:joedfuse
Comment Utility
2 things...

1. So do I add another IF statement to check for ==

2. How do you append q? maxcharacter.append(q)?
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
1) Yes -- use a second IF.  If count==max, append to the current string.  If count>max, blank the current string, then append the character to it.
2) Yes, you can use the append() function.
"Trust your instincts, Luke...."
    -- obiwan
0
 

Author Comment

by:joedfuse
Comment Utility
Here is the code I came up with... not really working. :( ... Darth Vader just hit me in head with light saber

string mostFrequent(string myText)
{
    int max=0;
    int count=0;
    string maxCharcter;
    for(char q=' ';q<='~';q++)
    {
        count = 0;
        for(int i=0; i<myText.length();i++)
        {
            if(myText[i]==q)
                count++;
        }
        
        if(count>max)
        {
            max=count;

			 maxCharcter=q;

			if (count==max)
			{
				maxCharcter=maxCharcter.append(q);
			}
           
        }
    }
    
    return maxCharcter;

}

Open in new window

0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
Still need to change line 15 -- indicated 4 posts ago.  Also, the other IF statement needs to be BEFORE you set max=count.  You could rework this into two (unnested) IF statements, but you MUST handle the == condition first.  If this is not obvious, single-step through the code on paper and see what happens.  (If you are not familiar with single-stepping on paper, let me know and I can explain more.)

Try:
 
if (count==max)
{
  maxCharcter.append(q);
}
if(count>max)
{
  max=count;
  maxCharcter.clear();
  maxCharcter.append(q);
}

Open in new window

Note that this can be further optimized, which is also a good exercise.
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
Note that this can be further optimized, which is also a good exercise.


the function to find the most frequently occurring char, has some overhead. the outer loop was performed 95 times from blank to tilde while only the characters of the string need to be checked. then, any of the characters was compared with any character of the string.

there are a few algorithms which would perform better.

(1) you could first sort the string and then determine the longest sequence of the same character.

use std::sort from <algorithm> and pass myText.begin and myText.end() as arguments.

if the string is sorted by character code, multiple existing characters build a sequence in the string. with one for loop you now can find the longest sequence in the array,

for (int n = 0, m = 0; n < myText.length(); ++n, ++m)
{
    ...
}

Open in new window

n counts the characters in the string. m counts the length of the current sequence. whenever m is a new maximum, you would assign m to the new maximum and the associated character (or use the string-append technique if you really want to catch duplicate maximums as well. i wouldn't do that for counts of 1 or less, though). you would start a new sequence by setting m to 0 when myText[n] is a new character.

(2) use an array of counters where the character code is used as the index.

int counts[256] = { 0 };  // makes all zeros

Open in new window


you need a for loop iterating the characters of myText (and not all characters from blank to tilde). in the loop block the counters were incremented by

counts[myText[n]]++;

Open in new window


you also could use the same for loop to determine the maximum count and most frequent character.

note, the array size was 256, though for ascii characters from blank to tilde, 95 slots would be sufficient. however, that would require additional checks and code and is more error-prone. if using an array for all possible characters, you could count tab character (ascii 9) and/or linefeed character (ascii 10).

Sara
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
Good input, Sara. However, when someone is learning C, it is usually a bad idea to start combining functions like this -- I have found that it causes WAY too much confusion.  

Optimization is always the second phase of the process. For example, isAlpha could be re-written:
int myAlpha(string myText)
{
    for (int countAlpha = 0, size_t i = 0; i<myText.length(); ) 
        if (isalpha(myText[i++])) 
            countAlpha++;
    return countAlpha;
}

Open in new window

This is a lot more compact, and it performs better because it has fewer variable dereferences.  However, it is harder to read and understand, too.
0
 

Author Comment

by:joedfuse
Comment Utility
Well the good thing is .... I'm confused by BOTH ways LOL

I actual understand what both of you are saying. My problem is actually writing the code. I am having as problem structuring it. I have everything working except how to handle more than one most frequent character. Currently if there are lets say two character that came up 5 times it will only display the first in the ascii order.

I understand in theory how this should be done but not how to write the code.

Thanks
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
Ignoring the side-bar from sarabande, look at my previous post (ID: 39605375) -- it has everything you need.
0
 

Author Comment

by:joedfuse
Comment Utility
I tried using that block yesterday and it broke the function without causing an actual error in the ide
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
if you post your latest code, we could check for the break.

generally, I think that nested loops with complex condition handling is not the right design for a beginner.

you may think about a design which avoids nested loops and moves iterations into functions:

for example the search for the most frequent character(s) could be changed to:

// function returns the count of the most frequent characters and fills vector
int mostFrequent(const std::string & text, std::vector<char> & mostFreqChars)
{
     // sorts the characters in text and returns the sorted string
     std::string s = sortCharacters(text);
     std::vector<std::string> sequences;
     // convert sequence (string) into a vector of strings
     textToSequences(s, sequences);
     // determine max sequence length
     int nseqlen = getMaxSequenceLength(sequences);
     // get first character from all sequences with given length 
     FillMostFreqChars(nseqlen, sequences, mostFreqChars);
     return nseqlen;
}

Open in new window


the above approach divides the problem into smaller units which are much simpler to implement.

Sara
0
 

Author Comment

by:joedfuse
Comment Utility
Here is what I have. There are 2 problems. One the .append(q) doesnt work with char. And even if I use + to combine strings the function breaks when it gets to the if without actual error.

Note: we arent at vectors yet so I think I need to figure out a way using loops and decision statements.

string mostFrequent(string myText)
{
    int max=0;
    int count=0;
    string maxCharcter;
    for(char q=' ';q<='~';q++)
    {
        count = 0;
        for(int i=0; i<myText.length();i++)
        {
            if(myText[i]==q)
                count++;
        }
        
        if (count==max)
{
  maxCharcter.append(q);
}
if(count>max)
{
  max=count;
  maxCharcter.clear();
  maxCharcter.append(q);
}
    }
    
    return maxCharcter;

}

Open in new window

0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
I reviewed the logic again -- it looks good. I normally program in C using pointers, where something like this is both easy and efficient. If you've not done pointers yet, it can be confusing, and I was trying to avoid this complexity for you.

Have you discussed string handling functions in class yet?  Use whatever functions you already have to add the character to the string.

Or, test the function by adding in some printf() calls. Make sure that MAX is being set correctly. Make sure that the right character is detected. At least you'll know if the problem is with the logic or not.
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
I may have found one other issue, though. The string MaxCharcter is LOCAL to the function. I believe this is implemented as a pointer internally (which you haven't done yet), and when the return value is passed back, it may point to a memory location that has already been freed up, which could explain why you get garbage. This is not an issue for the INT values, which are passed as return codes on the stack.  

Try allocating the string in the parent program and pass it in. That might help
0
 
LVL 32

Assisted Solution

by:sarabande
sarabande earned 150 total points
Comment Utility
change
maxCharcter.append(q); 

Open in new window

by
maxCharcter += q;

Open in new window

at both occuriencies.

after that it works. when i use ""Hello world. I am here. wowwowowowowowo" for input it returns "ow" as result. the count is 9 (for both o and w but is not returned).

Sara
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
The string MaxCharcter is LOCAL to the function. I believe this is implemented as a pointer internally (which you haven't done yet), and when the return value is passed back, it may point to a memory location that has already been freed up
No. the return type is string what means that the compiler returns a copy of the MaxCharcter by value. if you assign it to a string variable you would get another copy.

note, if you also want to return the count, you might change your function like the below:

int mostFrequent(string  & myText)
{
     // omit the redefinition of maxCharcter
     //string maxCharcter;
     ...
     return max;
}

Open in new window


Sara
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
it should be two arguments, second is maxCharcter passed by reference.
int mostFrequent(string myText, string  & myCharcter)

Open in new window


you would pass an empty string variable for maxCharcter and get it back with the found character(s).

Sara
0
 

Author Comment

by:joedfuse
Comment Utility
The += worked!!!! Thanks.

One more little thing ... how would I add a comma between them. I am assuming I write like

maxCharacter += q + ",";
0
 
LVL 28

Expert Comment

by:Bill Bach
Comment Utility
You don';t want a hanging comma, so you need another IF:
if(maxCharcter.length() > 0)
    maxCharacter += ',';
maxCharacter += q;
0
 

Author Closing Comment

by:joedfuse
Comment Utility
Great help! Not only does it worked but I learned a great deal from it. Thanks
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
how would I add a comma between them.
normally you would do it only for output, not in the return string.

std::string maxCharcter = mostFrequent(myText);
std::string sep; // sep is empty initially
std::string soutput = "("
for (size_t i = 0; i<maxCharcter.length(); ++i)
{
    soutput += (sep + maxCharcter[i]);
    sep=",";
}
soutput += ")";

Open in new window


Sara
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
we arent at vectors yet so I think I need to figure out a way using loops and decision statements

not necessarily:

// function returns the count of the most frequent characters and fills array
int mostFrequent(const std::string & text, std::string & mostFreqChars)
{
     // sorts the characters in text and returns the sorted string
     std::string s = sortCharacters(text);
     // count different characters in sorted string
     int nSeq = countSequences(s);
     // create array of strings
     std::string psequences = new std::string[nSeq+1];
     // put all sequences into the sequences array
     textToSequences(s, psequences, nSeq);
     // determine max sequence length
     int nseqlen = getMaxSequenceLength(psequences);
     // get first character from all sequences with given length 
     FillMostFreqChars(nseqlen, psequences, nSeq, mostFreqChars);
     // delete array
     delete []psequences;
     return nseqlen;
}

Open in new window


you would pass all output arguments by reference (adding & to the argument type).

the textToSequences for example would be implemented like

void textToSequences(std::string s, std::string psequences[], int nSeq)
{
     size_t len = s.length();
     // we add a terminating character for simpler search
     s += '\n'; 
     size_t pos1 = 0;
     size_t pos2 = 0;
     // the loops ends if the array given has no more free slots or if we are past length
     for (int n = 0; n < nSeq && pos1 < len; n++, pos1 = pos2)
     {
          // find next character in string which is different from current character
          pos2 = s.find_first_not_of(s[pos1], pos1);
          // fill array with sub string
          psequences[n] = s.substr(pos1, pos2-pos1);
    } 
} 

Open in new window

 

Sara
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
Entering a date in Microsoft Access can be tricky. A typo can cause month and day to be shuffled, entering the day only causes an error, as does entering, say, day 31 in June. This article shows how an inputmask supported by code can help the user a…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now