Fgetc + Skipping first character,

This is a discussion on Fgetc + Skipping first character, within the C Programming forums, part of the General Programming Boards category; Hi, When inputting a file using Fgetc, my program always skips the first character of the file being read. Code: ...

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    2

    Fgetc + Skipping first character,

    Hi,

    When inputting a file using Fgetc, my program always skips the first character of the file being read.

    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    #define FILENAME "x.txt"
    
    int main(void)
    {
    FILE *fp;
    int row, col;
    int ROWS,COLS;
    int ch;
    int i = 0;
    fp = fopen(FILENAME, "r");
    row = 0;
    col = 0;
    
    while ((ch = fgetc(fp) != EOF)){
    	if (ch != ' ' || ch != '*'){
    		fscanf(fp, "%d%d", &ROWS, &COLS);
    	}
    }
    printf("ROWS = %d COLS = %d\n", ROWS, COLS);
    
    	   return 0;
    }
    Is there anyway of getting this function to read the first element of a text file without changing the text file itself?

    Thanks Alot

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,796
    >my program always skips the first character of the file being read.
    It reads the first character, and you test it against a space and an asterisk. If it's not one of those, it's probably a character you don't want to throw away, so that's why you say your program "skips" the first character. Try this:
    Code:
    while ((ch = fgetc(fp) != EOF)){
      if (ch != ' ' || ch != '*'){
        ungetc ( ch, fp );
        fscanf(fp, "&#37;d%d", &ROWS, &COLS);
      }
    }
    If you have to use ungetc, it's a sign that your input is poorly designed. A much better solution is to read a line at a time and parse the line in memory. That way you don't "lose" any characters until you overwrite the string. In that case you could do this (assuming each row and column value is on a separate line):
    Code:
    while ( fgets ( line, sizeof line, fp ) != NULL ) {
      if ( line[0] != ' ' && line[0] != '*' ) {
        sscanf ( line, "%d%d", &ROWS, &COLS );
        printf ( "ROWS = %d COLS = %d\n", ROWS, COLS );
      }
    }
    On a side note, you probably want && instead of ||.
    My best code is written with the delete key.

  3. #3
    Registered User
    Join Date
    Oct 2007
    Posts
    2
    Thanks for that prelude, but it doesn't seem to be working.

    I think it has something to do with the structure of the input file.

    It has on the first line two numbers seperated by a space which indicate the size of the data that is to be imported ( in terms of rows and columns)

    Below this is the data (which consists of spaces and astrixes), which is imported using fgetc.

    Later on in the source file (not indicated above), this imported data is converted into an array.

    The purpose of those top two numbers is so the program can detect the size of the array that will be eventually created.

    Thanks Alot.

  4. #4
    Registered User
    Join Date
    Jul 2007
    Posts
    151
    Quote Originally Posted by Aoedogg View Post
    Hi,

    When inputting a file using Fgetc, my program always skips the first character of the file being read.

    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    #define FILENAME "x.txt"
    
    int main(void)
    {
    FILE *fp;
    int row, col;
    int ROWS,COLS;
    int ch;
    int i = 0;
    fp = fopen(FILENAME, "r");
    row = 0;
    col = 0;
    
    while ((ch = fgetc(fp) != EOF)){
    	if (ch != ' ' || ch != '*'){
    		fscanf(fp, "%d%d", &ROWS, &COLS);
    	}
    }
    printf("ROWS = %d COLS = %d\n", ROWS, COLS);
    
    	   return 0;
    }
    Is there anyway of getting this function to read the first element of a text file without changing the text file itself?

    Thanks Alot
    I am sorry if I misunderstood and am writing foolish ; but when u say :
    >while ((ch = fgetc(fp) != EOF)){

    You have already read the first character. So you took the first character into the ch variable. I did not understand the prupose of your program but if you are then trying to take integers into your rows variable you will be starting by the second character. These are that I can tell from what I understood from your post so far. Sorry if I misunderstood.

  5. #5
    Registered User
    Join Date
    Jul 2007
    Posts
    151
    You could do

    Code:
    int cont=0; /*this will control your starting time of the loop */
    while ((ch = fgetc(fp) != EOF)){
    cont++;
    if(cont==1) rewind(fp);	
    if (ch != ' ' || ch != '*'){
    		fscanf(fp, "&#37;d%d", &ROWS, &COLS);
    	}
    This will solve your problem I guess

    Prelude told you a lot to solve your problem though. Ungetc is not a good way to solve but useful. But first taking information into a string then modifying the codes is what I do usually.
    Last edited by ozumsafa; 10-06-2007 at 02:26 PM.

  6. #6
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    That code wouldn't work very well. You'd end up reading the first line over and over again infinitely. Use Prelude's code.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  7. #7
    cas
    cas is offline
    Registered User
    Join Date
    Sep 2007
    Posts
    983
    While fgets() is definitely the better choice, there's a bug in the original code that I think should be pointed out, so it's not repeated in the future.

    The line:
    Code:
    while ((ch = fgetc(fp) != EOF))
    is parsed as
    Code:
    while ( ch = (fgetc(fp) != EOF) )
    You meant to say:
    Code:
    while( (ch = fgetc(fp)) != EOF )
    As it stands, your code will only store the value 1 in ch, except when it hits EOF; in that case, 0 is stored. I suppose you put that extra set of parentheses around the condition because gcc (or perhaps another compiler) warned about assignment as a truth value. The parentheses likely silenced the compiler, but the bug still exists!

  8. #8
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    Good catch, one that all of the rest of us missed . . . if you're ever in doubt about which operator binds tighter, use parentheses or check a precedence table.

    It would also be a good idea to make sure that fopen() managed to open the file. And to fclose() it when you're done with it.

    Plus you're not using anything from <ctype.h> at the moment, although I'm sure you intend to in the future.

    As it stands, your code will only store the value 1 in ch, except when it hits EOF; in that case, 0 is stored.
    Nitpick: I'm pretty sure that the comparison operators are only guaranteed to return nonzero on success, not 1. But I can't say that I've ever seen a compiler that used, say, -1 instead of 1.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  9. #9
    cas
    cas is offline
    Registered User
    Join Date
    Sep 2007
    Posts
    983
    Nitpick: I'm pretty sure that the comparison operators are only guaranteed to return nonzero on success, not 1. But I can't say that I've ever seen a compiler that used, say, -1 instead of 1.
    They do yield 1: 6.5.9 in C99, 6.3.9 in C90 (so probably 3.3.9 in C89).

  10. #10
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    Sorry . . . in that case, I guess I was mistaken.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  11. #11
    Registered User
    Join Date
    Jul 2007
    Posts
    151
    Excuse me , but why would my code read the first line over and over again. That is impossible for this case dwks. If you looked carefully , you would see that rewind will work for just one time. Am I wrong somewhere?

  12. #12
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    No, you're right -- the code will only execute rewind() once. But it's still a bad way to do things, and will only work properly when the first character you read is the first character in the file, and then only that once. I could envision, for example, using fseek() to move the file pointer backwards one character; but rewind() is quite inappropriate.

    Code:
    int cont=0; /*this will control your starting time of the loop */
    while ((ch = fgetc(fp) != EOF)){
    cont++;
    if(cont==1) rewind(fp);	
    if (ch != ' ' || ch != '*'){
    		fscanf(fp, "&#37;d%d", &ROWS, &COLS);
    	}
    Also note that the condition (ch != ' ' || ch != '*') will always be true.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  13. #13
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,796
    >I could envision, for example, using fseek() to move the file
    >pointer backwards one character; but rewind() is quite inappropriate.
    If fseek is appropriate, how could rewind not be? At this point we're talking about the first character in the file, so:
    Code:
    fseek ( fp, -1, SEEK_CUR );
    and the equivalent of rewind:
    Code:
    fseek ( fp, 0, SEEK_SET );
    are basically identical operations. In fact, depending on the implementation of fseek, the two could very well be exactly identical. For example, here's one of my implementations:
    Code:
    int _intern_seek ( FILE *stream, fpos_t offset, int whence )
    {
      int err = 0;
      LARGE_INTEGER pos;
    
      /*
        SEEK_CUR is a pain, especially with padding and text expansion.
        Let's ignore it completely and work from SEEK_SET instead
      */
      if ( whence == SEEK_CUR ) {
        fpos_t curr;
    
        if ( _intern_tell ( stream, &curr ) != 0 ) {
          errno = _ESETP;
          return 1;
        }
    
        offset += curr;
        whence = SEEK_SET;
      }
    
      /* Flush output streams in write mode, discard otherwise */
      if ( stream->_flag & _WRITE )
        _intern_flush ( stream );
      else
        _deque_init ( stream->_buf, stream->_buf._base, stream->_buf._size );
    
      /* Clear the unget buffer if present */
      if ( stream->_unget._base != NULL )
        _deque_init ( stream->_unget, stream->_unget._base, stream->_unget._size );
    
      /* The next operation may be a read or a write */
      stream->_flag &= ~( _READ | _WRITE );
      stream->_flag &= ~_EOF;
    
      pos.QuadPart = offset;
      pos.LowPart = SetFilePointer ( stream->_fd, pos.LowPart, &pos.HighPart, whence );
    
      err = ( pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR );
    
      if ( err )
        errno = _ESETP;
    
      return err;
    }
    Any whence of SEEK_CUR is converted to the equivalent SEEK_SET, so:
    Code:
    fseek ( fp, -1, SEEK_CUR );
    becomes:
    Code:
    fseek ( fp, 0, SEEK_SET );
    Cool, huh?
    My best code is written with the delete key.

  14. #14
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    That is really neat.

    The problem is that I had just misunderstood the problem. But I think that the OP has misunderstood the problem, too.
    [The file] has on the first line two numbers seperated by a space which indicate the size of the data that is to be imported ( in terms of rows and columns)

    Below this is the data (which consists of spaces and astrixes), which is imported using fgetc.
    With a file format as simple as that, what's wrong with just using fscanf(), then possibly eating the whitespace, and then reading in asterisks and spaces? None of this ungetc stuff.

    In other words, if the file looks like
    Code:
    3 2
    * *
      *
    then you can just read it with something like
    Code:
    char line[BUFSIZ];
    int x, y, w, h;
    fgets(line, sizeof line, fp);
    sscanf(line, "&#37;d%d", &w, &h);
    for(x = 0; x < w; x++) {
        for(y = 0; y < w; y++) {
            data[x][y] = getc(fp);
        }
        getc(fp);  /* eat the newline */
    }
    That's without error checking, of course. And assuming that I've guessed the format correctly.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Errors including <windows.h>
    By jw232 in forum Windows Programming
    Replies: 4
    Last Post: 07-29-2008, 01:29 PM
  2. sequential file program
    By needhelpbad in forum C Programming
    Replies: 80
    Last Post: 06-08-2008, 01:04 PM
  3. Interpreter.c
    By moussa in forum C Programming
    Replies: 4
    Last Post: 05-28-2008, 05:59 PM
  4. character input using fgetc() code???
    By lesrhac03 in forum C Programming
    Replies: 3
    Last Post: 03-27-2008, 10:55 PM
  5. fgetc
    By Unregistered in forum C Programming
    Replies: 5
    Last Post: 09-10-2001, 11:57 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21