cpointersc-stringsargvchar-pointer

Understanding the dereference, address-of, and array subscript operators in C


I have argv[] defined as a char *. Using the following printf statements:

     printf("%s\n",argv[1]);   // prints out the entire string
     printf("%p\n",&argv[1]);  // & -> gets the address
     printf("%c\n",argv[1][0]);// prints out the first char of second var
     printf("%c\n",*argv[1]);  //  

It's this last one I don't understand. What does it mean to print *argv[1]? why isn't that the same as *argv[1][0] and how come you can't print out printf("%s\n",*argv[1]);. Also, why is &*argv[1] a different address then &argv[1]?


Solution

  • The array subscript operation a[i] is defined as *(a + i) - given the address a, offset i elements (not bytes) from that address and dereference the result. Thus, given a pointer p, *p is equivalent to *(p + 0), which is equivalent to p[0].

    The type of argv is char **; given that, all of the following are true:

        Expression         Type            Value
        ----------         ----            -----
              argv         char **         Pointer to a sequence of strings
             *argv         char *          Equivalent to argv[0]
            **argv         char            Equivalent to argv[0][0]
           argv[i]         char *          Pointer to a single string
          *argv[i]         char            Same as argv[i][0]
        argv[i][j]         char            j'th character of i'th string
          &argv[i]         char **         Address of the pointer to the i'th string
    

    Since the type of argv[i][j] is char, *argv[i][j] is not a valid expression.

    Here's a bad visualization of the argv sequence:

         +---+              +---+                                         +---+
    argv |   | ---> argv[0] |   | ---------------------------> argv[0][0] |   |
         +---+              +---+                     +---+               +---+
                    argv[1] |   | -------> argv[1][0] |   |    argv[0][1] |   |
                            +---+                     +---+               +---+
                             ...           argv[1][1] |   |                ...
                            +---+                     +---+               +---+
                 argv[argc] |   | ---|||               ...   argv[0][n-1] |   |
                            +---+                     +---+               +---+
                                         argv[1][m-1] |   |
                                                      +---+
    

    This may help explain the results of different expressions.