Incorrect char from file - c++

I have the following .txt file:
test.txt
1,2,5,6
Passing into a small C++ program I made through command line as follows:
./test test.txt
Source is as follows:
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char **argv)
{
int temp =0;
ifstream file;
file.open(argv[1]);
while(!file.eof())
{
temp=file.get();
file.ignore(1,',');
cout<<temp<<' ';
}
return 0;
}
For some reason my output is not 1 2 5 6 but 49 50 53 54. What gives?
UPDATE:
Also, I noticed there is another implementation of get(). If I define char temp then I can do file.get(temp) and that will also save me converting ASCII representation. However I like using while (file >> temp) so I will be going with that. Thanks.

temp is an int. So you see the encoded ascii values after casting the char to an int.

49 is the ascii code for digit 49-48 = 1.
get() gives you a character (character code).
by the way, eof() only becomes true after a failed read attempt, so the code you show,
while(!file.eof())
{
temp=file.get();
file.ignore(1,',');
cout<<temp<<' ';
}
will possibly display one extraneous character at the end.
the conventional loop is
while( file >> temp )
{
cout << temp << ' ';
}
where the expression file >> temp reads in one number and produces a reference to file, and where that file objected is converted to bool as if you had written
while( !(file >> temp).fail() )

This does not do what you think it does:
while(!file.eof())
This is covered in Why is iostream::eof inside a loop condition considered wrong?, so I won't cover it in this answer.
Try:
char c;
while (file >> c)
{
// [...]
}
...instead. Reading in a char rather than an int will also save you having to convert the ascii representation (ASCII value 49 is 1, etc...).

For the record, and despite this being the nth duplicate, here's how this code might look in idiomatic C++:
for (std::string line; std::getline(file, line); )
{
std::istringstream iss(line);
std::cout << "We read:";
for (std::string n; std::getline(iss, line, ','); )
{
std::cout << " " << n;
// now use e.g. std::stoi(n)
}
std::cout << "\n";
}
If you don't care about lines or just have one line, you can skip the outer loop.

Related

Encode a string of characters given a custom code table

I want to programmatically convert a string of characters stored in a file to a string of character codes (encode) by following a code table. The string of binary codes should then go to a file, from which I can revert it back to the string of characters later (decode). The codes in the code table were generated using Huffman algorithm and the code table is stored in a file.
For example, by following a code table where characters and its corresponding codes are single spaced like this:
E 110
H 001
L 11
O 111
encoding "HELLO" should output as "0011101111111"
My C++ code cannot seem to complete the encoded string. Here is my code:
int main
{
string English;
ifstream infile("English.txt");
if (!infile.is_open())
{
cout << "Cannot open file.\n";
exit(1);
}
while (!infile.eof())
{
getline (infile,English);
}
infile.close();
cout<<endl;
cout<<"This is the text in the file:"<<endl<<endl;
cout<<English<<endl<<endl;
ofstream codefile("codefile.txt");
ofstream outfile ("compressed.txt");
ifstream codefile_input("codefile.txt");
char ch;
string st;
for (int i=0; i<English.length();)
{
while(!codefile_input.eof())
{
codefile_input >> ch >> st;
if (English[i] == ch)
{
outfile<<st;
cout<<st;
i++;
}
}
}
return 0;
}
For an input string of "The_Quick_brown_fox_jumps_over_the_lazy_dog", the output string is 011100110, but it should be longer than that!
output image
Please help! Is there anything I have missed?
(n.b. my C++ code has no syntax errors)
Let's take a look at the main loop, you are doing your work in:
for (int i=0; i<English.length();)
{
while(!codefile_input.eof())
{
codefile_input >> ch >> st;
if (English[i] == ch)
{
outfile<<st;
cout<<st;
i++;
}
}
}
Your code, will read through the codefile_input once, and then will get stuck in codefile_input.eof () == true condition, and then, for (int i=0; i<English.length();) will become an infinite loop, due to the fact, that there won't be a code path, in which i is increased, and it will never reach the value equal to English.length ().
As a side note, take a read on Why is iostream::eof inside a loop condition considered wrong?.
To avoid the issue, explained above, consider reading the dictionary file, to a data container (e.g. std::map), and then, use that, while iterating through the string, that you want to encode.
For example:
std::ifstream codefile_input("codefile.txt");
char ch;
std::string str;
std::map<char, std::string> codes;
while (codefile_input >> ch >> str)
{
codes[ch] = str;
}
codefile_input.close ();
for (int i=0; i<English.length(); ++i)
{
auto it = codes.find (English[i]);
if (codes.end () != it)
{
outfile << codes->second;
cout << codes->second;
}
}
Note, you will need to #include <map> to use std::map.
In addition to solving the issue, about which, your question, was actually, about, your loop:
while (!infile.eof())
{
getline (infile,English);
}
only reads the last line of the file, while discarding all other lines, that came prior to it. If you want to process all the lines in a file, consider changing that loop to:
while (std::getline (infile, English))
{
/* Line processing goes here */
}
And, since, your dictionary is unlikely to be different for different lines, you can move that logic, to the front of this loop:
std::ifstream codefile_input("codefile.txt");
char ch;
std::string str;
std::map<char, std::string> codes;
while (codefile_input >> ch >> str)
{
codes[ch] = str;
}
codefile_input.close ();
ifstream infile("English.txt");
if (!infile.is_open())
{
cout << "Cannot open file.\n";
exit(1);
}
ofstream outfile ("compressed.txt");
string English;
while (std::getline (infile, English))
{
for (int i=0; i<English.length(); ++i)
{
auto it = codes.find (English[i]);
if (codes.end () != it)
{
outfile << codes->second;
cout << codes->second;
}
}
}
In addition, consider adding error checking for all of the files that you open. You check if you can open file English.txt, and exit if you can't, but you don't check if you could open any other file.
On unrelated note #2, considering reading Why is “using namespace std” considered bad practice? (that's why you see me using std:: explicitly in the code, that I added).

