Linux | Segmentation Fault in C++ - Due to the function ifstream - c++

I think I should begin by saying that I've just installed linux(debian) in my pc and have zero foreknowledge about doing things in linux. This problem is probably due to some really simple thing.
The relevant part of the code is similar to this:
ifstream stockNames("names.txt");
while (!stockNames.eof())
{
string snline;
getline(stockNames,snline);
cout << snline << endl;
.
.
.
}
this should print the first line of the file 'names.txt'. Instead it prints an empty line. And when I try to use snline as an input in another function I get the error 'Segmentation Fault'. How should I modify my code to do this? Is there any difference in usage of the ifstream in linux? Cause in windows the code works just fine
I've written the simple code below
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, const char *argv[])
{
string dos = "names.txt";
ifstream stockNames(dos.c_str() );
string snline;
while (getline(stockNames,snline))
{
cout << snline << " ";
}
return 0;
}
content of names.txt is
ABC
DEFG
HBO
instead of showing those line, cout << snline produces nothing
One more update: I've written two more codes.
(1)
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, const char *argv[])
{
cout << "program has initiated" << endl;
ifstream stockNames("names.txt");
if( !stockNames )
cout << "unable to open" << endl;
string snline;
while (getline(stockNames,snline))
{
cout << snline << endl;
}
return 0;
}
Result is as I desired. First 'program has initiated', then ABC, DEFG, HBO in different lines. But when I change this part
cout << snline << endl;
as
cout << snline << " hey" << endl;
Then ABC DEFG HBO does not appear and instead the only output is " hey".
This is crazy, how can this be??
btw I tried to make a debug with ddd and when I check the variable snline, ddd prints the following line
(gdb) print snline
$2 = {static npos = 4294967295, _M_dataplus = {> = {<__gnu_cxx::new_allocator> = {}, }, _M_p = 0x804c1a4 "ABC\r"}}
new mini update: when I change the relevant line as "cout << snline << " " << endl;" what's printed out is ' BC' ' FGH' ' BO' in seperate lines. Why does << operator overwrites over snline??

First of all, your while loop is wrong, because the eof flag (or any other failure flag) is set after an attempt to read from the stream fails; that means, if the attempt to read fails using getline(), the loop doesn't immediately exit, instead the loop continues which is a serious bug with your code.
So write your loop as (an idiomatic way):
string snline;
while (getline(stockNames,snline))
{
cout << snline;
//..
}
std::getline returns istream&, which can be implicitly converted into boolean type. So if getline reads successfully, then the returned value converts to true and the loop will continue, or else it will convert to false and the loop will exit.
After the edit in your question, all I can say that you need to check the stream object before using it to read contents from the file. More specifically, you need to check if the stream has been initialized properly and it has indeed opened the input file (i.e names.txt), and is ready to read data from it.
So try doing this:
//...
ifstream stockNames(dos.c_str() );
if (!stockNames)
{
cout << "file couldn't open properly" << endl;
return 0;
}
string snline;
while (getline(stockNames,snline))
{
cout << snline << " ";
}
Now run this, and see what it prints.

You have a dos file which uses \r\n at the end of each line. Linux doesn't recognise \r as part of the line ending so it gets included in the snline string. \r causes the next thing printed to appear at the beginning of the line so " hey" overwrites the stock names you were expecting to see.
Try
cout << snline << " " << endl;
and you'll see what I mean

stockNames will not actually appear to reach "end of file" until it has tried to input something and received the EOF character. Therefore, you're going to want to re-write your loop as follows:
ifstream stockNames("names.txt");
string snline;
getline(stockNames,snline);
while (!stockNames.eof())
{
cout << snline << endl;
.
.
.
getline(stockNames,snline);
}
or much simply
ifstream stockNames("names.txt");
string snline;
while (getline(stockNames, snline))
{
cout << snline << endl;
.
.
.
}

To answer your question; no, there is no significant difference in how ifstream operates on Linux and Windows. Of course if you write bugged code (as the other two answers have pointed out) then you might run into problems, but I can't see how the eof bug would cause the problems you are describing.
I would concentrate on the part where you say that using snline causes a segmentation fault, that indicates a more serious issue. Could you post code that demonstrates that?

