Loop creating extra output.

Okay, so I just started teaching myself C++ maybe a few days ago. Messed around with some basic input output things, I wanted to mess with characters and the input buffer to figure that out next.

I went to make a simple code that takes and converts the letters to the ANSI code then stops when it has cleared the input buffer. I spent a solid 8 hours getting it to this point but now I don't even know what to search for this one.

It works, it prints each letter in order and tells you its ANSI, but for some reason it always prints the last letter twice at the end. Can someone point me in the right searching direction?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 #include <iostream>
 
int main()
{
    char ch;
    
    do
    {
      
    std::cout << "Input a keyboard character: "; 
    
    std::cin >> ch; 
    std::cout << ch << " has ASCII code " << static_cast<int>(ch) << std::endl;
    

    } while (std::cin.peek() > 0); 
    return 0;
}


I snagged the ASCI print out from a helpful tutorial, so I still don't fully understand why "static_cast<int> ()" does what it does, but I don't think that should effect it printing one more time after it realizes there isn't anything in the buffer. (I will look that up once this code is working right)

My understanding of this is that it should look at the buffer, if it has a letter it in, it sees a value so it starts over, but once it runs out of letters is sees a 0 or no value so it shouldn't run the "do" again right?
Last edited on
I'm not observing what you're specifying.
Output I got:
Input a keyboard character: hello
h has ASCII code 104
Input a keyboard character: e has ASCII code 101
Input a keyboard character: l has ASCII code 108
Input a keyboard character: l has ASCII code 108
Input a keyboard character: o has ASCII code 111
Input a keyboard character:


Notice however that the condition std::cin.peek() > 0 does no good for you; try changing while (std::cin.peek() > 0); to while (true);, you'll get the same result.

In my opinion there's no need to use std::cin.peek() here. If you're expecting more than just one character, take input as a string and parse the string.

static_cast<int>(ch) tells the compiler that 'ch' must changed from the datatype char to int. If you hadn't written static_cast<int>() but instead written just ch, you would notice that it doesn't print the ASCII value but instead the character itself.
So the output I get is
input Hello

Input a keyboard character: H has ASCII code 72
Input a keyboard character: e has ASCII code 101
Input a keyboard character: l has ASCII code 108
Input a keyboard character: l has ASCII code 108
Input a keyboard character: o has ASCII code 111
Input a keyboard character: o has ASCII code 111


so it always repeats the last character.

I tried "true" and it prints


Input a keyboard character: H has ASCII code 72
Input a keyboard character: e has ASCII code 101
Input a keyboard character: l has ASCII code 108
Input a keyboard character: l has ASCII code 108
Input a keyboard character: o has ASCII code 111
Input a keyboard character: o has ASCII code 111
Input a keyboard character: o has ASCII code 111
Input a keyboard character: o has ASCII code 111
Input a keyboard character: o has ASCII code 111


Then keeps repeating the o until finally it "output limit exceeded"



I should mention that I don't know how to work with a string or parse yet, like I said I just started a few days ago, those two things are on my list but I figured I should understand a char before I figure out a string. My goal however is to be able to take a string of letters, convert the letters into integers and then pull those integers into another program.
Last edited on
You need to test the input method itself for success.
1
2
3
if ( std::cin >> ch ) {
  // do stuff with a valid ch
}


Or even loop for all the chars.
1
2
3
while ( std::cin >> ch ) {
  // do stuff with a valid ch
}
Then keeps repeating the o until finally it "output limit exeeded

??? How come! 0_0

It shouldn't loop like that because the program should wait for std::cin to finish executing.. hmm?

edit: Why is your std::cin failing?
Last edited on
So... Salem the input is functioning fine, and if you change the while to what you posted it just prints every other letter with the ASCI then stops because it kills a character after every execution of the do. I'm not sure what you are getting at.
Last edited on
Hahaha Grime I have no idea, because that was one of the first things I tried to. But it does keep going. I thought just like you did when I was first trying to figure this out.
Got it!!! Salem I get what you where saying now.

Grime thanks! you gave me the idea.

It was looking at the declared variable outside the DO statement and seeing a valid character to print. so I moved it inside the do and now it prints right!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
 
int main()
{
   
    
    do
    {
        char ch;
      
    std::cout << "Input a keyboard character: "; 
    
    std::cin >> ch; 
    std::cout << ch << " has ASCII code " << static_cast<int>(ch) << std::endl;
    

    } while (std::cin.peek() > 0); 
    return 0;
}


input hello

Input a keyboard character: h has ASCII code 104
Input a keyboard character: e has ASCII code 101
Input a keyboard character: l has ASCII code 108
Input a keyboard character: l has ASCII code 108
Input a keyboard character: o has ASCII code 111


but true still goes infinite... I will have to figure that out later.
Last edited on
I don't know why, but I think your cin goes into its fail state after you give your input. It seems like it.

In that case you might enclose your while loop within another while loop.
1
2
3
4
5
6
7
8
9
10
while (true) {
   while (std::cin >> ch) {
   . . .
   }
   // if program reaches here, cin stream is in fail state, so clear stream and discard
   cin.clear(); // remove fail state
   cin.ignore(1000, '\n'); // discard characters

   // then we go back to taking more inputs
}

That will be an infinite loop, so you can tweak it.



edit: run this code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
int main() {
   char ch;
   while (true) {
      while (std::cin >> ch) {
         std::cout << ch << " has ASCII code " << static_cast<int>(ch) << std::endl;
      }
      // if program reaches here, cin stream is in fail state, so clear stream and discard
      std::cin.clear(); // remove fail state
      std::cin.ignore(1000, '\n'); // discard characters

      // then we go back to taking more inputs
   }
}

Does it work?

Where ch is being declared is not our problem, in fact it should be declared outside the do-while, that would be better. I don't think I quite know what's wrong, so I'll leave it to some expert on this forum to help you out with that.
Last edited on
Yeah I am going to have to mess with the whole true thing. I even tried to add like an exit clause in a couple places but it just keeps going or ends on the first letter. I'll figure that one out. With the cin.peek it does exactly what I want it to do. Thanks for all the help!

Edit: Grime look above your last post :) It works when its in it doesn't work when its out.
Last edited on
Sorry I just realized something. It wasn't he location of the declaration. It was a return. my input wasn't "Hello"

It was "Hello
"

I was hitting return by reflex on the input and that return made it take a space as an input so it ran an extra cycle.
I don't know about the code itself but I want to point one thing about (std::cin.peek() > 0).

Don't write (std::cin.peek() > 0). It will ALWAYS be true in your code. If it's always true, what's the point of having it there anyway?

When you type some input the program reads what you typed INCLUDING the return you pressed. So if you wrote "Hello", it would read "Hello\n". If you typed "H", std::cin will read "H" and leave '\n' in the stream. The next std::cin will simply ignore preceding whitespaces.

Essentially std::cin.peek() will always read that '\n'. '\n' is 10 and 10 > 0.
Topic archived. No new replies allowed.