String concatenation issue in C++ - c++

I am trying to concatenate some string but it works in one but not another.
Working: I take in 2 argument and then do this. a = hello, b = world
string concat = a + b;
The output would be hello world with no problem.
Not working: I read from file and concatenate with 2nd argument. assuming string from file is abcdefg.
string concat = (string from file) + b;
and it gives me worldfg.
Instead of concatenating, string from b overwrites the initial string.
I have tried a few other methods such as using stringstream but it doesn't work as well.
This is my code.
int main (int nArgs, char *zArgs[]) {
string a = string (zArgs [1]);
string b = string (zArgs [2]);
string code;
cout << "Enter code: ";
cin >> code;
string concat = code + b;
}
// The output above gives me the correct concatenation.
// If I run in command prompt, and do this. ./main hello world
// then enters **good** after the prompt for code.
// The output would be **goodworld**
However, I read some lines from the file.
string f3 = "temp.txt";
string r;
string temp;
infile.open (f3.c_str ());
while (getline (infile, r)) {
// b is take from above
temp = r + b;
cout << temp << endl;
}
// The above would give me the wrong concatenation.
// Say the first line in temp.txt is **quickly**.
// The output after reading the line and concatenating is **worldly**
Hope it gives more clear example.
Update:
I think I may have found out that the problem is due to the text file. I tried to create a new text file with some random lines inside, and it seem working fine. But if I try to read the original file, it gives me the wrong output. Still trying to put my head around this.
Then I tried to copied the content of the original file to the new file, and it seem to be working fine. Not too sure what is wrong here though. Will continue to test out, and hopefully it works fine.
Thanks for all the help! Appreciate it!

I get the same output as the chap who asked the original question:
$ ./a.out hello world
Enter code: good
goodworld
worldly
The problem here is the contents of the text file. For my example, the initial 7 characters in the text file are: "quickly". However, immediately following that are 7 backspace bytes (hex 08). This is what the contents looks like in emacs:
quickly^H^H^H^H^H^H^H
So how is this causing the mess?
Well the concatenation operation actually works correctly. If you do:
std::cout << "string length: " << temp.size() << "\n";
...you get the answer 19 which is made up of: "quickly" (7) + 7 backspace chars + "world"(5). The overwriting effect you observe is caused when you print this 19 char string to console: it is the console (eg xterm) that interprets the backspace sequence as meaning "move the cursor back to the left", thus removing earlier characters. If instead you pipe the output to file, you will see the full string (including the backspaces) is actually generated.
To get around this you might want to validate/correct the input that comes from the file. There are functions commonly available in C/C++ environments such as isprint(int c), iscntrl(int c) that you could make use of.
Update: as mentioned by another responder, other ASCII control characters will also have the same effect, eg, a carriage return (Hex 0D) will also move the cursor back to the left.

If I compile this
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main (int nArgs, char *zArgs[]) {
string a = string (zArgs [1]);
string b = string (zArgs [2]);
string code;
cout << "Enter code: ";
cin >> code;
string concat = code + b;
// The output above gives me the correct concatenation.
//However, I read some lines from the file.
ifstream infile;
string f3 = "temp.txt";
string r;
string temp;
infile.open (f3.c_str ());
while (getline (infile, r)) {
temp = r + code;
cout << temp << endl;
}
// The above would give me the wrong concatenation.
infile.close();
return 0;
}
it compiles and runs flawlessly. What does this do on your computer? If it fails, we may have to compare the contents of our temp.txt.
(This ought to be a comment rather than an answer, but it's too long. Sorry.)

Related

How to read a specific amount of characters

I can get the characters from console with this code:
Displays 2 characters each time in a new line
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
char ch[3] = "";
ifstream file("example.txt");
while (file.read(ch, sizeof(ch)-1))
{
cout << ch << endl;
}
return 0;
}
My problem is, if the set of characters be odd it doesn't displays the last character in the text file!
my text file contains this:
abcdefg
it doesn't displays the letter g in the console
its displaying this:
ab
cd
ef
I wanna display like this:
ab
cd
ef
g
I wanna use this to read 1000 characters at a time for a large file so i don't wanna read character by character, It takes a lot of time, but it has a problem if u can fix it or have a better suggestion, share it with me
The following piece of code should work:
while (file) {
file.read(ch, sizeof(ch) - 1);
int number_read_chars = file.gcount();
// print chars here ...
}
By moving the read call into the loop, you'll be able to handle the last call, where too few characters are available. The gcount method will provide you with the information how many characters were actually read by the last unformatted input operation, e.g. read.
Please note, when reading less than sizeof(ch) chars, you manually have to insert a NUL character at the position returned by gcount, if you intend to use the buffer as a C string, as those are null terminated:
ch[file.gcount()] = '\0';