You aren't checking whether the stream opened properly.
std::ifstream stockNames("names.txt");
if (! stockNames) {
std::cerr << "Unable to open file 'names.tex'\n";
}
else {
// Do the rest of your stuff here.
}
Always check status. Don't just plow ahead and assume everything is OK.
BTW, using namespace std; is something you see in a lot of bad books that are trying to save a tiny amount of ink. Try to get out of this bad habit.

Related

How to read back what I just wrote to a file?

I've been trying to write a program to open a file in both read and write mode:
#include <fstream>
#include <iostream>
using namespace std;
int main(){
fstream obj;
obj.open("hello.txt",ios::in|ios::out);
if (!obj){
cout << "File not opened" <<endl;
return 1;
}
obj << "Hi How are you" ;
char c;
while (!obj.eof()){
obj.get(c);
cout << c;
}
obj.close();
return 0;
}
When I compile this program on Visual Studio Code on Windows, though the text "Hi how are you" is printed in the file, the contents of the file are not printed on my screen. Can someone tell me what might be the problem?
Resetting the position indicator with seekp to 0 helps, because both output and input indicators are set to the end of file after write operation (you can read them with tellp tellg).
obj << "Hi How are you" ;
obj.seekp(0);
char c;
while (!obj.eof()){
obj.get(c);
cout << c;
}
Considering avoiding using obj.eof(), you can e.g. read your file line by line:
std::string line;
std::getline(obj, line);
std::cout << line << std::endl;
or in the loop:
while (std::getline(obj, line)) // here std::basic_ios<CharT,Traits>::operator bool is used to check if operation succeeded
{
std::cout << line << std::endl;
}
You got two problems there: buffering and seek position.
Buffering:
When you write the text with obj << "Hi How are you, you just write it into the buffer and the text gets written into the file after flushing the buffer. You can adjust which buffer type you want to use. The easiest way is to write std::endl after your text if you use line buffering.
A better explaination is already here
Seek Position:
You are reading from the last position in your file. You have to manually change the read position to the first character in the file, then you are done.

Multiset: Problem with multiset adding more than one version of a word and cannot handle large amounts of text

Update and fixed: I have fixed the problem causing the error message- Huge thanks to user PaulMcKenzie for helping me understand what the error message was telling me!- When my program encountered a letter with a mark above it (diacritical marks I think they are called), it crashed. I have adjusted my code to account for these and now it doesn't crash at all! Another huge thanks to user ihavenoidea for helping me understand multisets! My program is now working the way it's supposed to!
Original post:
****I am VERY new to C++ so any and all help is appreciated!****
Ok, so I'm trying to use multiset to sort words so I can see how many times a word appears in a text. First, my program accepts a file, then it reads the words and takes out any punctuation, then it puts it into a multiset. After this, it is supposed to put the results into a text file the user names themselves.
My first issue is that the multiset seems to be creating more than one element for the same word (For example: in one of my tests I saw a(4) listed in the text document 3 times in a row instead of one time).
My Second issue is that when I try to read in large text documents (I'm using John Colliers story "Bottle Party" http://ciscohouston.com/docs/docs/greats/bottle_party.html to test it) my program completely crashes but doesn't crash when I test it with a smaller text document (small being with say about 5-10 lines of text). I'm using Visual Studios and (once again I'm new to Visual Studios also) I don't know what the error message is trying to tell me but it says:
After selecting retry:
As always, any and all help is greatly appreciated.
Code here:
#include <iostream>
#include <string> //for strings
#include <fstream> //for files
#include <set> //for use of multiset
using namespace std;
string cleanUpPunc(string);
//Global variables
multiset <string> words; //will change back to local variable later
int main() {
//Starting variables
string fileName1 = "", fileName2 = "", input = "", input2 = ""; //To hold the input file and the file we wish to print data to if desired
ifstream fileStream; //gets infor from file
//Program start
cout << "Welcome to Bags Program by Rachel Woods!" << endl;
cout << "Please enter the name of the file you wish to input data from: ";
getline(cin, fileName1);
//Trys to open file
try {
fileStream.open(fileName1);
if (!fileStream) {
cerr << "Unable to open file, please check file name and try again." << endl;
system("PAUSE");
exit(1);
}
while (fileStream >> input) {
input2 = cleanUpPunc(input); //sends the input word to check for punctation
words.insert(input2); //puts the 'cleaned up' word into the multiset for counting
}
fileStream.close();
//Sends it to a text document
cout << "Please name the file you would like to put the results into: ";
getline(cin, fileName2);
ofstream toFile; //writes info to a file
//Code to put info into text file
toFile.open(fileName2);
if (toFile.is_open()) {
multiset<string>::iterator pos;
for (pos = words.begin(); pos != words.end(); pos++) {
toFile << *pos << " " << words.count(*pos) << endl;
}
toFile.close();
cout << "Results written to file!" << endl;
}
else {
cout << "Could not create file, please try again." << endl;
}
}catch (exception e) {
cout << "Stop that. ";
cout << e.what();
}
cout << "Thanks for using this program!" << endl;
system("PAUSE");
return 0;
}
string cleanUpPunc(string maybe) {
//Takes out puncuation from string
//Variables
string takeOut = maybe;
//Method
for (int i = 0, len = maybe.size(); i < len; i++) {
if (ispunct(takeOut[i])) {
takeOut.erase(i--, 1);
len = takeOut.size();
}
}
return takeOut;
}

