I have been working on this for a while and can't fix it. I am very new to C++. So far I can get 10 things into my array but the output is not legible, it's just a bunch of numbers. I have read other posts with similar code but for some reason mine isn't working.
The input text file is 10 lines of fake data like this:
56790 "Comedy" 2012 "Simpsons" 18.99 1
56791 "Horror" 2003 "The Ring" 11.99 7
My code is here:
(My output is below my code)
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct DVD {
int barcode;
string type;
int releaseDate;
string name;
float purchaseprice;
int rentaltime;
void printsize();
};
int main () {
ifstream in("textfile.exe");
DVD c[10];
int i;
for (int i=0; i < 10; i++){
in >> c[i].barcode >> c[i].type >> c[i].releaseDate >>
c[i].name >> c[i].purchaseprice >> c[i].rentaltime;
}
for (int i=0;i< 10;i++) {
cout << c[i].barcode<<" ";
cout << c[i].type<<" ";
cout << c[i].releaseDate<<" ";
cout << c[i].name << " ";
cout << c[i].purchaseprice << " ";
cout << c[i].rentaltime << "\n";
}
return 0;
}
My output looks similar to garbage, but there are 10 lines of it like my array:
-876919876 -2144609536 -2.45e7 2046
A comment on what to study to modify my code would be appreciated.
As suggested by cmbasnett, ifstream in("textfile.exe") reads in an executable file. If you with for the program to read in a text file, changing it to ifstream in("textfile.txt") should work.
You always need to check that your input is actually correct. Since it may fail prior to reading 10 lines, you should probably also keep a count of how many entries you could successfully read:
int i(0);
for (; i < 10
&& in >> c[i].barcode >> c[i].type >> c[i].releaseDate
>> c[i].name >> c[i].purchaseprice >> c[i].rentaltime; ++i) {
// ???
}
You actual problem reading the second line is that your strings are quoted but the approach used for formatted reading of strings doesn't care about quotes. Instead, strings are terminated by a space character: the formatted input for strings will skip leading whitespace and then read as many characters until another whitespace is found. On your second line, it will read "The and then stop. The attempt to read the purchaseprice will fail because Ring isn't a value numeric value.
To deal with that problem you might want to make the name quotedstring and define an input and output operators for it, e.g.:
struct quoted_string { std::string value; };
std::istream& operator>> (std::istream& in, quoted_string& string) {
std::istream::sentry cerberos(in); // skips leading whitespace, etc.
if (in && in.peek() == '"') {
std::getline(in.ignore(), string.value, '"');
}
else {
in.setstate(std::ios_base::failbit);
}
return in;
}
std::ostream& operator<< (std::ostream& out, quoted_string const& string) {
return out << '"' << string.value << '"';
}
(note that the code isn't test but I'm relatively confident that it might work).
Just to briefly explain how the input operator works:
The sentry is used to prepare the input operation:
It flushes the tie()d std::ostream (if any; normally there is none except for std::cin).
It skips leading whitespace (if any).
It checks if the stream is still not in failure mode (i.e., neither std::ios_base::failbit nor `std::ios_base::badbit are set).
To see if the input starts with a quote, in.peek() is used: this function returns an int indicating either that the operation failed (i.e., it returns std::char_traits<char>::eof()) or the next character in the stream. The code just checks if it returns " as it is a failure if the stream returns an error or any other character is present.
If there is a quote, the quote is skipped using file.ignore() which by default just ignores one character (it can ignore more characters and have a character specified when to stop).
After skipping the leading quote, std::getline() is used to read from file into string.value until another quote is found. The last parameter is defaulted to '\n' but for reading quoted string using a '"' is the correct value to use. The terminating character is, conveniently, not stored.
Related
This question already has an answer here:
C++ - overloading operator >> for my string class
(1 answer)
Closed 9 months ago.
I am trying to read user entered data from the stream and then store it in a custom String class.
To my best knowledge, std::getline() can route data only to std::string , that is why I need to come up with something else, as my project is not allowed to use std::string class.
My code looks like this:
String street();
std::cout << "Street: "; std::cin >> std::noskipws;
char c='\0';
while(c!='\n'){
std::cin >> c;
street=street+c;
}std::cin >> std::skipws;
int bal=0;
std::cout << "Balance: "; std::cin >> bal;
To my best knowledge, std::getline() can route data only to std::string , that is why I need to come up with something else, as my project is not allowed to use std::string class.
Note that std::getline and std::istream::getline are two separate functions. The former will work with std::string while the latter will work with C-style strings (i.e. sequences of characters that are terminated by a null character).
Therefore, if you are not allowed to use std::string, then you can still use std::istream::getline, for example like this:
char line[200];
String street;
std::cout << "Street: ";
if ( std::cin.getline( line, sizeof line ) )
{
//the array "line" now contains the input, and can be assigned
//to the custom String class
street = line;
}
else
{
//handle the error
}
This code assumes that your custom class String has defined the copy assignment operator for C-style strings.
If it is possible that the lines will be larger than a fixed number of characters and you want to support such lines, then you could also call std::istream::getline in a loop:
char line[200];
String street;
std::cout << "Street: ";
for (;;)
{
std::cin.getline( line, sizeof line );
street += line;
if ( std::cin.bad() )
{
//TODO: handle error and break loop, for example by
//throwing an exception
}
if ( !std::cin.fail() || std::cin.eof() )
break;
std::cin.clear();
}
This code assumes that operator += is defined for class String.
This loop will continue forever until
getline succeeds (i.e. it is able to extract (but not store) the newline character), or
end-of-file is reached (eofbit is set), or
an error occurs (badbit is set).
You can use the C function "getchar()" to read a single character from standard input. This link describes it: https://www.ibm.com/docs/en/i/7.3?topic=functions-getc-getchar-read-character.
Here is my code:
String street=();
std::cout << "Street: ";
char c='\0';
while(c!='\n'){
c = getchar();
street=street+c;
}
int bal=0;
std::cout << "Balance: "; std::cin >> bal;
cout << street << endl;
I hope this will help you, and I recommend you make an independent function that will read line from standard input and whose return type will be "String". You can declare it as:
String readLine();
And I also recommend you to pay attention to that while loop because string that is obtained from that loop will have character '\n' at the end of it.
So I was taking input some integers and then taking input some sentences.
This code works fine:
#include<bits/stdc++.h>
using namespace std;
main(){
int c,b,n,i;string s;
cin>>n>>b>>c;
for(i=0;i<n;i++){
cin>>ws;
getline(cin,s,'\n');
cout<<s;
}
}
Example:
3 3 3
This is weird
This is weirdDefinitely makes
Definitely makesNo sense
No sense
However, when I try to omit the cin>>ws inside the forloop, it doesn't work properly, eg this code segment,
#include<bits/stdc++.h>
using namespace std;
main(){
int c,b,n,i;string s;
cin>>n>>b>>c;
for(i=0;i<n;i++){
getline(cin,s,'\n');
cout<<s;
}
}
Example:
3 3 3
This is weird
This is weirdDefinitely makes
Definitely makes
..and terminates there instead of taking all three inputs.
Why is that? cin>>ws extracts all whitespace from the input but isn't getline() doing that too? So why does it not work properly when I omit cin>>ws in the forloop?
std::getline() extract characters until it extracted the first delimiter character (by default '\n'). The delimiter is not stored in the result but it is extracted. It does not extract whitespace in general or multiple delimiter characters.
As an aside: always check whether input works after trying to read a value.
In the example printed, the issue is is that after formatted input, i.e., using the >> operator, whitespaces are not extracted. That is, the first calls to std::getline() extracts the empty string terminated by the initial newline. It generally is necessary to extract trailing whitespace when switching between formatted and unformatted I/O. That is, You'd want code like
if (cin>>n>>b>>c >> std::ws) {
for(i=0;i<n;i++){
if (getline(cin,s,'\n')) {
cout << "i=" << i << ":'" << s << "'\n";
}
}
}
I can't recommend input operations without adding check for success. The output is changed to make it more easily visible what is going on: try the code with/without this particular std::endl to see what is happening.
When you use cin >> it doesn't remove any whitespace after the input. This means the newline that terminated the first 3 inputs is still in the buffer, waiting to be read by the first getline. Since there's nothing before the newline, the first getline delivered an empty string. Your output should have included a newline so you could have seen the empty line, then it would have made sense.
Originally the code you posted showed a cin >> ws just before the for loop which would have eliminated this problem.
The default delimiter for getline() is '\n', so there is no need to include that in the getline call, though, it should not change the functionality.
See for example Same as getline(input, str, input.widen('\n')), that is, the default delimiter is the endline character.
The change in formatting from the integer input to the getline() input leaves some whitespace (endl) after the integer as explained by #DietmarKühl.
You can change the getline() call to eliminate the delimiter to
getline(cin,s);
which will cause getline() to use '\n' as the default delimiter.
I have modified the 'n' variable to count and removed the other integers to make the code a little simpler to read:
#include <iostream>
int main()
{
int i; // index
int count; // number of strings to accept
std::string str;
std::cout << "Input the number of strings you would like me to process: " << std::endl;
std::cin >> count;
if (std::cin >> count >> std::ws) {
for (i = 0; i < count; i++) {
if (getline(std::cin, str)) {
std::cout << "i=" << i << ":'" << str << "'\n";
}
}
}
}
Cin doesn't extract all white spaces, it just gets the first word until the first white space. It is like having a getline with a space delimiter(not quite but close to).
Getline takes the whole line and has the default '\n' delimiter like mentioned above.
Ex:
string a = "Stack Overflow is awesome";
can give you Stack and getline will give you everything at that line
I'm supposed to force the user to input a number then a space then a string and if the format was wrong, I should terminate the program. When I used the cin, the compiler ignored the space and considered the first character of the string to be the one he should check to make sure that the user inputs a space and since the first character is always not a space he terminates.
What should I do ?!
I assume by "when I used the cin" you mean with the >> operator. Reading from an istream with >> is a formatted input function which means the input is pre-formatted for you, one of the effects is skipping over whitespace by default.
There are several ways to solve your problem, including reading a single character at a time (using an unformatted input function such as std::istream::get) or reading a line at a time and parsing the line.
Alternatively, you can turn off skipping of whitespace characters with the noskipws manipulator:
#include <iostream>
#include <string>
int main()
{
int num;
char c;
std::string str;
if (std::cin >> std::noskipws >> num >> c >> str && c == ' ')
std::cout << "ok" << std::endl;
else
std::cout << "Failed" << std::endl;
}
Use std::getline. If you require further help, make sure to post a code sample which demonstrates the problem, otherwise you won't get specific answers.
Example:
#include <string>
#include <iostream>
int main()
{
std::string input;
std::cout << "Please enter a number and a string, separated by a space:";
std::getline(std::cin, input);
// Code to validate input
}
I am reading in a text file and have found that it will not print the blank characters between the words. I want to read each character a character at a time and then print the character to the output window. The read will read the file but does not show the blank spaces and I have not been able to find out why the blank spaces are being skipped.
Question: Why is my read not reading the blank characters in my test file?
When i find a blank character I want to print the word Blank Space.
Code:
#include "stdafx.h"
#include "iostream"
#include<iostream>
#include<fstream>
void readTestFile()
{
char ch;
std::fstream fin("C:/Users/itpr13266/Desktop/myTest.txt", std::fstream::in);
while (fin >> ch) {
std::cout << "Letter: " << ch << std::endl;
if (ch == ' ') <-- should catch a blank spaces
{
std::cout << "Blank Space" << std::endl;
}
else <-- Just write the letter
{
std::cout << ch << std::endl;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
readTestFile();
getchar();
return 0;
}
Test File:
This is testing for fprintf...
This is testing for fputs...
Output
Letter: T
T
Letter: h
h
...etc...
The standard input function istream::operator>>() skips all leading whitespace before performing input. If you need to obtain spaces, there are a couple options you can use:
std::noskipws
By setting the std::ios_base::noskipws flag, the stream will not discard leading whitespace and ch will be given the value of each consecutive character. Note that this succeeds only with the overload that takes a char (ch will be given the value of the space). For any other data type this will not work:
while (fin >> std::noskipws >> ch)
{
// ...
}
std::istream::get()
get() is an UnformattedInputFunction function, and thus will not parse the input beforehand.
while (fin.get(ch))
{
// ...
}
std::istreambuf_iterator<>
You can also use iterators to work directly with the buffer. std::istreambuf_iterator<> also doesn't parse the input:
std::copy(std::istreambuf_iterator<char>{fin},
std::istreambuf_iterator<char>{},
std::ostreambuf_iterator<char>{std::cout},
You are performing formatted input, use unformatted input
std::fstream::traits_type::int_type ch;
while((ch = fin.get()) != std::fstream::traits_type::eof()) {
// ...
}
By default, operator>> on streams skips any leading whitespace before parsing the value. This is, for example, what allows you to read the input 30 60 95 with int i,j,k; fin >> i >> j >> k; (otherwise reading j would fail because after the 30, there follows a space, not an integer).
You now have two options if you want to read the spaces as well:
(preferred): Use the member function get() for unformatted reading of a character.
Instruct the stream not to eat whitespace before reading: fin >> std::noskipws >> ch.
Read more about the different iostream methods. In particular, you are using istream's operator>>. Take careful note of how it is designed to work; it uses whitespace as a delimiter and does not store the whitespace.
If you want to read every char from your stream (e.g. a file stream), you should not be using >>, but rather consider using istream::get().
// stream is an istream, such as cin or ifstream
char ch;
while (ch = stream.get()) { }
This worked for me. I set it in a function so you can copy paste. It detects the space, and also the change in line. I tried it with ASCII art and it worked fine.
void print2()
{
char ch;
std::fstream myStream("GameOver.txt", std::fstream::in);
while (myStream.get(ch))
{
std::cout << ch;
}
}
I understand that cin.eof() tests the stream format. And while giving input, end of character is not reached when there is wrong in the input. I tested this on my MSV C++ 2010 and am not understanding the strange results. No matter what I give the input, I am getting Format Error message that is present in the program.
#include <iostream>
using namespace std;
int main()
{
int i;
cin>> i;
if(!cin.eof())
{
cout<< "\n Format Error \n";
}
else
{
cout<< "\n Correct Input \n";
}
getchar();
return 0;
}
Results I expected:
Values for i =
10 => Correct Input but the output is Format Error
12a => Format Error
Could someone explain where I am going wrong. Thanks.
std::cin.eof() tests for end-of-file (hence eof), not for errors. For error checking use !std::cin.good(), the built-in conversion operator (if(std::cin)) or the boolean negation operator (if(!std::cin)).
Use a direct test of the status of the stream with:
while (cin >> i)
{
...
}
For an input stream to enter the EOF state you have to actually make an attempt to read past the end of stream. I.e. it is not enough to reach the end-of-stream location in the stream, it is necessary to actually try to read a character past the end. This attempt will result in EOF state being activated, which in turn will make cin.eof() return true.
However, in your case you are not only not doing that, you (most likely) are not even reaching the end of stream. If you input your 10 from the keyboard, you probably finished the input by pressing the [Enter] key. This resulted in a new-line character being added to the input stream. So, what you are actually parsing with >> operator in this case is actually a 10\n sequence. Since you requested an int value from the stream, it only reads the numerical characters from the stream, i.e. it reads 1 and 0, but it stops at \n. That \n remains in the stream. You never read it. So, obviously, your code never reaches the end-of-file position in the stream. You have to reason to expect cin.eof() to become true in such case.
#include <iostream>
int main() {
using namespace std;
int i;
if (cin >> i) {
cout << "Extracted an int, but it is unknown if more input exists.\n";
char c;
if (cin.get(c)) { // Or: cin >> c, depending on how you want to handle whitespace.
cin.putback(c);
cout << "More input exists.\n";
if (c == '\n') { // Doesn't work if you use cin >> c above.
cout << "But this was at the end of this line.\n";
}
}
else {
cout << "No more input exists.\n";
}
}
else {
cout << "Format error.\n";
}
return 0;
}
Also see Testing stream.good() or !stream.eof() reads last line twice.
Sample session with the above program, note that input lines are marked with comments not present in the actual output:
$ your-program
12 # input
Extracted an int, but it is unknown if more input exists.
More input exists.
But this was at the end of this line.
$ your-program
12a # input
Extracted an int, but it is unknown if more input exists.
More input exists.
$ echo -n 12 | your-program
Extracted an int, but it is unknown if more input exists.
No more input exists.
$ your-program
a # input
Format error.
Assuming your input is line based, I suggest that you read the whole line using std::getline(). Once you have the line, you can analyse it and decide whether it contains correct or wrong input. Put the line into std::istringstream and do something like the following:
Edit: Changed !! iss to static_cast<bool>(iss) for compatibility with C++0x.
std::istringstream iss (line);
char ch;
long lval;
// read the input
iss >> lval;
// result variable will contain true if the input was correct and false otherwise
result
// check that we have read a number of at least one digit length
= static_cast<bool>(iss)
// check that we cannot read anything beyond the value read above
&& ! (iss >> ch);
Adding to the previous answer:
After reading your input (like 10), you are not at end-of-file, as you can easily type some more. How is the system to know that you will not?
When reading your second input (12a), it correctly reads all the digits that can be part of an integer. The letter 'a' cannot, so it is left for some possible later input. For example, you can read all parts of 12a with this code
int i;
char c;
cin >> i >> c;
cin.eof() test if the stream has reached end of file which happens if you type something like Ctrl+C (on Windows), or if input has been redirected to a file etc.
To test if the input contains an integer and nothing but an integer, you can get input first into a string and then convert that with a stringstream. A stringstream indeed reaches eof if there's no more to be extracted from it.
#include <iostream>
#include <sstream>
#include <string>
int main() {
using namespace std;
int i;
string input;
cin >> input; //or getline(cin, input)
stringstream ss(input);
if (ss >> i && ss.eof()) { //if conversion succeeds and there's no more to get
cout<< "\n Correct Input \n";
}
else {
cout<< "\n Format Error \n";
}
return 0;
}