getche() with while loop - c++

I want to make a simple program that counts the number of words and characters in it .
I found the following code sample:
char ch = 'a';
int Wcont = 1; // to count the number of words in the phrase
int Chcont = 0;
while (ch != '\r'){
ch = getche();
if ( ch == ' ' )
Wcont++
// to the end of program
}
input : Welcome
output : Wcont = 1 , Chcont = 8
If change the condition on it:
if ( ch == ' ' || ch == '\r')
then number of words increases by 1
and number of Characters decrease by 1
input : Welocme
output : Wcont = 2 , Chcont = 7
I don't understand how does getche() works and how it interacts with the screen. I also wonder why in the condition there is ch == '\r' and why the loop must stop when ch == '\r' is false.

The while loop tests the last char read and then reads the next one. You should use the following:
while ((ch = getche()) !='\r')
or alternatively:
while(true)
{
ch = getche();
if(ch=='\r')
break;
.....
}

Related

What is the proper way of reading a composite key and a numeric value from an input file?

I'm trying to read a text file consisting of numerous strings which either represent a key/value (the key is a car number in a format of a letter/' '/3digits/' '/2letters; the value is unsigned long long; \t or ' ' between them) or an empty line, e.g.:
empty line
empty line
Z 999 ZZ 80
A 000 AA 124
Z 666 ZZ 42
I am using a cin.getline() function for that, reading a whole line and going through every character, saving a key and a value into an 'element' variable and pushing it into a vector afterwards. But for some reason the program seems to work unexpectedly, giving a weird output:
0
0
Z 999 ZZP 80
A 000 AA| 124
Z 666 ZZ* 42
So far I have been trying to analyse what could go wrong but I just can't see it. I've also tried using other tools like scanf() or cin.get() but failed miserably. Can someone please explain to me why this is happening and maybe show a more correct way of solving this task? Here is the code:
struct kv {
char key[8];
unsigned long long val;
};
int main()
{
std::vector<kv> data_vector;
kv element;
char str[64] = {};
char num[32] = {};
while (std::cin.getline(str, 64)) {
if (str[0] == ' ' || str[0] == '\n' || str[0] == '\t' || str[0] == EOF) {
continue;
}
size_t i = 0, n = 0;
for (i = 0; i < 8; i++)
element.key[i] = str[i];
while (!(str[i] >= '0' && str[i] <= '9'))
i++;
while (str[i] >= '0' && str[i] <= '9')
num[n++] = str[i++];
element.val = atoi(num);
data_vector.push_back(element);
for (n = 0; n < 32; n++)
num[n] = 0;
for (i = 0; i < 64; i++)
str[i] = 0;
}
for (size_t i = 0; i < data_vector.size(); i++) {
std::cout << data_vector[i].key << "\t" << data_vector[i].val << std::endl;
}
return 0;
}
EDIT: as #JimRhodes pointed out, changing char key[8] to char key[9] and adding element.key[8] = '\0' helped, but empty lines are still being processed the wrong way (as they should be ignored), giving an output of 0.
I think you may not be understanding how std::cin.getline() works. First of all, you do not want to test the return value of std::cin.getline() for true or false. You need to check for eof or fail. Secondly, std::cin.getline() discards the newline character so there is no need to check for '\n'. Your loop could start like this:
for ( ; ; )
{
str[0] = '\0'; // Clear any previous data
std::cin.getline(str, 64);
if ( std::cin.eof() )
{
break; // No more data, exit loop
}
if ( std::cin.fail() || (str[0] < 'A') )
{
continue; // Empty line or line does not start with a letter
}
. . .

C++ How to output the letters or numbers from input of letters or numbers

So let's say we have the following case: for ”12323465723” possible answers would be ”abcbcdfegbc” (1 2 3 2 3 4 6 5 7 2 3), ”awwdfegw” (1 23 23 4 6 5 7 23), ”lcwdefgw” (12 3 23 4 6 5 7 23), in this case, the user will input numbers from 1 to 26, not divided by any space and the program itself will suggest 3 ways of interpreting the numbers, getting the most of the combinations from 1 to 26 these being the values from a to z
As you can see this is edited, as this is the last part of the problem, Thank you all who have helped me this far, I've managed to solve half of my problem, only the above mentioned one is left.
SOLVED -> Thank you
This involves a decision between 0 to 2 outcomes at each step. The base cases are there are no more characters or none of them can be used. In the latter case, we backtrack to output the entire tree. We store the word in memory like dynamic programming. This naturally leads to a recursive algorithm.
#include <stdlib.h> /* EXIT */
#include <stdio.h> /* (f)printf */
#include <errno.h> /* errno */
#include <string.h> /* strlen */
static char word[2000];
static size_t count;
static void recurse(const char *const str) {
/* Base case when it hits the end of the string. */
if(*str == '\0') { printf("%.*s\n", (int)count, word); return; }
/* Bad input. */
if(*str < '0' || *str > '9') { errno = ERANGE; return; }
/* Zero is not a valid start; backtrack without output. */
if(*str == '0') return;
/* Recurse with one digit. */
word[count++] = *str - '0' + 'a' - 1;
recurse(str + 1);
count--;
/* Maybe recurse with two digits. */
if((*str != '1' && *str != '2')
|| (*str == '1' && (str[1] < '0' || str[1] > '9'))
|| (*str == '2' && (str[1] < '0' || str[1] > '6'))) return;
word[count++] = (str[0] - '0') * 10 + str[1] - '0' + 'a' - 1;
recurse(str + 2);
count--;
}
int main(int argc, char **argv) {
if(argc != 2)
return fprintf(stderr, "Usage: a.out <number>\n"), EXIT_FAILURE;
if(strlen(argv[1]) > sizeof word)
return fprintf(stderr, "Too long.\n"), EXIT_FAILURE;
recurse(argv[1]);
return errno ? (perror("numbers"), EXIT_FAILURE) : EXIT_SUCCESS;
}
When run on your original input, ./a.out 12323465723, it gives,
abcbcdfegbc
abcbcdfegw
abcwdfegbc
abcwdfegw
awbcdfegbc
awbcdfegw
awwdfegbc
awwdfegw
lcbcdfegbc
lcbcdfegw
lcwdfegbc
lcwdfegw
(I think you have made a transposition in lcwdefgw.)
According to ASCII table we know that from 65 to 90 it A to Z.
so below is the simple logic to achieve what you're trying.
int main(){
int n;
cin>>n;
n=n+64;
char a=(char) n;
if (a>=64 && a<=90)
cout<<a;
else cout<<"Error";
return 0;
}
If you want to count the occurencs of "ab" then this will do it:
int main()
{
char line[150];
int grup = 0;
cout << "Enter a line of string: ";
cin.getline(line, 150);
for (int i = 0; line[i] != '\0'; ++i)
{
if (line[i] == 'a' && line[i+1] == 'b')
{
++grup;
}
}
cout << "Occurences of ab: " << grup << endl;
return 0;
}
If you want to convert an int to an ASCII-value you can do that using this code:
// Output ASCII-values
int nr;
do {
cout << "\nEnter a number: ";
cin >> nr;
nr += 96; // + 96 because the ASCII-values of lower case letters start after 96
cout << (char) nr;
} while (nr > 96 && nr < 123);
Here I use the C style of casting values to keep things simple.
Also bear in mind ASCII-values: ASCII Table
Hope this helps.
This could be an interesting problem and you probably tagged it wrong, There's nothing specific to C++ here, but more on algorithm.
First of all the "decode" method that you described from numerical to alphabetical strings is ambiguious. Eg., 135 could be interpreted as either "ace" or "me". Is this simply an oversight or the intended question?
Suppose the ambiguity is just an oversight, and the user will enter numbers properly separated by say a white space (eg., either "1 3 5" or "13 5"). Let nstr be the numerical string, astr be the alphabetical string to count, then you would
Set i=0, cnt=0.
Read the next integer k from nstr (like in this answer).
Decode k into character ch
If ch == astr[i], increment i
If i == astr.length(), set i=0 and increment cnt
Repeat from 2 until reaching the end of nstr.
On the other hand, suppose the ambiguous decode is intended (the numerical string is supposed to have multiple ways to be decoded), further clarification is needed in order to write a solution. For example, how many k's are there in "1111"? Is it 1 or 2, given "1111" can be decoded either as aka or kk, or maybe even 3, if the counting of k doesn't care about how the entire "1111" is decoded?

questions about a function that act like scanf

I am wondering about the function below.
inline int nextInt()
{
register int s = 0, ch;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
for (s = ch - '0', ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar())
s = s * 10 + ch - '0';
return s;
}
I know that this function behaviors scanf function-like by returning the integer value. However, I didn't understand the function's detailed procedure because many variables are in for loops and it is a little bit confused to me to understand correctly. Even though I copied and pasted them on my visual studio and see each value in variables by printf, but I failed to know what they are doing.
Could you explain above codes to me about what they are doing line by line?
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
reads and ignores characters until it gets something in the range 0-9.
for (s = ch - '0', ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar())
s = s * 10 + ch - '0';
stores the numeric value of the last-read ascii character into s (e.g. '1' puts 1 into s). Then it reads the next character into ch. Then it tests if ch is a numeric digit. If so, it multiplies the existing value of s by 10 and adds the numeric value of ch. Now it reads another character and proceeds to the test again.
If you type 123, it reads '1' and stores 1 into s. Then it reads '2', multiplies s (1) by 10 (10) and adds 2 (12). Then it reads '3', multiplies s (12) by 10 (120) and adds 3 (123).
First line
register int s = 0, ch;
The register keyword is an outdated storage specifier telling the compiler to keep a value in a processor register (outdated because nowadays the compilers are very good at making that decision themselves, and the register keyword is ignored anyway).
From the presence of this keyword, I conclude that this is very old code. For any modern compiler, the above can safely replaced with
int s = 0, ch;
Second line
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
Let's rewrite this into the equivalent while loop:
ch = getchar();
while (ch < '0' || ch > '9')
{
ch = getchar();
}
Now it's easier to see what it does: It reads a character, and as long as it is not a digit, discards it and reads the next character.
In the name of DRY (don't repeat yourself), it would better be written using a do while loop:
do
{
ch = getchar();
} while (ch < '0' || ch > '9');
Third and fourth line
for (s = ch - '0', ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar())
s = s * 10 + ch - '0';
Let's again replace it with an equivalent while loop:
s = ch - '0', ch = getchar();
while (ch >= '0' && ch <= '9')
{
s = s * 10 + ch - '0';
ch = getchar();
}
The s = ch - '0', ch = getchar() is just two expression statements combined with the comma operator. The comma operator just ignores the value of its first argument after evaluating it, and returns the value of the second. It is used here because there can only be one initializer statement in a for and for some reason the author of that code thought he must cram both in there. So let's split it now in two statements:
s = ch - '0';
ch = getchar();
The expression ch - '0' just evaluates the value of the digit. This uses the fact that the type char actually is an integer type, and 0 really is the character code for the digit 0. Also it makes use of the requirement that all ten digits are consecutive in the character set.
The variable s stores the integer read so far. Since so far only one digit has been read, the integer read so far is just the value of the digit we read.
The second statement here of course just reads the next character.
The loop now runs as long as the next character read is still a digit.
The statement
s = s * 10 + ch - '0'
effectively appends the next digit to s. Multiplying by 10 just "appends a zero", and adding (ch - '0') then replaces that final 0 with the digit value.
Note that to avoid overflow (and thus undefined behaviour) when reading a number close to INT_MAX, this should actually read
s = s * 10 + (ch - '0');
Alternatively, given that this code can only read positive numbers anyway, the author could just have used an unsigned type, as there overflow behaviour is well defined.
OK, let's break it down:
inline int nextInt()
The inline keyword is a hint to the compiler that this function is small and should be "inlined" (basically a little optimization that inserts the function into source code rather than making it a function call).
register int s = 0, ch;
The register keyword, for all practical intents and purposes and in 99.99% of cases, is semantically meaningless, making this line equivalent to int s = 0, ch;.
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
This line is a little silly. It's actually calling getchar() twice, meaning that it pulls in (potentially) two characters, compares one of them to ensure it's between 0 and 9, and keeps going if it isn't. A better way to write this might be do ch = getchar(); while (ch < '0' || ch > '9');.
for (s = ch - '0', ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar())
s = s * 10 + ch - '0';
These two lines, in effect, keep multiplying s by 10 while pushing a new integer into the ones column as long as the user keeps entering integers. If the user enters 8 1 3 4, the resulting integer will be 8134.

How to display char character as an int, not as the ASCII symbol

I need this character to display as a number but I keep getting smiley faces and hearts and other ASCII symbols. This part is where I think the problem is:
s = prefix + ch + '.';
And here's the whole code:
int main()
{
int levels = 2;
string prefix = "Recursion:";
sections(prefix, levels);
system("pause");
return 0;
}
void sections(string prefix, int levels)
{
if (levels == 0)
{
cout << prefix << endl;
}
else
{
for (char ch = 1; ch <= 9; ch++)
{
string s;
s = prefix + ch + '.';
sections(s, levels - 1);
}
}
}
You're using int values for your characters, rather than characters, so you will get whatever characters happen to have those codes in your character set. Use ' arounds a character to get the character code for a specifiec character:
for (char ch = '1'; ch <= '9'; ch++)
sections(prefix + ch + '.', levels - 1);
Note that this depends on the digit characters all being contiguous and in ascending order in your character set (implementation defined), but that is the case for every character set I can think of...
You should use std::to_string function to convert the number into string.
The problem is your for-loop
char ch = 1 //is not a 1
char ch = '1' //instead is (but i'm not sure if you can increment this)
char ch = 49 // is also a 1
hope that helps.
https://en.wikipedia.org/wiki/ASCII

I'm coming up with erroneous results counting characters in string

I'm trying to count the occurance of letters in a line. But my results are coming up way wrong. I'll just present the function I believe contains the error.
void readAndCount(int &numWords, int letterCount[])
{
//set letterCount[] numwords initial values
memset(letterCount, 0, 26);
numWords = 1;
char a = ' ';
while(a != '\n')
{
a = getc(stdin);
if (a == ' ' || a == ',' || a == '.' || '\n')
++numWords;
else
if(a >= 'A' && a <= 'Z')
{
++letterCount[a - 'A'];
} else if (a >= 'a' && a <= 'z') {
++letterCount[a - 'a'];
}
}
return;
}
this is a string yields:
3 words
1 a
4194305 g
1 h
3 i
4196355 k
32630 n
4197445 o
32630 r
4197379 s
2 t
4196576 w
32767 z
I've already tried fflush()ing stdin before reading input.
Any pointers would be appreciated, but please don't just write it for me.
memset(letterCount, 0, 26) zeroes out 26 bytes of memory pointed by letterCount, instead of 26 ints as you wanted. How about memset(letterCount, 0, 26*sizeof(int))?
Since this is tagged c++, replace the call to c's memset() with:
std::fill(letterCount, letterCount + 26, 0);
Or:
std::fill_n(letterCount, 26, 0);
...and this will fix the array initialisation. The arbitrary numbers that you're seeing after 'f' are whatever garbage was in RAM before your program was loaded.
Also, this:
if (a == ' ' || a == ',' || a == '.' || '\n')
Should be:
if (a == ' ' || a == ',' || a == '.' || a == '\n')
Note: In c++, we prefer std::cin.get(a); over c's a = getc(stdin); (but that would make no difference to how your code executes, just a matter of style).