My for loop is executing more times than is expected - c++

I have the following for loop executing within my program and I can't see how it's design correlates with the output I'm receiving.
cout << no_of_lines << endl;
for (int count = 0; count < no_of_lines + 1; count ++)
{
getline(Device, line, '=');
cout << line << endl;
}
This is the output:
3
DeviceName
GPU
Manufacturer
Intel
GraphicalRam
128MB
And this is the file DeviceList
DeviceName=GPU
Manufacturer=Intel
GraphicalRam=128MB
In the loop, no_of_lines refers to the number of lines in the file, in this case 3. I have provided this output as verification that the loop is only executing once per line. Can anyone tell me why this loop is executing more times than is expected? I'm guessing it's because of my inclusion of = as the deliminator, and that the loop is somehow executing an additional time before incrementing, but then why does it stop on the deliminator on the last line, requiring me to add 1 to the loop limit?

This http://www.cplusplus.com/reference/string/getline/ is your friend here. The documentation says that when delem character is passed to getline, it reads up to delem char is found or end of file is reached. '\n' is not treated differently. Once it find delem char it discards it and fills line whatever it read until that point. Next time you call getline, it continues to read from where it left. so in this case, each call reads as follows.
DeviceName
GPU\nManufacturer
Intel\nGraphicalRam
128MB\n
'\n' in the above string is basically newline character. it's not really backslash followed by n (2 characters). its just single newline character '\n'. Just for understanding purposes I used it that way.
For clarity, here is the complete code(compiled and tested).
#include <iostream>
#include <string>
using namespace std;
int main()
{
int no_of_lines = 3;
string line;
cout << no_of_lines << endl;
for (int count = 0; count < no_of_lines + 1; count++)
{
getline(cin, line, '=');
cout << line << endl ;
}
return 0;
}
By now I hope its clear to you why you need to call getline 4 times.

your loop executes no_of_lines+1 times.
I assume you want the delimiter to be '='. However, when the delimiter is '=', then \n is not a delimiter. Hence line will contain \n (say, on the second getline). And so the number of lines displayed is not equal to the number of times the loop executes.

When you use = as line delimiter, \n is not used as line delimiter.
So you get strings containing newline characters.
When you output such a string, it's presented as two or more lines (due to the newlines it contains).
Cheers & hth.,

You want it to count thrice, but your loop is counting 0,1,2,3,4, i.e 5 iterations.

Related

Ignore Spaces Using getline in C++ Palindrome homework

I am trying to skip the spaces in my code using getline();
I think I solved the spacing problem, but I'm trying to make the code check from the beginning of the word and the end of the word at the same time, so that when I type sentences like "ufo tofu" it will come back as a palindrome.
I've tried removing the spaces, but it only causes the system to return me an error.
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string userInput;
int startInput;
int endInput;
bool isPalindrome = true;
startInput = userInput.length();
getline (cin, userInput);
cin.ignore();
for (int i = 0; i<(startInput/2); i++){
if (userInput[i] != userInput[(startInput -1) -i])
isPalindrome = false;
}
if (isPalindrome){
cout << userInput << " is a palindrome" << endl;
}
else {
cout << userInput << " is not a palindrome" << endl;
}
return 0;
}
I am trying to make the output come back as "is not a palindrome" when I submit my code to be graded.
These are the two errors that are coming back;
4: Compare output
0 / 2
Output differs. See highlights below.
Special character legend
Input
statistics
Your output
statistics is a palindrome
Expected output
statistics is not a palindrome
6: Compare output
0 / 2
Output differs. See highlights below.
Special character legend
Input
evil is alive
Your output
evil is alive is a palindrome
Expected output
evil is alive is not a palindrome
string s;
do {
getline(cin, s);
}while(s.empty());
s.erase((remove(s.begin(),s.end(),' ')),s.end());
cout<<s<<endl;
Let's say your string s is ufo tofu. It will after erasing all spaces become ufotofu. That way you can easily check if it's palindrome or not.
How does this thing work ?
Well we declare a string called s. In that string, we will store our ufo tofu input.
We use do-while loop to input our "sentence" into a string. We could use just getline(cin, s);, but if you pressed enter-key once, it would stop your program.
Next thing, we use function combination of functions remove and erase: As the beginning parameter we use function remove, which finds all the spaces in the string, pushes them to the end of the container (in our case string s), and returns beginning iterator of that "pushing", and the second parameter tells us to remove every single element of container from that beginning iterator to the end.
We just print out the string, but now without spaces!
I think this is really simple way to do it, but if it can't be useful to you, I am sorry for wasting your time reading all of this! :)

