I wrote the following method to check whether my program works correctly with file IO, but it most definitely doesn't work. All that I get from inFile is "ELF", can anyone tell me why? My objects work perfectly fine with other types of istreams.
void testFiles(int ct, char ** args)
{
if(ct<2){
cout<<"Invalid number of arguments. Must be two files, one for input, one for output."<<endl;
return;
}
ifstream inFile;
inFile.open(args[0]);
Tree<Word,int> x;
Word *key;
Word *val;
cout<<"Tree extracted from file: "<<endl;
while(inFile.good()&&inFile.is_open()){
key = new Word();
val = new Word();
inFile>>*key;
inFile>>*val;
if(!inFile.good()){
cout<<"Error: incomplete key-value pair:"<<key->getStr()<<endl;
break;
}
cout<<key->getStr()<<" "<<val->getStr()<<endl;
x[*key] = val->asInt();
delete key;
delete val;
}
inFile.close();
ofstream outFile;
outFile.open(args[1]);
cout<<"Tree as read from file:"<<endl<<x;
outFile<<x;
outFile.close();
}
args[0] is not the first argument to your program. It's the name of the executable file itself.
What's happening is that you're opening your own executable file, rather than the file specified on the command line, and since your program is a linux binary, you're reading in the magic string at the start of ELF binaries, which is "ELF".
To fix the error, change args[0] to args[1].
You are specifying the program name instead of the first param as a file name.
It is a good idea to check for the validity of what U do. ie. check either whether the args[1] is not empty and/or the return value of file open... Only checking the parameter count is not enough.
Related
So currently I am working on an assignment, and for a section of it I need to be able to read a .txt file into a linked list of type char. I was already confused trying to do this, so I set out on a different path and decided to try to copy the text from the file into a char array, and then one by one copy the values in the array into the linked list.
So far I have my program compiling and running up to a certain point, before I receive the error Segmentation fault (core dumped).
The code for reading the file is as follow:
void readFile(list<char> &originList, string fileName){
ifstream fileInput;
fileInput.open(fileName.c_str());
int arraySize = fileInput.gcount();
char tempHold[arraySize];
if (!fileInput) {
cout << "Can't open file: " << fileName << "\n";
} else {
string contents((istreambuf_iterator<char>(fileInput)), istreambuf_iterator<char>());
strcpy (tempHold, contents.c_str());
for (int x = 0; x < fileInput.gcount(); x++) {
originList.push_back(tempHold[x]);
}
}
fileInput.close();
}
Also to add some context, using cout I determined that the code stops running, instead presenting the error, at the following point:
strcpy (tempHold, contents.data());
Also, I am not 100% on how exactly they work, only a loose idea to be honest. I mostly sourced the idea from this Stack Overflow question,
How to copy a .txt file to a char array in c++, but got confused somewhere a long the way.
Thanks in advance for any help you can provide.
istream::gcount returns the number of characters extracted by the last unformatted input operation performed on the object. Since you did not read anything from the file, you should get something wrong.Call, for example, istream.getline(); before calling gcount()
Like my comment to your question says, read each character from the file and add it to the list.
void readFile(list<char> &originList, string fileName) {
ifstream fileInput(fileName.c_str());
if (!fileInput) {
cout << "Can't open file: " << fileName << "\n";
}
char c;
while (fileInput.get(c)) {
originList.push_back(c);
}
}
Note: while (fileInput.get(c)) This reads the character and returns the stream. When a stream is used as a bool value it checks to see if the stream is valid. Valid means eof() and bad() are both false. - From a comment to the answer to the question linked below.
My answer was adapted from this other Stack Overflow question: Reading from text file until EOF repeats last line
This is how I get the name of the file from the command line and open a file and save the content of the file line by line to a string. All the procedures works fine except three empty spaces at the beginning of the file. Is anyone can say why these empty spaces occurred and how can I ignore them?
string filename = "input.txt";
char *a=new char[filename.size()+1];
a[filename.size()]=0;
memcpy(a,filename.c_str(),filename.size());
ifstream fin(a);
if(!fin.good()){
cout<<" = File does not exist ->> No File for reading\n";
exit(1);
}
string s;
while(!fin.eof()){
string tmp;
getline(fin,tmp);
s.append(tmp);
if(s[s.size()-1] == '.')
{
//Do nothing
}
else
{
s.append(" ");
}
cout<<s<<endl;
The most probable cause is that your file is encoded in something else than ASCII. It contains a bunch of unprintable bytes and the string you on the screen is the result of your terminal interpreting those bytes. To confirm this, print the size of s after the reading is done. It should be larger than the number of characters you see on the screen.
Other issues:
string filename = "input.txt";
char *a=new char[filename.size()+1];
a[filename.size()]=0;
memcpy(a,filename.c_str(),filename.size());
ifstream fin(a);
is quite an overzealous way to go about it. Just write ifstream fin(a.c_str());, or simply ifstream fin(a); in C++11.
Next,
while(!fin.eof()){
is almost surely a bug. eof() does not tell if you the next read will succeed, only whether the last one reached eof or not. Using it this way will tipically result in last line seemingly being read twice.
Always, always, check for success of a read operation before you use the result. That's idiomatically done by putting getline in the loop condition: while (getline(fin, tmp))
I've written a program that takes its first argument and reverses the letters. So, for instance:
revstr cat
Will produce tac.
Now I want this to work when a file is redirected in. So, if filler.txt is a file containing "Now is the time for all good men to come to the aid of their country!", then:
revstr < filler.txt
Should produce:
!yrtnuoc rieht fo dia eht ot emoc ot nem doog lla rof emit eht si woN
But I don't know how to detect that such redirection is occurring!
This is what I've tried - obviously, it's no good. Where am I going wrong?
int main(int argc, char* argv[]) {
string temp,input,output;//store input from file, and get which file//
ofstream out("output.txt");
if(argc == 3)
{
if(ifstream(argv[2]))
{
input = argv[2];
ifstream in(input);
while(in.good())
{
in >> temp;
ReverseWord(temp);
cout << temp << endl;
out << temp << endl;
}
}
else
ReverseWord(argv[2]);
}
else
}
I'm fairly new to C++ and am doing my best to learn.
There are two possible approaches for you (well, you can even support both):
You can accept a file name as command line argument (using a main that accepts arguments), then open an ifstream using this filename as the stream to read from. Users use your program like revstr filename.txt.
You can read your input from std::cin. Then users need to use redirection to pass you the contents of a file. If your program is started using: revstr < filename.txt, then reading from std::cin will read the contents of the file. The program never even sees the filename.
You can support both by reading from an ifstream, if you get an argument, and from cin, if you don't get an argument. The function that does the reading can get the steam passed in as a generic istream&.
You should change your definition of your main() function so that it accepts arguments passed from command line:
int main(int argc, char* argv[])
The first variable will hold the number of command-line arguments provided, the second is a vector whose elements are pointers to NULL-terminated strings. These strings are the command-line arguments themselves. Please keep in mind, that the first string will always be the name of the executable.
For instance, supposing the name of the file to be opened will be passed as the first argument:
int main(int argc, char* argv[])
{
std::string filename;
if (argc > 1)
{
// Oh, there's some command line arguments here...
filename = argv[0];
}
// Go on processing...
}
I'm trying to write a program that will save the contents of a linked list (each individual list is called a locality and includes a mix of data types). The code compiles but terminates unexpectedly; it refers me to the lines in the ifstream library (even though I only want to be using writing)
*_Str = _Elem(); // add terminating null character
Does anyone have an idea whats gone wrong?
//saves a single locality onto a file
void fSave_locality(Clinked *current, fstream *fout)
{
fout->write(current->site_name,100);
fout->write((char*) ¤t->cood_x,sizeof(double));
fout->write((char*) ¤t->cood_y,sizeof(double));
fout->write((char *) ¤t->dip,sizeof(double));
fout->write((char *) ¤t->strike,sizeof(double));
if (current->next!=NULL) fSave_locality(current->next,fout);
}
void fSave_list(char* fname)
{
fstream *fout;
do
{
cout<<"Would you like to save as a (b)inary or (t)ext file? ";
test = getch();
cout<<"Enter file name (make sure its unique!): ";
cin.getline(fname,100);
if(toupper(test)=='T') fout->open(fname, fstream::out);
if(toupper(test)=='B') fout->open(fname, fstream::out| fstream::binary);
}
while(toupper(test)!='T' || toupper(test)!='B');
if(fout->fail())
{
cout<<"unable to open file.\n";
exit(0);
} //it gets to here without any problems.
current = start;
while(current->next!=NULL)
{
fSave_locality(current, fout);
current=current->next; //repeat for the next object in the list
}
fout->close();
}
I don't understand why you are iterating recursively and sequentially in the same time ?
Just choose one or the other, I changed the code, you also need to set a correct limit to your while loop and make sure you do not use a null object and try to access elements on a null object.
void fSave_locality(Clinked *current, fstream *fout)
{
fout->write(current->site_name,100);
fout->write((char*) ¤t->cood_x,sizeof(double));
fout->write((char*) ¤t->cood_y,sizeof(double));
fout->write((char *) ¤t->dip,sizeof(double));
fout->write((char *) ¤t->strike,sizeof(double));
//if (current->next!=NULL) fSave_locality(current->next,fout); // comment this out
}
and change the below part :
while(current!=NULL)
{
fSave_locality(current, fout); // you should either comment this one or the recursive one
current=current->next; //repeat for the next object in the list
}
we are running into an odd issue when trying to parse an input file. the idea is that this file can include other files, which must be parsed as well. We are doing this recursively in a function defined as
int parse_inp(const char* filename)
The main file parses no problem, but recursive calls cannot open their file streams.
int parse_inp(const char* filename)
{
char buffer[BUFFER_MAX+1];
char* token;
std::string tok;
int keywordSection;
bool end_of_file;
int cardNum;
...
int i;
std::string tempop;
double tempd1, tempd2;
SetSegmentCard2 tempSetSegmentCard2;
int offset;
printf("%s\n", filename);
std::ifstream inp;
inp.clear();
inp.open(filename, std::ios::in);
if(!inp.good() || !inp.is_open())
{
char path1[256];
getcwd(path1,256);
printf("CWD: %s\n", path1);
fflush(NULL);
printf("Unable to open '%s'\n", filename);
return 0;
}
std::set<std::string> unrecognized;
std::string line;
while(inp.good() && !inp.eof())
{
getline(inp, line);
strcpy(buffer, line.c_str());
if (isComments(buffer)) //skip the comments line
continue;
if (buffer[0]=='*') //this is a keyword line
{
token = strtok(buffer," \n");
keywordSection = is_inp_keyw(token);
if (keywordSection==0)
unrecognized.insert(token);
cardNum = 0;
continue;
}
//a data line
tempop="";
char* found = NULL;
char path_buffer[100] = "Dyna3DWriter\\";
int pos = 0;
switch(keywordSection)
{
case 0: //not recognized
//end of last keyword, not recognizable word
break;
case 1: //KEYWORD
//"KEYWORD didn't do anything
break;
case 2: //TITLE
break;
case 3: //INCLUDE
token = strtok(buffer, "\n");
inp.clear();
parse_inp(token);
break;
...
}
}
if(inp.is_open())
{
inp.close();
inp.clear();
}
}
The recursive files never parse. I looked around a lot and most issues seemed to be either that the fail bit was set (which is why we are calling inp.clear() a lot), or that we are making the wrong assumption about the current working directory.
To test the second theory, we added in:
if(!inp.good() || !inp.is_open())
{
char path1[256];
getcwd(path1,256);
printf("CWD: %s\n", path1);
fflush(NULL);
printf("Unable to open '%s'\n", filename);
return 0;
}
And our working directory and file name are both correct. We see the same behavior when using fopen(filename, "r") --- a call to perror("fopen") results in:
fopen: no such file or directory
EDIT: Filled in more code
Are you sure the filename does not contain any garbage or bad character that would lead to this issue?
If the error is file not found, that means the filename is wrong in some way.
Could it come from a bad declaration of buffer? We don't see it in your code.
Another possibility is that you use strtok again in your initialization before opening the file. You must avoid using strtok that is based on global storage for recursive method like this. You should use strtok_r instead.
If your recursive function is called very deeply you can easily overload the OS limit on the number of open files.
I used to run my Gentoo Linux with a per-process file limit of 250 with exceptions for programs that needed a lot more.
Windows has limits that vary depending on how much memory is available to the system and how many objects have already been created system-wide.
The smart way to do this is to have two functions. The first function is the one everyone else calls and it does the setup, including opening the file. The second function is the recursive function and it takes nothing but a reference to a std::ifstream object.
EDIT:
I see that I misunderstood your question, and you aren't recursively opening the same file. I will leave my above paragraph anyway.