When I add a file to a char array, then print, I get garbage output (random ASCII symbols). The file contains only text (a paragraph).
The code is as follows:
int arraySize = 0;
string line;
while(getline(inFile, line)){
//cout << line << endl; // this will print array fine.
arraySize += line.length();
}
char message[arraySize];
char encrypted[arraySize];
//adds file to array
int i = 0;
while(inFile.good() && !inFile.eof()){
inFile.get(message[i]);
i++;
}
message[i] = '\0';
//prints array
for(int i = 0; i < arraySize; i++){
cout << message[i]; //this returns garbage values
}
I believe its printing garbage because it thinks there's nothing in the array messages, but I do not know why there is "nothing there."
The reason is you reached the end of file when you count the length of the text thus the read pointer is at the end of the file and you used it again to read the text file.
To do it: Get the read pointer again to the beginning:
inFile.clear();
inFile.seekg(0, ios::beg);
while(inFile.get(message[i])){
i++;
}
Also don't use: while (!infile.eof()) it is considered to be incorrect.
What I recommend is to use std::vector you don not mind about the file size or any allocation / de-allocation of memory. So your code can be like this:
std::ifstream inFile("data.txt"); // your file name here
std::string strLine;
std::vector<std::string> vecStr;
while(std::getline(inFile, strLine))
vecStr.push_back(strLine);
for(int i(0); i < vecStr.size(); i++)
std::cout << vecStr[i] << std::endl;
inFile.close();
Have you seen how the code is charm above?
NB: You got the garbage values because the array is only declared but not initialized:
The first read gets the length of the text. But moved the read pointer to the end and then you did:
while(inFile.good() && !inFile.eof()){ // Will fail because inFile.eof() is true from the previous read.
//std::cout << "Inside the reading loop" << std::endl;
inFile.get(message[i]);
i++;
}
As you can see above the loop will not be executed because the previous read reached the eof thus the array is just declared without being initialized thus as you know it contains garbage values.
To confirm that the loop is not executed un-comment the line above and see if the loop is executed. The result is no printing message which means it was not executed.
Related
There's some code I wrote that should read all new lines in a text file, but it gets stuck on one of the loops it runs.
The code is as follows:
#define MAX_MESSAGE_LENGTH 200;
fstream("some/random/file.txt", ios::in | ios::out);
streampos fileSizeReference = 0;
vector<string> messages;
vector<string> onDisplay;
char message[MAX_MESSAGE_LENGTH];
if((int)fileSizeReference == 0)
fileReader.seekg(0);
else
fileReader.seekg((int)fileSizeReference + 1);
cout << "Test" << endl;
// Add all new messages to the messages vector
do
{
fileReader.getline(message, MAX_MESSAGE_LENGTH);
string newMsg = message;
messages.push_back(newMsg.substr(0, MAX_MESSAGE_LENGTH));
}
while (!fileReader.eof());
//
cout << "Test" << endl;
fileReader.seekg(0, ios::beg);
// Set the newest messages in the onDisplay vector
for(int i = 0; i < amountOfMessages; i++)
{
onDisplay[i] = messages[messages.size() - (i + 1)];
}
//
cout << "Test" << endl;
// Display new messages
int current_Y = 0;
for(int i = 0; i < amountOfMessages; i++)
{
current_Y = renderText(messages[i], current_Y);
}
//
// set the new file size as the fileSizeReference
fileReader.seekg(0, ios::end);
fileSizeReference = fileReader.tellg();
The text file looks like this:
Hello World!
Carpe Diem
Random Message
Whenever I run this code, I don't get past the first do-while loop.
This is the first run, so the fileSizeReference is 0.
The newMsg variable within the loop is always an empty string, just like the message array.
Does any one of you know why my code gets stuck?
Thank you in advance!
You have two errors (at least).
do
{
fileReader.getline(message, MAX_MESSAGE_LENGTH);
string newMsg = message;
messages.push_back(newMsg.substr(0, MAX_MESSAGE_LENGTH));
}
while (!fileReader.eof());
should be
while (fileReader.getline(message, MAX_MESSAGE_LENGTH))
{
string newMsg = message;
messages.push_back(newMsg.substr(0, MAX_MESSAGE_LENGTH));
}
More reading Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
Incidentally those two lines in the while loop can also be simplified, just this will work perfectly well.
messages.push_back(message);
And secondly after finishing reading the stream will be in an error state, which you need to clear before seeking back to the beginning of the file (closing and reopening the file would also work).
while (fileReader.getline(message, MAX_MESSAGE_LENGTH))
{
string newMsg = message;
messages.push_back(newMsg.substr(0, MAX_MESSAGE_LENGTH));
}
fileReader.clear();
fileReader.seekg(0, ios::beg);
not sure what i'm doing wrong but this is my code
int main (){
int marks [100];
int i=0;
ifstream inputfile;
ofstream outputfile;
inputfile.open("data.txt");
if(!inputfile.is_open())
{
cout<< "File did not open"<< endl;
return 0;
}
cout<<"Marks in File:"<<endl;
while (marks [i] != -1)
{
inputfile>>marks[i];
cout << marks[i] <<endl;
i++;
}
return 0;
}
the output is messed up and returns stuff that was never in the data file to begin with
Here is the minimal code for reading data from a file and write it to console. Description is added as comments
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
int main()
{
ifstream configrecord("D:\\Temp\\temp.txt"); // opening the file named temp for reading.
if(configrecord.good()) // check whether the file is opened properly.
{
string line;
while (getline(configrecord, line)) // reading a line from file to std::string
{
cout << line; // printing the line, if you want it to store in an array, you can use the std::string::data() api to get the character pointer.
}
configrecord.close(); // closing the file after reading completed
}
}
If we translate your code to English, we get:
Check if the current array element is -1, if it is, break the loop.
Read the value into the current array element.
Output the value.
Move to the next array element and repeat.
Notice a big problem: We're checking if the value is -1 before we actually read it. We need to reverse the order of steps 1 and 2 so that we get:
Read the value into the current array element.
Check if the current array element is -1, if it is, break the loop.
Output the value.
Move to the next array element and repeat.
We can do this by using true as our loop condition and then using an if statement to check if the inputted value is -1 later in the loop, using break to break the loop if it is.
#include <fstream>
#include <iostream>
//using namespace std; is considered bad practice
int main()
{
std::ifstream inFile("input.txt");
int marks[100];
//check if file is open stuff...
for(int i = 0; true; i++)
{
inFile >> marks[i];
if(marks[i] == -1) break;
std::cout << marks[i] << '\n'; //endl flushes the buffer, unnecessary here.
}
}
Of Note: it is good practice that if you use an if statement, you also include an else statement. Also, your while loop is confusing, because it stops if it encounters negative one, so I am assuming you know that integer -1 is not in the file.
int n = -1;
if(!inputfile.is_open())
{
cout<< "File did not open"<< endl;
}
else
{
cout<<"Marks in File:"<< endl;
while(!inputfile.eof()){ // .eof is bad practice, but for this instance it works.
File >> marks[n];
n++; // Essentially the size of the array (Number of values), keeping track of how many values there are will assist you in the output process.
}
}
When you are done reading the file, you should close it and then use the data in the array.
inputfile.close();
Lastly, in order to output an array of data, you must use a for loop or some type of iterator to access the values stored in the array.
for(int i=0; i < n ; i++) // Output array. Where array size is less than n.
{
cout << marks[i] << " "; // " " inputs a space in between each word.
}
I have attached my full source code of my program that can open a .txt file. It doesn't execute after the cout << length. I am trying to store the .txt file information in memory by using an array.
#include <iostream>
#include <string.h>
#include <fstream>
using namespace std;
char filename[128];
char file[10][250];
int count;
int length;
string line;
int main ()
{
int count = 0;
int length = 0;
cout << "Filename: ";
cin.clear();
cin.getline(filename, sizeof(filename));
string new_inputfile(filename);
ifstream inputfiles (new_inputfile.c_str());
if(!inputfiles.is_open())
{
cout << "File could not be opened. \n ";
}
else
{
for (int i=0; getline(inputfiles,line); i++)
{
length++;
}
cout << length;
// char file[length][250]; <- How can I create the array based on the length variable?
// CODE DOES NOT EXECUTE AFTER THIS.
while(!inputfiles.eof() && (count<10))
{
inputfiles.getline(file[count],250);
count++;
}
for(int i=0; i < count; i++)
{
cout << file[i] << endl;
}
}
inputfiles.close();
return 0;
}
Also, since file[] is char, say for example file[1] contained the char Name=Mike, how do I strip off everything before the =. I want just Mike. I know with string, I can use substr() method, but I don't know for char.
This is horribly wasteful way to count number of lines in a file.
for (int i=0; getline(inputfiles,line); i++) // i is also completely useless here
{
length++;
}
You're reading the whole file only to throw everything away and start again! And after this loop is done, inputfiles.eof() will be true and you'll never enter neither the next while loop nor the last for loop (because i == count). Execution skips directly to inputfiles.close() and then you return from main.
I suggest you work on the line string as you go:
for ( ; getline(inputfiles, line); )
{
// do stuff with line and ditch the global char arrays
}
If you want store the lines for later, well, just save them :) The easiest thing to do is to use a vector:
std::vector<std::string> all_them_lines;
while (getline(file, line) all_them_lines.emplace_back(line);
There, the entire file is now saved in all_them_lines, line by line. You can access them just like you would in an array, like all_them_lines[0]. You also don't need to know the number of lines beforehand - vectors expand automatically when you add stuff to them.
Now to parse a line and extract formatted input from it, check out what stringstream class has to offer.
You asked:
// char file[length][250]; <- How can I create the array based on the length variable?
Declare file as:
char (*file)[250] = NULL;
and then,
file = new char[length][250];
Make sure you call delete [] file before the end of the function.
You said:
// CODE DOES NOT EXECUTE AFTER THIS.
You can rewind the stream and start reading from it again.
inputfiles.seekg(0);
count = 0;
while(!inputfiles.eof())
{
inputfiles.getline(file[count],250);
count++;
}
This seems like such an easy task, but everything I've tried hasn't worked so far.
I have a file foo.txt:
3
3 4 2
Now I want to read this file, read the first line and instantiate an int array with the size of the number it read on the first line.
Then it should populate that array with the elements in the second line, which has the exact same amount of elements and noted in line one.
If we're going to give you example code, might as well show you the best way to do it:
std::ifstream datafile("foo.txt");
if (!datafile) {
std::cerr << "Could not open \'foo.txt\', make sure it is in the correct directory." << std::endl;
exit(-1);
}
int num_entries;
// this tests whether the number was gotten successfully
if (!(datafile >> num_entries)) {
std::cerr << "The first item in the file must be the number of entries." << std::endl;
exit(-1);
}
// here we range check the input... never trust that information from the user is reasonable!
if (num_entries < 0) {
std::cerr << "Number of entries cannot be negative." << std::endl;
exit(-2);
}
// here we allocate an array of the requested size.
// vector will take care of freeing the memory when we're done with it (the vector goes out of scope)
std::vector<int> ints(num_entries);
for( int i = 0; i < num_entries; ++i )
// again, we'll check if there was any problem reading the numbers
if (!(datafile >> ints[i])) {
std::cerr << "Error reading entry #" << i << std::endl;
exit(-3);
}
}
Demo (with small changes because I can't provide a file with the right name on ideone): http://ideone.com/0vzPPN
You need to use ifstream object just like you use cin
ifstream fin("foo.txt"); //open the file
if(!fin.fail()){
int count;
fin>>count; //read the count
int *Arr = new int[count];
for(int i=0;i<count;i++){ //read numbers
fin>>Arr[i];
}
//... do what you need ...
//... and finally ...
delete [] Arr;
}
If you open a file using input filestream you can simply do that:
std::ifstream file_txt("file.txt");
int number_count = 0;
file_txt >> number_count; // read '3' from first line
for (int number, i = 0; i < number_count; ++i) {
file_txt >> number; // read other numbers
// process number
}
Filestreams just like other standard streams (std::cin, std::cout) can apply formatting depending on type supplied to operator>> (in this case an int).
This apply to both input and output.
Alternatively, you could avoid the entire need to read in the size beforehand by simply loading it into a std::vector:
std::ifstream fin("myfile.txt");
std::vector<int> vec{std::istream_iterator<int>(fin), std::istream_iterator<int>()};
fin.close();
or, if you cannot use C++11 syntax:
std::ifstream fin("myfile.txt");
std::vector<int> vec;
std::copy(std::istream_iterator<int>(fin), std::istream_iterator<int>(), std::back_inserter(vec));
fin.close();
I am doing a very basic checksum on files by reading the input file into a character array, and then iterating over that array and adding each character into the checksum. The problem is that when I do this all of my checksums are 10 too high (10 is the ascii decimal value for the newline character).
How is it newline characters are being inserted into my code, when I know for a fact there is no newline character in my text? Even a single line text file gets a newline character added in!
#include <iostream>
#include <fstream>
int main () {
int fileLength = 0;
std::ifstream inputFile;
char charArray[10000];
int checkSumValue = 0;
// open file in binary
inputFile.open("/Path/To/File", std::ios::binary);
// get file length, then return to beginning of file
inputFile.seekg(0, std::ios_base::end);
fileLength = inputFile.tellg();
inputFile.seekg(0, std::ios_base::beg);
// read all data from file into char array
inputFile.read(charArray, fileLength);
// iterate over char array, adding ascii decimal value to checksum
for (int num = 0; num <= fileLength; num++) {
std::cout << "Checksum value before iteration " << num << " is "
<< checkSumValue << std::endl;
checkSumValue += static_cast<int>(charArray[num]);
}
// properly close out the input file
inputFile.close();
inputFile.clear(std::ios_base::goodbit);
std::cout << "The checksum value is: " << checkSumValue << std::endl;
std::cout << "The file length is: " << fileLength << std::endl;
return 0;
}
Your problem is here:
num <= fileLength
It should be:
num < fileLength
For example. If the length is 1. Then the only valid character is charArray[0]
Also note. Doing this:
inputFile.read(charArray, fileLength);
is dangerious as fileLength may be larger than the size of the array.
A better solution would be to use a vector (as it dynamically sizes)
std::vector<char> charArray(fileLength);
inputFile.read(&charArray[0], fileLength);
But do you really need to copy the data into an array? Why not just do the sum on the fly.
size_t checkSumValue = std::accumulate(std::istreambuf_iterator<char>(fileLength),
std::istreambuf_iterator<char>(),
size_t(0)
);
Martin was also correct - you should be (num < fileLength) in all cases.
The other possibility is that you created your file in an editor and it's artificially added a spurious newline for you. That's common. Try dumping your file in a hex editor. I just ran your program (with the <= removed) and it works fine.