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

我的未来我决定 提交于 2019-12-11 05:38:56

问题


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]?


回答1:


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.




回答2:


char *argv[]

argv is array(1) of char pointers. So it is normal array just each element of the array is a pointer. argv[0] is a pointer, argv[1], etc.

argv[0] - first element in the array. Since each element in the array is char pointer, value of this is also a char pointer (as we already mentioned above).

*argv[1] - Now here argv[1] is second element in the above array, but argv[1] is also a char pointer. Applying * just dereferences the pointer and you get the first character in the string to which argv[1] points to. You should use %c to print it as this is just a character.

argv[1][0] is already first character of second string in the array - so no more room for dereferencing. This is essentially same as previous.


(1) as highlighted strictly saying it is pointer to pointer, but maybe you can "think" of it as array of pointers. Anyway more info about it here: https://stackoverflow.com/a/39096006/3963067




回答3:


If argv[1] is a pointer to char, then *argv[1] dereferences that pointer and gets you the first character of the string at argv[1], so it's the same as argv[1][0] and is printed with the "%c" format specifier.

argv[1][0] is a char itself, not a pointer, so it's not dereferensable.




回答4:


  1. This is not specific to char *.
  2. You can simplify by what is the difference between *ptr and ptr[0].
  3. There are no difference because ptr[0] is a sugar for *(ptr + 0) or *ptr because + 0 is useless.

// printf("%p\n", &argv[1]); is wrong you must cast to (void *)
printf("%p\n", (void *)&argv[1]);

Because %p specifier expect a void *, in normal case C auto promote your pointer into void * but printf() use variable argument list. There are a lot of rule about this, I let you read the doc if you want. But char * wiil not be promote to void * and like I say printf() except void * so you have a undefined behavior if you don't cast it yourself.




回答5:


The last line printf("%c\n",*argv[1]); is both dereferencing argv and accessing array index 1. In other words, this is doing argv[1][0], just like the previous line, because the array subscript access [1] has a higher precedence than the dereference operator (*).

However, if you were to parenthesize the expression in the last line to make the dereference operator be processed first, you would do this:

printf("%c\n", (*argv)[1]);

Now, when you run the program, the last line of output would be argv[0][1] instead of [1][0], i.e. the second character in the command line you use to execute the program.



来源:https://stackoverflow.com/questions/41664392/understanding-the-dereference-address-of-and-array-subscript-operators-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!