1

I want to simplify a txt document and I tried this code:

#include <iostream>
#include <conio.h>

using namespace std;

int main()
{
    // 1. Step: Open files
    FILE *infile;
    FILE *outfile;
    char line[256];
    infile = fopen("vcard.txt", "r");
    outfile = fopen("records.txt", "w+");
    if(infile == NULL || outfile == NULL){
         cerr << "Unable to open files" << endl;
         exit(EXIT_FAILURE);
    }

    // 2.Step: Read from the infile and write to the outfile if the line is necessary
    /* Description:
    if the line is "BEGIN:VCARD" or "VERSION:2.1" or "END:VCARD" don't write it in the outfile
    */

    char word1[256] = "BEGIN:VCARD";
    char word2[256] = "VERSION:2.1";
    char word3[256] = "END:VCARD";

    while(!feof(infile)){
        fgets(line, 256, infile);
        if(strcmp(line,word1)!=0 && strcmp(line,word2)!=0 && strcmp(line,word3)!=0){ // If the line is not equal to these three words
          fprintf(outfile, "%s", line); // write that line to the file
        }
    }

    // 3.Step: Close Files
    fclose(infile);
    fclose(outfile);

    getch();
    return 0;
}

Unfortunately, despite the infile includes word1, word2 and word3 hundred times I still get 1 or -1 as the return value of strcmp.

What should I try?

Scooter
  • 6,802
  • 8
  • 41
  • 64
  • 3
    you want to use C or C++ ? because your code looks more like a C source code than a C++ source code. – Ken Oct 21 '12 at 11:42
  • Doesn't really matter. C and C++ both is fine. I just wanted to use std::cout and std::cerr. Thats why I called it C++. –  Oct 21 '12 at 11:45
  • 1
    [“while( !feof( file ) )” is (almost) always wrong](http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong) – interjay Oct 21 '12 at 11:46
  • What's wrong? What's should I use instead? –  Oct 21 '12 at 11:47
  • Read the [fgets spec](http://www.cplusplus.com/reference/clibrary/cstdio/fgets/) *very* carefully. – Hot Licks Oct 21 '12 at 11:49
  • @user1762990 maybe **read the link** interjay put in his comment??? –  Oct 21 '12 at 11:50
  • C++ has a real support for strings where C offers no support for strings, strings in C are abstracted as arrays of char but they are not real "strings". You can solve your problem just taking a look to already published questions here on SO http://stackoverflow.com/questions/11635/case-insensitive-string-comparison-in-c http://stackoverflow.com/search?q=compare+string+file+c%2B%2B – Ken Oct 21 '12 at 11:53
  • Add this after your fgets(): line[ strlen(line) - 1] = '\0'; – Scooter Oct 21 '12 at 12:04
  • Actually, make that: if line[ strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; – Scooter Oct 21 '12 at 12:46

1 Answers1

1

fgets returns the newline character as part of the string. Since the strings you are comparing against don't contain a newline, they will be compared as different.

Since you are writing in C++, you may want to use std::ifstream and std::getline to read the file. The strings returned by getline will not have the newline in them, and as an added bonus you won't have to specify a limit on the line size.

Another (unrelated) issue: Using while (!foef(file)) is wrong, and can result in the last line being read twice. Instead, you should loop until fgets returns a null pointer.

interjay
  • 107,303
  • 21
  • 270
  • 254
  • So what shoud I use instead of fgets to fix the first issue? –  Oct 21 '12 at 11:52
  • @user1762990 first, make a separate call to `fgets()`, **only then** use the `while(feof(file) == 0)` loop... –  Oct 21 '12 at 11:53
  • @user1762990: I recommend using C++ classes as in my edit. If you use `fgets` you will need to remove the trailing newline yourself or compare it with a string that contains a newline (but note that the last line in the file may *not* contain a newline). – interjay Oct 21 '12 at 11:57
  • @H2CO3: That doesn't help, it can still read the last line twice. Just look at the return value of `fgets`, `feof` isn't needed in the loop condition. – interjay Oct 21 '12 at 11:59
  • @interjay I don't believe that is correct. How does fgets() while (! feof() ) { fgets() } read the last line twice? – Scooter Oct 21 '12 at 12:09
  • @Scooter: http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong. After `fgets` reads the last line, `feof` will not necessarily return nonzero until after the next read operation. – interjay Oct 21 '12 at 12:14
  • I used while(feof(infile) == 0) and changed the declerations like that: char word1[256] = "BEGIN:VCARD\n"; char word2[256] = "VERSION:2.1\n"; char word3[256] = "END:VCARD\n"; so it's works fine now. Thank you all. –  Oct 21 '12 at 12:20
  • @interjay The link you provided talks about problems using feof() with regard to an i/o error, which is great advice. But I don't see anything about reading the last line twice. feof() I believe only returns true after you try and read past the end. Which doesn't cause a double read if it is fgets() while () { process line fgets() }. You read the last line, check for feof(), no, process that line. You read past the last line, check for feof(), yes, you exit the while loop and don't process any more data. – Scooter Oct 21 '12 at 12:28
  • @H2CO3 I don't believe an if/break is necessary. Ignoring the problems pointed out in that referenced question with regard to an I/O error, a "priming fgets()" allows all lines, but no extra lines, to be processed with while ( ! fgets() ) { process line ; fgets(); } – Scooter Oct 21 '12 at 12:33
  • 1
    @Scooter: Quote from the link: "This program will consistently print one greater than the number of characters in the input stream (assuming no read errors)". In the program here, `fgets` reads the last line and the program processes it. Then you call `feof` and it returns 0. Then you call `fgets` again. Since it encounters end of file immediately, it returns NULL and the buffer contents are unchanged. Your code then processes the last line again. Only after that you call `feof` again and it returns nonzero, but it's too late then. – interjay Oct 21 '12 at 12:34
  • @interjay That comment in the linked question, was made with respect to code that does NOT have a fgets()/fgetc() before the while loop. Which is different than what H2C03 and I are talking about. He and I are are referencing code that does fgets() while( ! feof() ) { process line; fgets; } The code here also does NOT do a priming fgets() which is what H2C03 was advocating and I am talking about. It appears we are talking about two different things. – Scooter Oct 21 '12 at 12:39
  • @Scooter: I see, but that's also bad, because it won't process the last line if it didn't contain a newline (and it's also pointlessly more complicated than the correct code, and doesn't handle errors correctly). – interjay Oct 21 '12 at 12:42
  • @interjay fgets() will read the last line if it doesn't contain a newline. It reads until newline or EOF. I agree that an IO error is not handled by a loop condition of just ( ! feof() ) – Scooter Oct 21 '12 at 12:44
  • @Scooter: It will read the last line, but `feof` will then return nonzero and your incorrect code won't process it. [Proof](http://ideone.com/lzJeOJ). And here's the [correct code](http://ideone.com/T2lQPX), both simpler and it works. – interjay Oct 21 '12 at 12:47
  • @interjay You're right! I guess I will have to use fgetc() from now on to handle lines not terminated with '\n'... ;) It seems like editors always end that last line with a '\n', even if you don't type it these days so I don't think I have ever hit that bug. – Scooter Oct 21 '12 at 13:08