C++ opening a .txt file and creating a new one

So I'm trying to make a program that will open up a text file based on user input (or fail trying), read the contents and create a new text file named after user input and rewrite the contents, but this time with row numbers.
I'm having trouble that I can't pin down on anything specific. My Qt Creator gives no massive errors, but the program seems to halt around line 30 without any error messages.
An online C++ compiler complained about a segmentation problem.
The code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main() {
string input_file = "";
cout << "input file: ";
getline(cin, input_file);
vector<string> line_vector;
string output_file = "";
cout << "output file:";
getline(cin, output_file);
ifstream file_object(input_file);
if ( not file_object )
{
cout <<"Error! The file " << input_file <<
" cannot be opened." << endl;
} else {
int row_number = 0;
string line;
while (getline(file_object, line) )
{
cout << line << endl;
line_vector[row_number] = line;
++row_number;
}
file_object.close();
ofstream output_file;
output_file.open("");
for (int i = 0; i>=row_number;++i)
{
output_file << i << " " << line_vector[i] << "\n";
}
output_file.close();
}
}
What the code is doing on this line: line_vector[row_number] = line is not actually appending to the vector - which is what you are trying to do -, but instead accessing an element at the index i inside the vector, and trying to assign line to it.
This would be fine, however, since the vector has 0 size, it is trying to assign line to unknown memory. This leads to undefined behaviour, and often, crashes. You can do one of two things. The first is to use resize or reserve to reserve the memory for the vector, then assign the variable, like so:
while (getline(file_object, line) ) {
cout << line << endl;
line_vector.resize(row_number + 1);
line_vector[row_number] = line;
++row_number;
}
However, this is pretty pointless, and instead, you should use push_back:
while (getline(file_object, line) ) {
cout << line << endl;
line_vector.push_back(line);
}
nullifying the use of row_number in that loop.
Oh, and don't use using namespace std, it's a bad habit.
"When you define a vector like line_vector, it starts out empty. All indexing into it will be out of bounds and lead to undefined behavior. Please learn how to push back elements into a vector. "
– Some programmer dude

Looping over file, only get one line

