Thread: comparison between pointer and integer

  1. #1
    Registered User
    Join Date
    Feb 2003
    Posts
    596

    comparison between pointer and integer

    If endptr is of type char**, **endptr is not a pointer.
    So why does this give me:
    Code:
    scrap.c: In function ‘main’:
    scrap.c:14: warning: comparison between pointer and integer
    ?
    But, if I replace NULL with 0 or '\0', the warning goes away.

    (in both gcc 4.1.2 and gcc 3.4.6)

    Code:
    #include <stdio.h>
    
    int main( int argc, char** argv ) {
      if (argc < 4) {
        printf ("\nUsage: threshEdges <input_filename> <threshold> "
                "<output_filename>\n");
        return 0;
      }
      char **endptr;
      long threshold;
      threshold  = strtol(argv[2], endptr, 10);
      printf("**endptr: %d\n", **endptr);
      printf("argv[2]: %d\n", threshold);
      if (**endptr != NULL) {
        printf ("\nUsage: threshEdges <input_filename> <threshold> "
                "<output_filename>\n"
                "%s is not a valid threshold.\n", argv[2]);
        printf("**endptr: %d\n", **endptr);
        return 0;
      }
        
      return 0;
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,662
    Always read the manual page for a function. It's not enough just to declare a variable of the right type just to make the compiler shut up.

    > char **endptr;
    > long threshold;
    > threshold = strtol(argv[2], endptr, 10);
    Should be
    char *endptr;
    long threshold;
    threshold = strtol(argv[2], &endptr, 10);

    Same effective type passed to strtol(), but completely different outcome.

    Then you can do
    if ( *endptr == '\0' )
    kind of things.

    Oh, and you're mixing declarations and statements, which isn't standard C (C89 anyway).
    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.

  3. #3
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    I thought I was reading the manual. I read this:
    Code:
    long int
    strtol(const char *nptr, char **endptr, int base);
    When a parameter is defined as a **SOMETHING, does it always mean the address of a pointer to a SOMETHING?

    (I suppose the difference is whether memory is allocated for a pointer to a SOMETHING, or a pointer to a pointer, correct?)

    Does a function ever actually want a pointer-pointer? How would that be distinguished in the manual?

    (Thanks for pointing out my non-C scattering of declarations. I found that that was causing a seg fault in another piece of code.)

    PS: I made the changes you suggested but I'm still getting the "comparison between pointer and integer" warning when I compare to NULL.
    Last edited by R.Stiltskin; 03-24-2007 at 11:48 AM.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,662
    > threshold = strtol(argv[2], &endptr, 10);
    The & takes endptr (a char*) and yields a char**

    Code:
    #include <stdio.h>
    #include <stdlib.h> /* missing */
    
    int main( int argc, char** argv ) {
      char *endptr;
      long threshold;
      if (argc < 4) {
        printf ("\nUsage: threshEdges <input_filename> <threshold> "
                "<output_filename>\n");
        return 0;
      }
      threshold  = strtol(argv[2], &endptr, 10);
      printf("**endptr: %d\n", *endptr);
      printf("argv[2]: %ld\n", threshold); /* format */
      if (*endptr != '\0' ) {
        printf ("\nUsage: threshEdges <input_filename> <threshold> "
                "<output_filename>\n"
                "%s is not a valid threshold.\n", argv[2]);
        printf("*endptr: %d\n", *endptr);
        return 0;
      }
        
      return 0;
    }
    
    
    $ ./a.exe 12 34 56
    **endptr: 0
    argv[2]: 34
    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.

  5. #5
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Quote Originally Posted by R.Stiltskin
    PS: I made the changes you suggested but I'm still getting the "comparison between pointer and integer" warning when I compare to NULL.
    Why do you want to compare to NULL ?
    You want to check if endptr correctly points to a '\0' ( the end of the string ).
    salem told you
    Code:
    if ( *endptr == '\0' )
    is what you need
    Kurt

  6. #6
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Quote Originally Posted by Salem
    > threshold = strtol(argv[2], &endptr, 10);
    The & takes endptr (a char*) and yields a char**

    Code:
    ...
    
    $ ./a.exe 12 34 56
    **endptr: 0
    argv[2]: 34
    My original code gives the same result. The only difference is that the compiler complains (warns) about my comparison to NULL, but not about a comparison to 0 or to '\0', and this is the same whether I use endptr (where endptr is type char**) or &endptr (where endptr is type char*).


    Quote Originally Posted by ZuK
    Why do you want to compare to NULL ?
    I suppose I shouldn't be using NULL in this instance -- although it works. Doesn't NULL = '\0' = 0?

    But even if my use of NULL is inappropriate in this case, I'm still curious as to why the compiler complains about the comparison to NULL but not about a comparison to 0 or to '\0', when they're all essentially the same.

  7. #7
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    NULL is sometimes defined as ((void *)0), which is a void pointer to the number 0. Yes, it resolves to 0, but it's generally meant in that case to be used to compare with pointers, not chars since a char is not a pointer.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,662
    If your compiler declares NULL as (void*)0 then they are not the same thing, and you're back to comparing a pointer and an int.

    > My original code gives the same result.
    Except that your **endptr doesn't point anywhere special, so you just trash a bit of someone else's memory (and get lucky).
    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.

  9. #9
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Quote Originally Posted by MacGyver
    NULL is sometimes defined as ((void *)0), which is a void pointer to the number 0. Yes, it resolves to 0, but it's generally meant in that case to be used to compare with pointers, not chars since a char is not a pointer.
    Now I see. When the compiler said "comparison between pointer and integer" I assumed NULL was the integer & I couldn't understand why it would be calling **endptr a pointer. Thanks.


    Quote Originally Posted by Salem
    Except that your **endptr doesn't point anywhere special, so you just trash a bit of someone else's memory (and get lucky).
    Sorry to be dense, but I still don't see this. I agree that my **endptr is just a pointer, but I assumed that when I give endptr to strtol, strtol would assign a pointer to the address of the first non-numeric char in argv[2] to my pointer.

    I don't understand why that is fundamentally different from your char *endptr, which is also just a pointer and has no char memory space allocated to it.

    The memory for the actual char was already allocated to argv, wasn't it?

  10. #10
    Registered User Noir's Avatar
    Join Date
    Mar 2007
    Posts
    218
    but I assumed that when I give endptr to strtol, strtol would assign a pointer to the address of the first non-numeric char in argv[2] to my pointer.
    Okay, that accounts for what goes into the address pointed to by endptr, but where does endptr point to? Don't assume anything. In Salem's code, endptr is assigned to by strtol because he passes the address of it. That accounts for all levels of indirection. In your code, you didn't account for the first level even though strtol takes care of the second level.

  11. #11
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    OK, so whenever a function wants a char** as an argument, I should declare a char* and pass it's address to the function?

  12. #12
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Quote Originally Posted by R.Stiltskin
    OK, so whenever a function wants a char** as an argument, I should declare a char* and pass it's address to the function?
    You can't generalize that. But it's always a good idea to read the manual
    endptr
    Reference to an object of type char*, whose value is set by the function to the next character in str after the numerical value.
    This parameter can also be a null pointer, in which case it is not used.
    Kurt

  13. #13
    Registered User Noir's Avatar
    Join Date
    Mar 2007
    Posts
    218
    OK, so whenever a function wants a char** as an argument, I should declare a char* and pass it's address to the function?
    If a function wants a char** it means that it's going to save a pointer. It's like when you want to save an int, you pass a pointer to the int:
    Code:
    void save( int *p ) {
      *p = 0;
    }
    
    
    int main( void ) {
      int x;
    
      save( &x );
    
      return 0;
    }
    You wouldn't do this because the pointer doesn't point anywhere meaningful:
    Code:
    int main( void ) {
      int *x;
    
      save( x );
    
      return 0;
    }
    It's the same thing if you want to save a pointer, you pass a pointer to the pointer:
    Code:
    void save( int **p ) {
      *p = NULL;
    }
    
    
    int main( void ) {
      int *x;
    
      save( &x );
    
      return 0;
    }
    Likewise, you wouldn't do this because the pointer doesn't point anywhere meaningful:
    Code:
    int main( void ) {
      int **x;
    
      save( x );
    
      return 0;
    }
    The only difference is an extra * in the code. All the concepts are the same. But that doesn't mean that you always do it that way. You might want to allocate memory to the pointer and then it points somewhere, so everything's good:
    Code:
    int main( void ) {
      int *p;
      int **x = &p;
    
      save( x );
    
      return 0;
    }

  14. #14
    Registered User
    Join Date
    Feb 2003
    Posts
    596


    OK, you finally got through to me.

    Thanks, all of you.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. sorting number
    By Leslie in forum C Programming
    Replies: 8
    Last Post: 05-20-2009, 04:23 AM
  2. memory issue
    By t014y in forum C Programming
    Replies: 2
    Last Post: 02-21-2009, 12:37 AM
  3. Link List math
    By t014y in forum C Programming
    Replies: 17
    Last Post: 02-20-2009, 06:55 PM
  4. Looking for constructive criticism
    By wd_kendrick in forum C Programming
    Replies: 16
    Last Post: 05-28-2008, 09:42 AM
  5. Direct3D problem
    By cboard_member in forum Game Programming
    Replies: 10
    Last Post: 04-09-2006, 03:36 AM