Filling a cstring using <cstring> with text from a textfile using File I/O C++

I began learning strings yesterday and wanted to manipulate it around by filling it with a text from a text file. However, upon filling it the cstring array only prints out the last word of the text file. I am a complete beginner, so I hope you can keep this beginner friendly. The lines I want to print from the file are:
"Hello World from UAE" - First line
"I like to program" - Second line
Now I did look around and eventually found a way and that is to use std::skipary or something like that but that did not print it the way I had envisioned, it prints letter by letter and skips each line in doing so.
here is my code:
#include <fstream>
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;
int main() {
ifstream myfile;
myfile.open("output.txt");
int vowels = 0, spaces = 0, upper = 0, lower = 0;
//check for error
if (myfile.fail()) {
cout << "Error opening file: ";
exit(1);
}
char statement[100];
while (!myfile.eof()) {
myfile >> statement;
}
for (int i = 0; i < 30; ++i) {
cout << statement << " ";
}
I'm not exactly sure what you try to do with output.txt's contents, but a clean way to read through a file's contents using C++ Strings goes like this:
if (std::ifstream in("output.txt"); in.good()) {
for (std::string line; std::getline(in, line); ) {
// do something with line
std::cout << line << '\n';
}
}
You wouldn't want to use char[] for that, in fact raw char arrays are hardly ever useful in modern C++.
Also - As you can see, it's much more concise to check if the stream is good than checking for std::ifstream::fail() and std::ifstream::eof(). Be optimistic! :)
Whenever you encounter output issues - either wrong or no output, the best practise is to add print (cout) statements wherever data change is occurring.
So I first modified your code as follows:
while (!myfile.eof()) {
myfile >> statement;
std::cout<<statement;
}
This way, the output I got was - all lines are printed but the last line gets printed twice.
So,
We understood that data is being read correctly and stored in statement.
This raises 2 questions. One is your question, other is why last line is printed twice.
To answer your question exactly, in every loop iteration, you're reading the text completely into statement. You're overwriting existing value. So whatever value you read last is only stored.
Once you fix that, you might come across the second question. It's very common and I myself came across that issue long back. So I'm gonna answer that as well.
Let's say your file has 3 lines:
line1
line2
line3
Initially your file control (pointer) is at the beginning, exactly where line 1 starts. After iterations when it comes to line3, we know it's last line as we input the data. But the loop control doesn't know that. For all it knows, there could be a million more lines. Only after it enters the loop condition THE NEXT TIME will it come to know that the file has ended. So the final value will be printed twice.

ifstream does not read first line

I am using the code with ifstream that I used ~1 year ago, but now it does not work correctly. Here, I have the following file (so, just a line of integers):
2 4 2 3
I read it while constructing a graph from this file:
graph g = graph("file.txt");
where graph constructor starts with:
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
graph::graph(const char *file_name) {
ifstream infile(file_name);
string line;
getline(infile, line);
cout << line << endl; // first output
istringstream iss;
iss.str(line);
iss >> R >> C >> P >> K;
iss.clear();
cout << R << " " << C << " " << P << " " << K; // second output
}
The second output (marked in code), instead of giving me 2 4 2 3, returns random(?) values -1003857504 32689 0 0. If I add the first output to check the contents of line after getline, it is just an empty string "".
All the files (main.cpp where a graph is instantiated, 'graph.cpp' where the graph is implemented and 'file.txt') are located in the same folder.
As I mentioned, this is my old code that worked before, so probably I do not see some obvious mistake which broke it. Thanks for any help.
These two locations:
where your program's original source code is located
where your program's input data is located
are completely unrelated.
Since "file.txt" is a relative path, your program looks for input data in the current working directory during execution. Sometimes that is the same as where the executable is. Sometimes it is not. (Only you can tell what it is, since it depends on how you execute your program.) There is never a connection to the location of the original source file, except possibly by chance.
When the two do not match, you get this problem, because you perform no I/O error checking in your program.
If you checked whether infile is open, I bet you'll find that it is not.
This is particularly evident since the program stopped working after a period of time without any changes to its logic; chances are, the only thing that could have changed is the location of various elements of your solution.

C++ retrieve numerical values in a line of string

Here is the content of txt file that i've managed read.
X-axis=0-9
y-axis=0-9
location.txt
temp.txt
I'm not sure whether if its possible but after reading the contents of this txt file i'm trying to store just the x and y axis range into 2 variables so that i'll be able to use it for later functions. Any suggestion? And do i need to use vectors? Here is the code for reading of the file.
string configName;
ifstream inFile;
do {
cout << "Please enter config filename: ";
cin >> configName;
inFile.open(configName);
if (inFile.fail()){
cerr << "Error finding file, please re-enter again." << endl;
}
} while (inFile.fail());
string content;
string tempStr;
while (getline(inFile, content)){
if (content[0] && content[1] == '/') continue;
cout << endl << content << endl;
depends on the style of your file, if you are always sure that the style will remain unchanged, u can read the file character by character and implement pattern recognition stuff like
if (tempstr == "y-axis=")
and then convert the appropriate substring to integer using functions like
std::stoi
and store it
I'm going to assume you already have the whole contents of the .txt file in a single string somewhere. In that case, your next task should be to split the string. Personally, yes, I would recommend using vectors. Say you wanted to split that string by newlines. A function like this:
#include <string>
#include <vector>
std::vector<std::string> split(std::string str)
{
std::vector<std::string> ret;
int cur_pos = 0;
int next_delim = str.find("\n");
while (next_delim != -1) {
ret.push_back(str.substr(cur_pos, next_delim - cur_pos));
cur_pos = next_delim + 1;
next_delim = str.find("\n", cur_pos);
}
return ret;
}
Will split an input string by newlines. From there, you can begin parsing the strings in that vector. They key functions you'll want to look at are std::string's substr() and find() methods. A quick google search should get you to the relevant documentation, but here you are, just in case:
http://www.cplusplus.com/reference/string/string/substr/
http://www.cplusplus.com/reference/string/string/find/
Now, say you have the string "X-axis=0-9" in vec[0]. Then, what you can do is do a find for = and then get the substrings before and after that index. The stuff before will be "X-axis" and the stuff after will be "0-9". This will allow you to figure that the "0-9" should be ascribed to whatever "X-axis" is. From there, I think you can figure it out, but I hope this gives you a good idea as to where to start!
std::string::find() can be used to search for a character in a string;
std::string::substr() can be used to extract part of a string into another new sub-string;
std::atoi() can be used to convert a string into an integer.
So then, these three functions will allow you to do some processing on content, specifically: (1) search content for the start/stop delimiters of the first value (= and -) and the second value (- and string::npos), (2) extract them into temporary sub-strings, and then (3) convert the sub-strings to ints. Which is what you want.

What's the correct way to read a text file in C++?

I need to make a program in C++ that must read and write text files line by line with an specific format, but the problem is that in my PC I work in Windows, and in College they have Linux and I am having problems because of line endings are different in these OS.
I am new to C++ and don't know could I make my program able read the files no matter if they were written in Linux or Windows. Can anybody give me some hints? thanks!
The input is like this:
James White 34 45.5 10 black
Miguel Chavez 29 48.7 9 red
David McGuire 31 45.8 10 blue
Each line being a record of a struct of 6 variables.
Using the std::getline overload without the last (i.e. delimiter) parameter should take care of the end-of-line conversions automatically:
std::ifstream in("TheFile.txt");
std::string line;
while (std::getline(in, line)) {
// Do something with 'line'.
}
Here's a simple way to strip string of an extra "\r":
std::ifstream in("TheFile.txt");
std::string line;
std::getline(input, line));
if (line[line.size() - 1] == '\r')
line.resize(line.size() - 1);
If you can already read the files, just check for all of the newline characters like "\n" and "\r". I'm pretty sure that linux uses "\r\n" as the newline character.
You can read this page: http://en.wikipedia.org/wiki/Newline
and here is a list of all the ascii codes including the newline characters:
http://www.asciitable.com/
Edit: Linux uses "\n", Windows uses "\r\n", Mac uses "\r". Thanks to Seth Carnegie
Since the result will be CR LF, I would add something like the following to consume the extras if they exist. So once your have read you record call this before trying to read the next.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
If you know the number of values you are going to read for each record you could simply use the ">>" method. For example:
fstream f("input.txt" std::ios::in);
string tempStr;
double tempVal;
for (number of records) {
// read the first name
f >> tempStr;
// read the last name
f >> tempStr;
// read the number
f >> tempVal;
// and so on.
}
Shouldn't that suffice ?
Hi I will give you the answer in stages. Please go trough in order to understand the code.
Stage 1: Design our program:
Our program based on the requirements should...:
...include a definition of a data type that would hold the data. i.e. our
structure of 6 variables.
...provide user interaction i.e. the user should be able to
provide the program, the file name and its location.
...be able to
open the chosen file.
...be able to read the file data and
write/save them into our structure.
...be able to close the file
after the data is read.
...be able to print out of the saved data.
Usually you should split your code into functions representing the above.
Stage 2: Create an array of the chosen structure to hold the data
...
#define MAX 10
...
strPersonData sTextData[MAX];
...
Stage 3: Enable user to give in both the file location and its name:
.......
string sFileName;
cout << "Enter a file name: ";
getline(cin,sFileName);
ifstream inFile(sFileName.c_str(),ios::in);
.....
->Note 1 for stage 3. The accepted format provided then by the user should be:
c:\\SomeFolder\\someTextFile.txt
We use two \ backslashes instead of one \, because we wish it to be treated as literal backslash.
->Note 2 for stage 3. We use ifstream i.e. input file stream because we want to read data from file. This
is expecting the file name as c-type string instead of a c++ string. For this reason we use:
..sFileName.c_str()..
Stage 4: Read all data of the chosen file:
...
while (!inFile.eof()) { //we loop while there is still data in the file to read
...
}
...
So finally the code is as follows:
#include <iostream>
#include <fstream>
#include <cstring>
#define MAX 10
using namespace std;
int main()
{
string sFileName;
struct strPersonData {
char c1stName[25];
char c2ndName[30];
int iAge;
double dSomeData1; //i had no idea what the next 2 numbers represent in your code :D
int iSomeDate2;
char cColor[20]; //i dont remember the lenghts of the different colors.. :D
};
strPersonData sTextData[MAX];
cout << "Enter a file name: ";
getline(cin,sFileName);
ifstream inFile(sFileName.c_str(),ios::in);
int i=0;
while (!inFile.eof()) { //loop while there is still data in the file
inFile >>sTextData[i].c1stName>>sTextData[i].c2ndName>>sTextData[i].iAge
>>sTextData[i].dSomeData1>>sTextData[i].iSomeDate2>>sTextData[i].cColor;
++i;
}
inFile.close();
cout << "Reading the file finished. See it yourself: \n"<< endl;
for (int j=0;j<i;j++) {
cout<<sTextData[j].c1stName<<"\t"<<sTextData[j].c2ndName
<<"\t"<<sTextData[j].iAge<<"\t"<<sTextData[j].dSomeData1
<<"\t"<<sTextData[j].iSomeDate2<<"\t"<<sTextData[j].cColor<<endl;
}
return 0;
}
I am going to give you some exercises now :D :D
1) In the last loop:
for (int j=0;j<i;j++) {
cout<<sTextData[j].c1stName<<"\t"<<sTextData[j].c2ndName
<<"\t"<<sTextData[j].iAge<<"\t"<<sTextData[j].dSomeData1
<<"\t"<<sTextData[j].iSomeDate2<<"\t"<<sTextData[j].cColor<<endl;}
Why do I use variable i instead of lets say MAX???
2) Could u change the program based on stage 1 on sth like:
int main(){
function1()
function2()
...
functionX()
...return 0;
}
I hope i helped...