Say we have a text file with this contents:
dogs
cats
bears
trees
fish
rocks
sharks
these are just words separated by newline chars. I am trying to create a Node.js addon. The Addon will read through a file and replacing matching lines with a blank line. Say I pass my program a regex that matches /trees/. If I pass the file to my C++ program it will read + write to the file, and result in:
dogs
cats
bears
fish
rocks
sharks
Right now, the problem is it's not looping through all the lines in the file. I get the feeling that's opening the file in append mode and therefore just starting at the end of the file? I can't tell. Anyway, I want to edit the file in place, not truncate and re-write or replace the whole file, because this will interrupt processes which are tailing the file.
Here's the code:
#include <nan.h>
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
void Method(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(Nan::New("world").ToLocalChecked());
}
void Init(v8::Local<v8::Object> exports) {
fstream infile("/home/oleg/dogs.txt");
if(infile.fail()){
cerr << " infile fail" << endl;
exit(1);
}
int pos = 0;
string line;
int count = 0;
while (getline(infile, line)){
// we only seem to loop once, even though the file has 7 or 8 items
count++;
long position = infile.tellp();
cout << "tellp position is " << position << endl;
string str(line);
int len = str.length();
cout << " => line contains => " << line << endl;
cout << " line length is " << len << endl;
std::string s(len, ' '); // create blank string of certain length
infile << s; // write the string to the current position
pos = pos + len;
cout << "pos is " << pos << endl;
}
cout << " => count => " << count << endl;
infile.close();
exports->Set(Nan::New("hello").ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(Method)->GetFunction());
}
NODE_MODULE(hello, Init)
to compile the code you might need to use Node.js tooling, which is
node-gyp rebuild
If you want to help and want to try to compile the code, then let me know, because you may need more info. But I am a new C++ newb and I think someone can help me figure it out without compiling/running the code. Thanks.
To answer your question on why you only read one line of the input file:
Your first write to the file likely sets the eofbit on the stream, so the second getline() attempt will think it has no more to read.
The comment from #RSahu describes the simplest way to do this for text files.

Writing using << on an fstream

I'm trying to write a long to a text file using c++ fstream class. The file is already created on disk before the execution. I run the following code and can read the initial value but can't save the new one, overwriting. What am i doing wrong?
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char* argv[]) {
long f;
fstream myFile("data.txt", fstream::in|fstream::out);
cout << "f before: " << f << endl;
myFile >> f;
cout << "f after: " << f << endl;
f++;
cout << "f after increment: " << f << endl;
myFile << f;
myFile.close();
return 0;
}
After that, I read the value in the file and it isn't changed. What I did wrong here?
You need to rewind to the beginning of the file before writing. Otherwise the second value is written after the first one.
You need to add myFile.seekp(ios::beg); just before myFile << f; in order to update the count correctly.
If you want to keep appending to the end, add myFile.clear(); before myFile << f;. This will cause the contents to become :
1->12->1213->12131214->1213121412131215. This is required because eof is reached upon reading the input. Note that get and put pointers are the same.
As you have yourself correctly pointed out, this is required because the file has just the number, not even the newline. Thus the read operation hits straight the EOF and causes problems. To work around it, we clear eof status and continue.
Adding a newline at the end is a solution as you suggested. In that case
myFile.seekp(ios::beg);
myFile << f<<"\n";
Would be the complete solution.
I figured what I was doing wrong here:
My file contained ONLY the long that I wanted to read and write afterwards. When I read the file, I reached EOF and then couldn't rewind or write anything at the end.
That said, my solution was to include a space or a \n at the end of the file.
Does anyone know why the API works this way? Does not seeem very useful for me...
It has to do with this line:
myFile >> f;
Remove it and everything works just fine. I'm not familiar with fstream but it seems to me this code would try to force a string in a long. I'm also not allowed to cast it to a long, which makes me think this is never meant to be executed like this. I suggest you read up on how to retrieve a value from a file as a long type and then try again.
edit:
After reading a bit this site suggested you have to close and reopen the file between reading and writing, I was amazed that actually fixed it. I can't help but wonder why though, I thought fstream was meant for reading OR writing OR both.... Anyway, here is your working code:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char* argv[]) {
long f;
fstream myFile("data.txt", fstream::in|fstream::out);
cout << "f before: " << f << endl;
myFile >> f;
cout << "f after: " << f << endl;
f++;
cout << "f after increment: " << f << endl;
myFile.close();
myFile.open("data.txt", fstream::in|fstream::out);
myFile << f;
myFile.close();
return 0;
}