This is a very strange issue. I'm trying to print a large text file, it's a Wikipedia entry. It happens to be the page on Velocity. So, when I tell it to print the file, it prints "In", when it should print "In physics, velocity is etc, etc etc".
Here's the code I'm using to print out:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream wiki;
wiki.open("./wiki/velocity.txt");
char* wikiRead;
wiki >> wikiRead;
cout << wikiRead << endl;
wiki.close();
}
Please help.
wiki >> wikiRead;
The default delimiter for stream is space, so when the stream encounters a space, it simply stops reading, that is why it reads only one word.
If you want the stream to read all words, the you've to use a loop as:
char* wikiRead = new char[1024]; //must allocate some memory!
while(wiki >> wikiRead)
{
cout << wikiRead << endl;
}
wiki.close();
delete []wikiRead; //must deallocate the memory
This will print all the words in the file, each on a new line. Note if any of the word in the file is more than 1024 character long, then this program would invoke undefined behavior, and the program might crash. In that case, you've to allocate a bigger chunk of memory.
But why use char* in the first place? In C++, you've better choice: Use std::string.
#include<string>
std::string word;
while(wiki >> word)
{
cout << word << endl;
}
wiki.close();
Its better now.
If you want to read line-by-line, instead of word-by-word, then use std::getline as:
std::string line;
while(std::getline(wiki, line))
{
cout << line << endl;
}
wiki.close();
This will read a complete line, even if the line contains spaces between the words, and will print each line a newline.
You ask the stream to read the (binary) value of a pointer (probably 4 bytes, depending on your machine architecture), then you ask it to print the text pointed to by those 4 bytes!
I wonder why you ignored the compiler warning (most of the modern compiler warns you about using uninitialized variables). How about this?
ifstream wiki;
wiki.open("./wiki/velocity.txt");
char wikiRead[255];
wiki >> wikiRead;
cout << wikiRead << endl;
wiki.close();
Alternatively I'd suggest you to use string object with getline to get a single line of text.
string str;
getline(wiki, str);
The >> operator applied to a char * reads only one word. Moreover, you're reading into an uninitialized pointer, which is not valid. Usually std::string, not char *, is used for string processing in C++.
If you only want to print the file's contents, you can hook the file's buffer directly to std::cout:
int main() {
std::ifstream wiki("./wiki/velocity.txt");
std::cout << wiki.rdbuf() << '\n';
}
If you want to put the contents into an automatically-allocated string, use std::getline with the delimiter disabled.
int main() {
std::ifstream wiki("./wiki/velocity.txt");
std::string wiki_contents;
getline( wiki, wiki_contents, '\0' /* do not stop at newline */ );
std::cout << wiki_contents << '\n'; // do something with the string
}
Since you want to read a large file, reading it block by block is a better way.
ifstream wiki;
wiki.open("./wiki/velocity.txt");
const int buf_size = 1024;
char* wikiRead = 0;
int cnt = 1;
do
{
wikiRead = realloc( wikiRead, bufsize*cnt );
wiki.Read( wikiRead + (bufSize*(cnt-1)), buf_size ); //appends to reallocated memory
cnt++;
}while( !wiki.eof())
wikiRead[(bufSize*(cnt-2)) + wiki.gcount() + 1] = '\0'; // null termination.
wiki.Close();
cout << wikiRead;
delete[] wikiRead;
The operator>> is designed to only read one word at a time. If you want to read lines, use getline.
#include <iostream>
#include <fstream>
#include<string>
using namespace std;
int main()
{
ifstream wiki;
wiki.open("./wiki/velocity.txt");
string wikiRead;
while (getline(wiki, wikiRead))
{
cout << wikiRead << endl;
}
wiki.close();
}
Related
This is for a homework assignment, but what I am presenting is a small test program for a chunk of my assignment.
Starting out, I am to have a list of songs in file "songs.txt". My current file looks like this.
Maneater;4;32
Whip It;2;41
Wake Me Up Before You Go-Go;3;45
The file simply contains a song title, and the duration in minutes and seconds, with the title, minutes, and seconds separated by semicolons. The full file is supposed to contain the Artists and Album as well, all separated by semicolons. Anyways, the code.
#include<iostream>
#include<cstring>
#include<fstream>
#include<cstdlib>
using namespace std;
const int CAP = 100;
const int MAXCHAR = 101;
struct songInfo
{
char title[CAP];
char durMin[CAP];
char durSec[CAP];
};
void getData(songInfo Song[], int listSize, int charSize);
int main()
{
string fileName;
songInfo Song[CAP];
ifstream inFile;
cout << "What is the file location?: ";
cin >> fileName;
inFile.open(fileName.c_str());
if (inFile.fail())
{
cout << "Cannot open file " << fileName << endl;
exit(1);
}
getData(Song, CAP, MAXCHAR);
for (int i=0;i<CAP;i++)
{
cout << Song[i].title << " - "
<< Song[i].durMin << ":"
<< Song[i].durSec << endl;
}
cout << "Press any button to continue..." << endl;
cin.get(); cin.get();
return 0;
}
void getData(songInfo Song[], int listSize, int charSize)
{
for (int i = 0; i < listSize; i++)
{
cin.get(Song[i].title, charSize, ';');
cin.get(Song[i].durMin, charSize, ';');
cin.get(Song[i].durSec, charSize, '\n');
i++;
cin.ignore();
}
}
The program compiles correctly without incident, but the output is not what I want it to be. What should happen:
Test.cpp opens songs.txt
Read the first char array into Song[i].title, delimited by ';'
Read the second char into Song[i].durMin, delimited by ';'
Read the third char into Song[i].durSec, delimited by newline
After compiling the code and running it, I get this as my output:
~/project2Test> ./test
What is the file location?: songs.txt
The program then hangs here and I have to ctrl+C out
First, what am I doing wrong?
Second, how do I go about fixing what I screwed up?
Also, as a note for class rules, I am not allowed to use any strings except for the filename. Other than that, all words must be chars.
A debugger is definitely a good thing to use for a problem like this.
Your hanging problem is occurring because in your get_data function you are using cin.get instructing your program to get input from the standard input file. You intended to use the file you defined, "inFile" not the standard input cin.
As an aside it is not clear to me why you are incrementing i twice per iteration of the for loop.
Use inFile.get() instead of cin. You need to pass inFile to the function first.
Put a print statement in the for loop to see what is happening.. A future issue that might crop up is that if you are on a Windows machine and have \r\n line endings. Unix uses \n, Windows uses \r\n
I'm pretty sure that this is a common question, but I can't find an example similar to mine, so..
I have a text file called input.txt that has: 0.0001234 1.0005434 0.0005678 1.0023423 0.00063452 1.0001546 0.00074321 1.00017654 in it.
Now I want to write a program to read that into an array, and then quickly check that it worked. So far, I've got:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
double PA[8];
int n;
ifstream myfile ("input.txt");
if (myfile.is_open())
{
while (! myfile.eof() )
{
getline (myfile,line);
cout << PA[line]<< endl;
}
myfile.close();
}
else cout << "Unable to open file";
for (n=0; n<8; n++) // to print the array, to check my work
{
cout << " {" << PA[n] << "} ";
}
system("PAUSE");
return 0;
}
My problem so far is that I keep getting the error: line was not declared. And I want to use the array later with floats to calculate new data. I think I'm doing it wrong for that.. Any help? Thanks!
declare line variable
int n, line = 0;
std::string value;
proper load data:
getline (myfile,value);
PA[line] = atof(value.c_str());
cout << PA[line]<< endl;
line++;
the variable line here
cout << PA[line]<< endl;
is not declared. and if you declare it, you also have to give it a value, otherwise it's undefined and the PA[line] is undefined, in other words: will crash.
the entire while block seems suspicious:
while (! myfile.eof() )
{
getline (myfile,line);
cout << PA[line]<< endl;
}
are you sure about the getline call?
I know a getline with this signature:
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
and that does not even match the number of arguments in your version.
if your input file has more than 8 lines on input, than the while loop will have that many interations - and your array has only space for 8 elements.
You need to declare the variable you called 'line' as follows:
int i=0;
while (! myfile.eof() && i<8)
{
std::string line; // this was the missing statement
getline (myfile,line);
double value = atof(line.c_str()); // convert line form char* to double
PA[i++] = value;
cout << value << endl;
}
Note that you need to convert line as double and use increment variable 'i' (for example, as I did. Make sure not overflowing PA capacity by checking i agains the size (currently 8, which should not hard coded, btw).
Also note that you shouldn't print the result if file access failed.
Special characters disappear when I pass a string into a stringstream.
I tried this code which can directly be tested:
#include <iostream>
#include <sstream>
using namespace std;
int main(int argc, char* argv[]) {
string txt("hehehaha\n\t hehe\n\n<New>\n\ttest:\t130\n\ttest_end:\n<New_end>\n");
cout << txt << endl; // No problem with new lines and tabs
stringstream stream;
stream << txt;
string s;
while(stream >> s) {
cout << s; // Here special characters like '\n' and '\t' don't exist anymore.
}
cout << "\n\n";
return 0;
}
What can I do to overcome this?
Edit: I tried this:
stream << txt.c_str();
and it worked. But I don't know why...
basically, you are just printing it wrong, it should be:
cout << stream.str() << endl;
Some details. You are calling operator<<(string) which
overloads operator<< to behave as described in ostream::operator<<
for c-strings
The referred to behaviour is explained here:
(2) character sequence Inserts the C-string s into os. The terminating
null character is not inserted into os. The length of the c-string is
determined beforehand (as if calling strlen).
Strlen documentation says that the result is affected by nothing but
the terminating null-character
Indeed, strlen(tmp) in your examples outputs 55.
The stream, hence, gets "assigned" everything which comes up to the 55th character in your input string.
cout << stream.str() << endl;
will show you that this is indeed what happens.
A parenthesis: you can modify the behaviour of the stream << txt line by means of setting/unsetting flags, as in
stream.unsetf ( std::ios::skipws );
which you should try out.
The statement
while(stream >> s)
Is the problem, it gives you one token on each call, using white spaces for splitting and therefor ignoring them.
I wrote the code below that successfully gets a random line from a file; however, I need to be able to modify one of the lines, so I need to be able to get the line character by character.
How can I change my code to do this?
Use std::istream::get instead of std::getline. Just read your string character by character until you reach \n, EOF or other errors. I also recommend you read the full std::istream reference.
Good luck with your homework!
UPDATE:
OK, I don't think an example will hurt. Here is how I'd do it if I were you:
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
static std::string
answer (const string & question)
{
std::string answer;
const string filename = "answerfile.txt";
ifstream file (filename.c_str ());
if (!file)
{
cerr << "Can't open '" << filename << "' file.\n";
exit (1);
}
for (int i = 0, r = rand () % 5; i <= r; ++i)
{
answer.clear ();
char c;
while (file.get (c).good () && c != '\n')
{
if (c == 'i') c = 'I'; // Replace character? :)
answer.append (1, c);
}
}
return answer;
}
int
main ()
{
srand (time (NULL));
string question;
cout << "Please enter a question: " << flush;
cin >> question;
cout << answer (question) << endl;
}
... the only thing is that I have no idea why do you need to read string char by char in order to modify it. You can modify std::string object, which is even easier. Let's say you want to replace "I think" with "what if"? You might be better off reading more about
std::string and using find, erase, replace etc.
UPDATE 2:
What happens with your latest code is simply this - you open a file, then you get its content character by character until you reach newline (\n). So in either case you will end up reading the first line and then your do-while loop will terminate. If you look into my example, I did while loop that reads line until \n inside a for loop. So that is basically what you should do - repeat your do-while loop for as many times as many lines you want/can get from that file. For example, something like this will read you two lines:
for (int i = 1; i <= 2; ++i)
{
do
{
answerfile.get (answer);
cout << answer << " (from line " << i << ")\n";
}
while (answer != '\n');
}
i have a little problem on writing the string into a file,
How can i write the string into the file and able to view it as ascii text?
because i am able to do that when i set the default value for str but not when i enter a str data
Thanks.
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
fstream out("G://Test.txt");
if(!out) {
cout << "Cannot open output file.\n";
return 1;
}
char str[200];
cout << "Enter Customers data seperate by tab\n";
cin >> str;
cin.ignore();
out.write(str, strlen(str));
out.seekp(0 ,ios::end);
out.close();
return 0;
}
Please use std::string:
#include <string>
std::string str;
std::getline(cin, str);
cout << str;
I'm not sure what the exact problem in your case was, but >> only reads up to the first separator (which is whitespace); getline will read the entire line.
Just note that >> operator will read 1 word.
std::string word;
std::cin >> word; // reads one space seporated word.
// Ignores any initial space. Then read
// into 'word' all character upto (but not including)
// the first space character (the space is gone.
// Note. Space => White Space (' ', '\t', '\v' etc...)
You're working at the wrong level of abstraction. Also, there is no need to seekp to the end of the file before closing the file.
You want to read a string and write a string. As Pavel Minaev has said, this is directly supported via std::string and std::fstream:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ofstream out("G:\\Test.txt");
if(!out) {
std::cout << "Cannot open output file.\n";
return 1;
}
std::cout << "Enter Customer's data seperated by tab\n";
std::string buffer;
std::getline(std::cin, buffer);
out << buffer;
return 0;
}
If you want to write C, use C. Otherwise, take advantage of the language you're using.
I can't believe no one found the problem. The problem was that you were using strlen on a string that wasn't terminated with a null character. strlen will keep iterating until it finds a zero-byte, and an incorrect string length might be returned (or the program might crash - it's Undefined Behavior, who knows?).
The answer is to zero-initialize your string:
char str[200] = {0};
Supplying your own string as the value of str works because those in-memory strings are null-terminated.