how to use multiple functions in one while loop?

i am trying to open an text file and trying to count the numbers of characters and words in the file, i have created while " while (!infile.eof()); " to scan the whole file till the end . However only one of the function is working and other one is also printing the same answer as the first one.
#include <iostream>
#include <fstream>
#include <conio.h>
using namespace std;
int main()
{
ifstream infile;
infile.open("tomorrow.txt");
int count1_char = 0;
int count2_word = 0;
while (!infile.eof())
{
{
char ch;
infile.get(ch); //number of characters
count1_char++;
}
{
char word[30];
infile >> word; //numner of words
count2_word++;
}
}
cout << " the number of characters :" << count1_char << endl;
cout << " the number of words :" << count2_word << endl;
infile.close();
return 0;
}
the output:
the number of characters :17
the number of words :17
Press any key to continue . . .
Since words consist of characters, you cannot read characters and words separately. You should take one of two approaches:
Read words, and add their lengths to character count - this approach is very simple, but your code has no control over separators, or
Read characters, and find delimiters to decide when one word ends and another word begins - this is slightly more complex, but your program stays in full control over its input.
The advantage of the first approach is its simplicity; the advantage of the second approach is an ability to account for whitespace characters correctly.
The second approach requires you to keep a "state" that lets you distinguish if the current character is part of a new word, or a continuation of a previously found word. A simple flag is sufficient for this. You will have one loop reading characters one by one, classifying each character as a space or non-space (e.g. with std::isspace function), incrementing the character count, and doing one of three things:
If you see a space, reset "is inside a word" flag to "false"
If you see a non-space, and "is inside a word" flag is "true", do nothing
If you see a non-space, and "is inside a word" flag is "false", set it to "true", and increment word count.

Cin not read my inputs

