Thread: Moving a file pointer in a function

  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
    37,490
    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
    626
    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
    Quote Originally Posted by CommonTater View Post
    It shouldn't.

    The function should be in a .c file separate from main and prototyped in a .h file included in main.
    The function implementations were together in the header (just out of laziness because I had been frequently changing the prototypes and it was frustrating for debugging), but I properly separated the String_Utilities.h into String_Utilities.c, recompiled, and still got an infinite loop.

  9. #9
    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.

  10. #10
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by 127.0.0.1 View Post
    The function implementations were together in the header (just out of laziness because I had been frequently changing the prototypes and it was frustrating for debugging), but I properly separated the String_Utilities.h into String_Utilities.c, recompiled, and still got an infinite loop.
    This is more form than substance...
    Headers (.h) should contain prototypes, typedefs, extern variables... no actual code.
    Function definitions, live structs and active variables belong in C files.

    Yes you can put active code in a .h file and the compiler won't care about it... but it is widely considered to be bad form because can lead to a lot of needless code duplication and errors if the header is included in a project more than once.

  11. #11
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,490
    > 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.

  12. #12
    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.

  13. #13
    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);
        }

  14. #14
    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.

  15. #15
    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;
            }

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