Thread: Moving a file pointer in a function

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92

    Moving a file pointer in a function

    I have a function that takes a file pointer and returns the next non-blank line of text (removing comments as well). However, even though the code works in main it obviously doesn't work when isolated in a function because it is unable to move the file pointer outside of its scope.

    Is there a way around this using pointer pointers? Or should I start looking at other ways to solve this problem

    Code:
      int Next_Line
      (
        FILE *Input,
        char *Line,
        int  Size,
        char *Comment_Prefix
      ){
        int Line_Length;
        int Prefix_Length = strlen(Comment_Prefix);
        if(Prefix_Length < 0 || Prefix_Length > 2)
          return FAILURE;
        do{
          do{
            if(feof(Input))
              return FAILURE;
            fgets(Line, Size, Input);
          }while(Line[0] == 10);
          Line_Length = strlen(Line);
          for(int i = 0;i <= Line_Length - Prefix_Length;i++)
            if((Prefix_Length == 1 && Line[i] == Comment_Prefix[0])
            || (Prefix_Length == 2 && Line[i] == Comment_Prefix[0]
            && Line[i + 1] == Comment_Prefix[1])){
              Line[i] = '\0';
              break;
            }
          Line_Length = strlen(Line) - 1;
          for(int i = 0;i <= Line_Length;i++)
            if(Line[i] != ' ' && Line[i] != '\t')
              break;
            else if(i == Line_Length - 1)
              Line[0] = '\0';
        }while(Line[0] == '\0');
        return SUCCESS;
      }
    Last edited by 127.0.0.1; 05-04-2011 at 09:53 AM.

  2. #2
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Look into the ftell() and fseek() functions... you should be able to hand the function the file at it's current position, let it do it's thing, reposition the pointer for you and then return the new position.
    Code:
    int FindNextLine(FILE *fp)
      { int tc;  // test character 
        while (1)
          { tc = (fgetc(fp))  // advance file pointer
             if (isalpha(tc))
               { fseek(fp,-1,SEEK_CUR); // reposition -1 spaces
                  return ftell(fp); }
             else if (tc == EOF)
               return EOF; }  }
    C is not a high level language... you will find it very helpful to think in smaller blobs... Each function does one function...

    Call the FindNextLine() function... then use another function (say) IsComment() to tell you if you eed to find the next line again.
    Code:
      do
       {  FindNextLine(fp); }
     while (IsComment(fp));
    You will probably find uses for both functions in tandem and separately throughout your code.
    Last edited by CommonTater; 05-04-2011 at 10:21 AM.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,667
    There must be something else going on, because that doesn't make any sense.

    This does what you expect.
    Code:
    $ gcc bar.c
    $ cat bar.c
    #include <stdio.h>
    void foo ( FILE *fp );
    int main (void)
    {
        FILE *fp = fopen("bar.c","r");
        char    buff[100];
        foo(fp);
        fgets( buff, sizeof buff, fp);
        fputs( buff, stdout );
        fclose(fp);
        return 0;
    }
    void foo ( FILE *fp ) {
        char buff[100];
        fgets( buff, sizeof buff, fp);
        fputs( buff, stdout );
    }
    $ ./a.out 
    #include <stdio.h>
    void foo ( FILE *fp );
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Quote Originally Posted by Salem View Post
    There must be something else going on, because that doesn't make any sense
    This is the code I used to call the function (the "!feof(Input)" while loop is infinitely repeated because the file pointer doesn't increment, it just prints the first line over and over):
    Code:
        FILE *Input;
        char Line[256];
        char Comment_Prefix[2] = "//";
        int Line_Length;
        int Prefix_Length = strlen(Comment_Prefix);
        Input = fopen("test.txt", "r");
        if(Input != NULL){
          while(!feof(Input)){
            Next_Line(&Input, Line, sizeof(Line), Comment_Prefix);
            printf("%s", Line);
          }
          fclose(Input);
        }
    And this is the test file I had it read:
    Code:
    TEST    TEST TEST 1
    
    
    
    TEST 2
    
                               
    
    
    
    TEST  3
    
    
            //TES TEST TEST
    
    //TEST
    
    Test 4
    Ttest 5 // TEST
    
    
    
    
    TEST
    Other than that I have no idea what other factors could contribute to fgets not working properly.

  5. #5
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Quote Originally Posted by 127.0.0.1 View Post
    Code:
            Next_Line(&Input, Line, sizeof(Line), Comment_Prefix);
    Lose the ampersand. Also turn on, turn up and fix the warnings your compiler gives. It would have complained about this. Also 2, don't use feof to control loops.
    Last edited by adeyblue; 05-04-2011 at 10:31 AM.

  6. #6
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Quote Originally Posted by adeyblue View Post
    Lose the ampersand. Also turn on, turn up and fix the warnings your compiler gives. It would have complained about this. Also 2, don't use feof to control loops.
    Sorry, I had tried to pass a file pointer pointer to the function to see if it would help (it didn't) and forgot to correct the code in the calling. It doesn't work with this code:

    Code:
    /************
     * Includes *
     ************/
     
      #include "../Core/String_Utilities.h"
      #include <stdio.h>
      
    /**************
     * Test_Cases *
     **************/
     
      int main
      (){
        FILE *Input;
        char Line[256];
        char Comment_Prefix[2] = "//";
        int Line_Length;
        int Prefix_Length = strlen(Comment_Prefix);
        Input = fopen("test.txt", "r");
        if(Input != NULL){
          while(!feof(Input)){
            Next_Line(Input, Line, sizeof(Line), Comment_Prefix);
            printf("%s", Line);
          }
          fclose(Input);
        }
      }
    Does it matter that the function Next_Line is in a header file separate from the main?

  7. #7
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by 127.0.0.1 View Post
    Does it matter that the function Next_Line is in a header file separate from the main?
    It shouldn't.

    The function should be in a .c file separate from main and prototyped in a .h file included in main.

  8. #8
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Code:
    This does what you expect.
    Salem, your solution does indeed work -- even when I separated it into another header. Which makes me further confused about my code.

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,667
    > int Prefix_Length = strlen(Comment_Prefix);
    Ooops...

    > char Comment_Prefix[2] = "//";
    Despite appearances, this is NOT a proper C-String. It does NOT have a \0, and thus your attempt to strlen() it will fail.

    The function doesn't read anything, it just returns fail immediately.

    Avoid setting a size for the string, unless it is absolutely important that it occupies a specific number of bytes.
    Normally, you do
    Code:
    char Comment_Prefix[] = "//";


    Which begs the next question, you worked so hard to return success/fail, why aren't you using it?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Avoid setting a size for the string, unless it is absolutely important that it occupies a specific number of bytes.
    Thank you, this did the trick. I guess I was so concerned that my function library was wrong that I didn't even consider that it was my debugging code with the problem xD.

    Final code:
    Code:
        FILE *Input= fopen("test.txt", "r");
        char Line[256];
        char Comment_Prefix[] = "//";
        int Line_Length;
        int Prefix_Length = strlen(Comment_Prefix);
        if(Input != NULL){
          while(Next_Line(Input, Line, sizeof(Line), Comment_Prefix))
            printf("%s", Line);
          fclose(Input);
        }

  11. #11
    Registered User
    Join Date
    Mar 2011
    Posts
    278
    Code:
    char Comment_Prefix[] = "//";
    If you aren't going to ever modify this string, it might be better to either make it a const (so the compiler will tell you if there are any attempts to write to it). Some static analysis programs will tell you this. I'm no stickler.

    Another option is to define it as a macro.

  12. #12
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Looking at this code...
    Code:
          for(int i = 0;i <= Line_Length - Prefix_Length;i++)
            if((Prefix_Length == 1 && Line[i] == Comment_Prefix[0])
            || (Prefix_Length == 2 && Line[i] == Comment_Prefix[0]
            && Line[i + 1] == Comment_Prefix[1])){
              Line[i] = '\0';
              break;
    ... there might be a simpler way to do this...

    Code:
    const char Comment_Prefix[] = "//";
    
    
    if (strstr(line[i],Comment_Prefix))
      break;
    strstr() from the strings.h library returns a pointer to the found string or NULL if it's not found. Seems like a pretty easy way to detect your comment prefix.

  13. #13
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Quote Originally Posted by CommonTater View Post
    ... there might be a simpler way to do this...

    Code:
    const char Comment_Prefix[] = "//";
    
    
    if (strstr(line[i],Comment_Prefix))
      break;
    strstr() from the strings.h library returns a pointer to the found string or NULL if it's not found. Seems like a pretty easy way to detect your comment prefix.
    Your solution doesn't work because the whole string is compared for the match, I need to know the index that the match is at so I can terminate the string if there is valid text before the comment.

    Also as a side note, I got rid of the !feof code and replaced it with the safer equivient (thanks for the article adeyblue).
    Code:
            if(!fgets(Line, Size, Input))
              return FAILURE;
          }while(Line[0] == 10);
          Line_Length = strlen(Line);
          Line[Line_Length - 1] = '\0';
          for(int i = 0;i <= Line_Length - Prefix_Length;i++)
            if(strstr(&Line[i], Comment_Prefix)){
              Line[i] = '\0'; /* I need to know the index the comment starts here */
              break;
            }

  14. #14
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by 127.0.0.1 View Post
    Your solution doesn't work because the whole string is compared for the match, I need to know the index that the match is at so I can terminate the string if there is valid text before the comment.
    Since StrStr returns a pointer to the first character in the matched string, you do know exactly where to plop your \0 to terminate the string with only a very slight modification.

    Code:
    bool KillCommentString(char *str)
      { char *cmt; // address of comment
         cmt = strstr(str,Comment_Prefix);
         if (!cmt)
           return 0;
         *cmt = 0;  // terminate the string
         return 1; }
    No offense is intended, but I'm thinking you're still trying to make this whole new thing into the same old thing you already understand and, as I mentioned before, that's a mistake.
    Last edited by CommonTater; 05-04-2011 at 02:11 PM.

  15. #15
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Since StrStr returns a pointer to the first character in the matched string, you do know exactly where to plop your \0 to terminate the string with only a very slight modification.
    My mistake, I misunderstood how strstr was used, and I agree it would make much cleaner code, but I looked at an implementation of strstr and I think that although my solution is not beautiful by any measure it does have less overhead. This operation is - after all - preformed on every single character in the file.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. moving the pointer
    By ^ARTICUNO^ in forum C++ Programming
    Replies: 5
    Last Post: 02-06-2011, 12:25 PM
  2. Have function return file pointer
    By krogz in forum C Programming
    Replies: 6
    Last Post: 05-03-2007, 08:56 PM
  3. Pointer problem with FILE *f in function
    By mabuhay in forum C Programming
    Replies: 6
    Last Post: 02-14-2006, 04:15 PM
  4. moving an array from function to function
    By Dan17 in forum C++ Programming
    Replies: 3
    Last Post: 11-23-2005, 04:07 PM
  5. Moving Mouse Pointer
    By loobian in forum Windows Programming
    Replies: 8
    Last Post: 10-16-2001, 03:45 PM