Reading in multiple text strings of various lengths with C++

I have a bunch of ASCII based text files that are used as input files into various computer programs and I need to convert them to a different format. Each input file starts with a 4 digit number and is then either followed by further input data or comment lines if the first four digit number begins with a 0 (number zero). I am developing a C++ based file convertor and I would like it to read in the four digit number and if that number is a zero read in the comment lines that follow it. An example is provided below. C++ can easily read in the numbers as an array or by using std::vector; however reading in the character string gets to be much more complex. First of all if each comment line had the same number of words, I could treat each string as if it were filling its own line within a fixed column, but since each comment line has a different number of words, then the number of columns to be read in at each line would be different. Is there a simple way to read in the comment lines where C++ will not see the space between each word as the end of one column of data and the beginning of another? Generic numbers and data are used in the file example below, but hopefully you can see that the comment lines starting with the number 0 have a different number of words following them, making it impossible to read the file in as a serious of data columns.
0001 Input File Name
0001 - Description of input file goes here
0001 - PROGRAM name that works on this data
0000 ==========================================
0001 List of references used in the development of this input file
0001 [1] Ref. 1
0001 [2] Ref. 2
0001 [3] Ref. 3
1100 Input line 1: CBRD 1-0220
1101 Core Length (mm): 8.189
1102 Core diameter (mm): 37.81
Use getline function to read a line from the file to a string and work on that string to do whatever you want.
Something like: while(getline(file, string)) { ... }
You don't need to know max chars per line.
This is simply what I meant:
int main() {
std::fstream iFile("Input.txt", std::fstream::in);
//You might want to check if it is open
std::string line;
int firstNumber;
std::string word;
while(getline(iFile, line)){
std::stringstream lineStream(line);
lineStream >> firstNumber;
if(firstNumber == 0) { // modify based on what you want to do
while(lineStream >> word) {
std::cout << word << " ";
}
}
}
std::cout << std::endl;
iFile.close();
}
Based on the suggestions provided above, I was able to implement the following solution. I will try to clean it up and make it more generic so it can be applied easily to other problems. I appreciate the suggestions and the help it gave me.
#include <iostream>
#include <fstream>
#include <cstring>
#include <stdio.h>
int main(int argc, const char * argv[]) {
std::string Input_File("Input.txt");
std::string comment;
const int MAX_CHARS_PER_LINE = 1200;
const int MAX_TOKENS_PER_LINE = 40;
const char* const DELIMITER = " ";
FILE *Output_File;
std::ifstream inp(Input_File, std::ios::in | std::ios::binary);
if(!inp) {
std::cout << "Cannot Open " << Input_File << std::endl;
return 1; // Terminate program
}
Output_File = fopen ("Output_File.txt","w");
std::ofstream out("Output_File.txt", std::ios::in | std::ios::binary);
// read each line of the file
while (!inp.eof())
{
// read an entire line into memory
char buf[MAX_CHARS_PER_LINE];
inp.getline(buf, MAX_CHARS_PER_LINE);
// parse the line into blank-delimited tokens
int n = 0; // a for-loop index
// array to store memory addresses of the tokens in buf
const char* token[MAX_TOKENS_PER_LINE] = {}; // initialize to 0
// parse the line
token[0] = strtok(buf, DELIMITER); // first token
if (token[0]) // zero if line is blank
{
for (n = 1; n < MAX_TOKENS_PER_LINE; n++)
{
token[n] = strtok(0, DELIMITER); // subsequent tokens
if (!token[n]) break; // no more tokens
}
if (strncmp (token[0],"0",1) == 0)
{
for(int i = 0; i < n; i++) out << token[i] << " ";
}
out << std::endl;
}
}
inp.close();
return 0;
}

