2

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();
}
Kijewski
  • 25,517
  • 12
  • 101
  • 143
LucienK
  • 310
  • 2
  • 5
  • 12
  • To clarify, Word is a custom String object, and after inFile>>*key;, key has the string "ELF" inside it. This does not happen with any other istream – LucienK Apr 02 '13 at 21:53
  • 1
    What are you using as the value of `args`? If you are using the `argv` from `main`, then `argv[0]` (and thus `args[0]`) is the name of the executable, and you are opening the executable file. In Linux executable files are stored using a format called `ELF`... Guess what the first three bytes of an `ELF` file are? – Nik Bougalis Apr 02 '13 at 21:54
  • 1
    Your syntax is terrible. Please do not use C90-style variable declarations. If you need `key` and `val` inside the loop, then declare them exactly there. I guess `Word` is not big enough to justify the allocation on the heap. – Kijewski Apr 02 '13 at 22:59
  • In addition to Kay's comment: when you create an object such as `outFile`, pass the available arguments to the constructor: `ofstream outFile(args[1]);`. – MSalters Apr 03 '13 at 13:48

2 Answers2

9

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].

SecurityMatt
  • 6,593
  • 1
  • 22
  • 28
  • Thanks, that fixed it. I'll check you off as the answer as soon as it lets me – LucienK Apr 02 '13 at 21:54
  • @Dazedy: Yeah, if you are not used to C or C++, I can understand. Also, if this code was on windows, I believe your program would crash. – Jesse Good Apr 02 '13 at 21:59
  • @JesseGood: If it works on Linux, I can't think why it wouldn't work on Windows. It would just return the word "MZ" instead of "ELF". – SecurityMatt Apr 02 '13 at 22:01
  • @SecurityMatt: Sorry, I was thinking of overwriting an executable while it is running, not reading from it. In windows this is not allowed, but on linux it is possible. – Jesse Good Apr 02 '13 at 22:07
0

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.

Kupto
  • 2,802
  • 2
  • 13
  • 16
  • @Kupto: Could you suggest what I need to specify on the command line to end up with a "NULL reference being sent to program as parameter"? That sounds to me like it would be in violation of the C standard that the parameter to main is int argc, char** argv, where argc >= 1, and argv holds argc number of char*s? – SecurityMatt Apr 02 '13 at 22:04
  • @SecurityMatt firstly programs do not get called from command line only, secondly you might enjoy this: http://stackoverflow.com/questions/4390007/in-either-c-or-c-should-i-check-pointer-parameters-against-null-nullptr# – Kupto Apr 02 '13 at 22:14
  • @SecurityMatt In 5.1.2.2.1 the C standard guarantees that `argv[argc] == NULL`. Granted, that's not a "NULL reference", but if you run your programs without parameters (fairly common), `argv[1]` is `NULL`. – Nik Bougalis Apr 02 '13 at 22:39
  • On the other hand, I don't believe there's a *requirement* that `argv[i]` be non-NULL for a value of `i < argc`. With that said, I think that sort of scenario is exceedingly unlikely to occur in practice. @Kupto I think the term "NULL reference" is confusing, and you may want to revise it. – Nik Bougalis Apr 02 '13 at 22:48
  • @NikBougalis: You might be interested to read the C standard's 5.1.2.2.1, which includes "argv[0] through argv[argc-1] inclusive shall contain pointers to strings" and "the strings pointed to by the argv array shall be modifiable by the program", which guarantees that they are not NULL. Even if programs are not called from the command line, they are always called *into* by the C runtime, which is required to follow these rules. Hence, no, argv[1] will not be NULL if argc is 2. – SecurityMatt Apr 02 '13 at 23:01
  • @SecurityMatt: Ahh, I missed the "*modifiable by the program*" bit, which (opaque as it may be) pretty much requires that they are not `NULL`. Thanks for pointing that out. – Nik Bougalis Apr 02 '13 at 23:18
  • @SecurityMatt: Yes you are correct. I have never realized that this is what this section of standard implies. Thank you for expanding my knowledge. – Kupto Apr 02 '13 at 23:59