理解C中的dereference,address-of和array下标运算符

时间:2017-01-15 17:57:12

标签: c pointers c-strings argv char-pointer

我将argv []定义为char *。使用以下printf语句:

     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]);  //  

这是我不明白的最后一个。打印*argv[1]是什么意思?为什么与*argv[1][0]不一样,你怎么能打印printf("%s\n",*argv[1]);。另外,为什么&*argv[1]的地址与&argv[1]不同?

5 个答案:

答案 0 :(得分:4)

char *argv[]

argv是char指针的数组(1)。所以它是普通数组,只是数组的每个元素都是一个指针。 argv[0]是一个指针,argv[1]等等。

argv[0] - 数组中的第一个元素。由于数组中的每个元素都是char指针,因此this的值也是一个char指针(如上所述)。

*argv[1] - 现在这里argv[1]是上面数组中的第二个元素,但argv[1]也是一个char指针。应用*只是取消引用指针,然后获得argv[1]指向的字符串中的第一个字符。 您应该使用%c进行打印,因为这只是一个角色。

argv[1][0]已经是数组中第二个字符串的第一个字符 - 因此没有更多空间可以解除引用。这与之前的基本相同。

(1)严格地说它是指向指针的指针,但也许你可以"思考"它作为指针数组。无论如何,有关它的更多信息:https://stackoverflow.com/a/39096006/3963067

答案 1 :(得分:3)

如果argv[1]是指向char的指针,那么*argv[1]会取消引用该指针,并在argv[1]处获取字符串的第一个字符,因此它就是{\ n}}与argv[1][0]相同,并使用"%c"格式说明符打印。

argv[1][0]本身就是一个char,而不是一个指针,所以它不是可以解释的。

答案 2 :(得分:3)

数组下标操作a[i]定义为*(a + i) - 给定地址a,偏移i元素(不是字节)解决和取消引用结果。因此,给定指针p*p相当于*(p + 0),相当于p[0]

argv的类型为char **;鉴于此,以下所有情况均属实:

    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

由于argv[i][j]的类型为char*argv[i][j]不是有效的表达式。

这是argv序列的错误可视化:

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

这可能有助于解释不同表达方式的结果。

答案 3 :(得分:2)

最后一行printf("%c\n",*argv[1]);既解除引用argv又访问数组索引1。换句话说,这就像前一行一样argv[1][0],因为数组下标访问[1]比去引用运算符(*)有higher precedence

但是,如果您要在最后一行中括起表达式以使dereference运算符首先被处理,那么您将执行此操作:

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

现在,当您运行程序时,最后一行输出将是argv[0][1]而不是[1][0],即您用于执行程序的命令行中的第二个字符。

答案 4 :(得分:2)

  1. 这不是char *
  2. 特有的
  3. 您可以简化* ptr和ptr [0]之间的区别。
  4. 没有区别,因为ptr [0]是*(ptr + 0)或* ptr的糖,因为+ 0没用。
  5. // printf("%p\n", &argv[1]); is wrong you must cast to (void *)
    printf("%p\n", (void *)&argv[1]);
    

    因为%p说明符期望void *,所以在正常情况下C自动将指针提升为void *printf()使用变量参数列表。关于这个有很多规则,如果你愿意,我让你阅读doc。但是char *不会被提升为void *,而且我会说printf()除了void *,所以如果你不自己投射,你会有一个未定义的行为。