C++ file reading

I have a file that has a number in which is the number of names that follow. For example:
4
bob
jim
bar
ted
im trying to write a program to read these names.
void process_file(ifstream& in, ofstream& out)
{
string i,o;
int tmp1,sp;
char tmp2;
prompt_user(i,o);
in.open (i.c_str());
if (in.fail())
{
cout << "Error opening " << i << endl;
exit(1);
}
out.open(o.c_str());
in >> tmp1;
sp=tmp1;
do
{
in.get(tmp2);
} while (tmp2 != '\n');
in.close();
out.close();
cout<< sp;
}
So far I am able to read the first line and assign int to sp
I need sp to be a counter for how many names. How do I get this to read the names.
The only problem I have left is how to get the names while ignoring the first number.
Until then i cannot implement my loop.
while (in >> tmp1)
sp=tmp1;
This successfuly reads the first int from the and then tries to continue. Since the second line is not an int, extraction fails, so it stops looping. So far so good.
However, the stream is now in fail state, and all subsequent extractions will fail unless you clear the error flags.
Say in.clear() right after the first while loop.
I don't really see why you wrote a loop to extract a single integer, though. You could just write
if (!(in >> sp)) { /* error, no int */ }
To read the names, read in strings. A loop is fine this time:
std::vector<std::string> names;
std::string temp;
while (in >> temp) names.push_back(temp);
You'd might want to add a counter somewhere to make sure that the number of names matches the number you've read from the file.
int lines;
string line;
inputfile.open("names.txt");
lines << inputfile;
for(i=0; i< lines; ++i){
if (std::getline(inputfile, line) != 0){
cout << line << std::endl;
}
}
First of all, assuming that the first loop:
while (in >> tmp1)
sp=tmp1;
Is meant to read the number in the beginning, this code should do:
in >> tmp1;
According to manual operator>>:
The istream object (*this).
The extracted value or sequence is not returned, but directly stored
in the variable passed as argument.
So don't use it in condition, rather use:
in >> tmp1;
if( tmp1 < 1){
exit(5);
}
Second, NEVER rely on assumption that the file is correctly formatted:
do {
in.get(tmp2);
cout << tmp2 << endl;
} while ( (tmp2 != '\n') && !in.eof());
Although whole algorithm seems a bit clumsy to me, this should prevent infinite loop.
Here's a simple example of how to read a specified number of words from a text file in the way you want.
#include <string>
#include <iostream>
#include <fstream>
void process_file() {
// Get file name.
std::string fileName;
std::cin >> fileName;
// Open file for read access.
std::ifstream input(fileName);
// Check if file exists.
if (!input) {
return EXIT_FAILURE;
}
// Get number of names.
int count = 0;
input >> count;
// Get names and print to cout.
std::string token;
for (int i = 0; i < count; ++i) {
input >> token;
std::cout << token;
}
}

Reading char from file in c++

I have created a file hangman_word_collection.txt and stored all the content of file into the string line.
Now I want to use the line string in my program but line[0] is not having any value into it or I don't know if it have something in it.
I am new to this please help.
Here is the code:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
string line;
ifstream myfile ("hangman_word_collection.txt");
if (myfile.is_open()) {
while (myfile.good()) {
getline (myfile,line);
cout << line << endl;
}
}
for(int i=0; i <= 79; i++) {
cout << "\n" << i;
cout << ":" << line[i];
}
return 0;
}
And the output:
actingraringbackupcampusdacoiteasilyfabricgardenhackediceboxprimeralwaysupload.
0:
1:c
2:t
3:i
4:n
5:g
6:r
7:a
8:r
9:i
10:n
11:g
12:b
13:a
14:c
15:k
Press <RETURN> to close this window...
When getline fails on writing to your target line you are assuming it will not modify what is in that string but it is blanking the string, which internally is replacing character 0 with a null character.
The rest is undefined behaviour as you are reading characters off the end of the logical string.
To fix this issue change your code to;
string line;
ifstream myfile ("hangman_word_collection.txt");
if (myfile.is_open())
{
while (myfile.good())
{
std::string temp;
if( getline( myfile, temp ) )
{
temp.swap( line );
cout <<line<<endl;
}
}
}
Note that it is bad practice to hard-code in magic numbers like 79. If you had put line.size() instead you would have seen what size the string actually is, and there would be no undefined behaviour. You can store this in a variable outside the loop if you are worried about performance, although chances are it makes little difference.

HW Help: get char instead of get line C++

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');
}