It must be that I'm tired but I can't seem to figure out why my program will not read my cin values for init and end which is supposed to be a start and an end point for my program. The way its setup for input is the first line is the amount of cases then there will be a new line which will be a string then on the next line there will be two integers separated by a space so I feel the way I built it is correct but when I debug the code the values for init and end never change whether I initialize the variable or not.
int case_count;
string name;
int init = 0;
int end = 0;
cin >> case_count;
cin.ignore(numeric_limits<::streamsize>::max(),'\n');
for (int i = 0; i < case_count; ++i) {
cout << "Case " << i << "\n";
getline(cin, name);
cin.ignore(numeric_limits<::streamsize>::max(), '\n');
cin >> init;
cin >> end;
Example input
3
flap
1 3
swoop
0 9
flip
0 6
Its making it hard to continue with the rest of the code.
The problem is that you call ignore in the loop. The problem with this is that std::getline extracts (and throws away) the newline character, meaning your ignore call in the loop will read and discard the next line (the one with the two numbers).
Besides that, when using the input operator to read numbers or strings, the operator will skip leading white-space, so even if getline didn't read the newline, it would still have worked without the ignore call.
However, there is a newline left over in the input stream after you read the numbers, and the next iteration the std::getline call will pick up that newline and then name will be empty, so you should, as suggested by M.M in a comment, move the ignore call to last in the loop.

cin.getline() skipping first iteration

I'm practicing with c string / pointers and can't solve this simple problem. cin.getline() isn't prompting user input for the first iteration, but does so for the consecutive strings. (I arbitrarily chose 10 as the char limit).
Am I overlooking something extremely simple?
void getStrings() {
int num;
cout << "How many strings? ";
cin >> num;
const int numStrings = num;
char** stringSet = (char**) malloc(numStrings * sizeof(char*));
for (int i = 0; i < numStrings; i++) {
*(stringSet + i) = (char*) malloc(10);
cout << "String " << i << ": ";
cin.getline(stringSet[i], 10);
cout << endl;
}
Setting aside the fact that it's generally inadvisable to use bare pointers in C++ when things like the standard library's std::string are available, you should not use malloc. For example: Instead of (char*) malloc(10), you should write new char[10] and remember to delete[] *(stringSet+i) at the end of your program.
That said, the line:
cin >> num
... extracts only the first number it comes across. It will fail (and cin will set its fail bit, and will need to be reset with cin.reset()) if it encounters any non-whitespace characters before it encounters a number.
But it stops extracting from the input after that. In your input stream is still whatever whitespace or other characters were still present in your input. For example, if you ran this program and typed "2 foobar" before pressing enter, it would immediately print:
String 1: foobar
String 2:
This is because the stream still contains "foobar\n".
In order to get the behavior you're looking for you will probably want to add this before your loop:
cin.ignore();
That will clear the stream of anything that's there.
cin >> num;
This will prompt the user for some input. Assuming the user does what's expected of them, they will type some digits, and they will hit the enter key. The digits will be stored in the input buffer, but so will a newline character, which was added by the fact that they hit the enter key. cin will parse the digits to produce an integer, which it stores in the num variable. It stops at the newline character, which remains in the input buffer. Later, you call getline, which looks for a newline character in the input buffer. It finds one immediately, so it doesn't need to prompt the user for any more input. So it appears that the first call to getline didn't do anything, but actually it did.
What do you mean by " isn't prompting user input for the first iteration"? I read that to mean "isn't printing the prompt for the input of the first string", but based on your code, I think it means "is printing the prompt for the input of the first two strings before it reads input."
cin >> num reads a number, the whole number, and nothing but the number. It does not read whatever follows the number, like a newline. So the first getline reads the newline character which you've already typed.
By the way, you should use cerr instead of cout for user prompts.
cout should be reserved for actual output. That makes scripting much easier, because you can redirect cout independent of cerr, and because you don't want to capture prompts in the program results anyway.

Is there a way to have user input multiple char arrays at once c++

I currently have a function that takes a array of 4 characters and returns another value based on that sequence of characters.
What I want is to have the user input a whole line of characters and then create a loop to go over each "sub- group of characters" and then return the result for all of them.
My initial thinking is to somehow use push_back to keep adding the arrays to a vector.
I don't know how long the entire array will be, but it should be a product of 3.
As an example, right now I am able to do :
char input [4] ;
cin >> input;
int i = name_index[name_number(input)];
cout << name[i].fullName;
But what I would like is the user ti input multiple name abbreviations at once
I would change your sample from this:
char input [4] ;
cin >> input;
int i = name_index[name_number(input)];
cout << name[i].fullName;
To this:
string input;
cin >> input;
const int i = name_index[name_number(input)];
cout << name[i].fullName;
Then you can start using a vector to track multiple inputs:
vector<string> inputs;
string line;
while (cin >> line)
{
if (line == "done")
break;
inputs.push_back(line);
}
for (unsigned int i = 0; i < inputs.size(); ++i)
{
cout << "inputs[" << i << "]: " << inputs[i] << endl;
//const int index = name_index[name_number(inputs[i])];
//cout << name[index].fullName;
}
You asked for an explanation of line. The line while (cin >> line) tries to take text from the standard input and put it into line. By default, this will stop when it encounters whitespace (space, tab, return, etc.) If it succeeds, then the body of the while loop is executed and we add what was input to the vector. If not, then we assume we're at the end of input and stop. We can then process the vector. (In the code linked below, I just output it since I don't know what name_index or name_number are.
(Working code here)
The way cin works, is it will accept any amount of input and separate them each by spaces, when you ask for specific input it prompts the user to give input, and then only takes the very first string (up until the space). If there are any more input after that, another cin >> input will just retrieve that value without prompting the user again. You can tell when the actual end of the input is reached when there is only a newline character left. This code should allow you to type in multiple strings separated by spaces and then process them all at once after the user enters the text:
char input[4];
do // Start our loop here.
{
// Our very first time entering here, it will prompt the user for input.
// Here the user can enter multiple 4 character strings separated by spaces.
// On each loop after the first, it will pull the next set of 4 characters that
// are still remaining from our last input and use it without prompting the user
// again for more input.
// Once we run out of input, calling this again will prompt the user for more
// input again. To prevent this, at the end of this loop we bail out if we
// have come accros the end of our input stream.
cin >> input;
// input will be filled with each 4 character string each time we get here.
int i = name_index[name_number(input)];
cout << name[i].fullName;
} while (cin.peek() != '\n'); // We infinitely loop until we reach the newline character.
EDIT: Also, keep in mind that allocating only 4 characters to input does not account for the end of string character '\0' that will be tacked on the end. If the user inputs 4 characters then it will actually access bad memory when it assigns the string to your input. There are 4 characters + 1 end character which means you need a minimum of 5 characters allocated for your input. The best way is to just use std::string as it will size itself properly even if the user enters more than 4 characters.