了解C语言中的取消引用、地址和数组下标运算符

xkftehaa  于 2023-01-29  发布在  其他
关注(0)|答案(5)|浏览(167)

我把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]是不同的地址?

2skhul33

2skhul331#

数组下标操作a[i]定义为*(a + i)-给定地址a,从该地址偏移i个元素(* 不是字节 *)并解引用结果。因此,给定指针p*p等价于*(p + 0)*(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] |   |
                                                  +---+

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

nom7f22z

nom7f22z2#

char *argv[]

argv是字符指针的数组(1)。所以它是普通数组,只是数组的每个元素都是一个指针。argv[0]是一个指针,argv[1],等等。
argv[0]-数组中的第一个元素。因为数组中的每个元素都是字符指针,所以它的值也是字符指针(正如我们上面提到的)。
*argv[1]-这里argv[1]是上述数组中的第二个元素,但argv[1]也是一个字符指针。应用*只是解引用该指针,您将获得argv[1]指向的字符串中的第一个字符。您应该使用%c打印它,因为这只是一个字符。
argv[1][0]已经是数组中第二个字符串的第一个字符-所以没有更多的空间来解引用。
(1)严格来说,它是指针到指针的,但也许你可以把它看作是指针数组。无论如何,这里有更多关于它的信息:https://stackoverflow.com/a/39096006/3963067

62lalag4

62lalag43#

如果argv[1]是指向char的指针,那么*argv[1]解引用该指针,并获取字符串在argv[1]处的第一个字符,因此它与argv[1][0]相同,并使用"%c"说明符打印。
argv[1][0]本身就是一个char,而不是一个指针,所以它是不可取消引用的。

izkcnapc

izkcnapc4#

1.这不是特定于char *的。
1.您可以简化 *ptr和ptr[0]之间的区别。
1.因为ptr[0]是 *(ptr + 0)或 *ptr的糖,所以没有区别,因为+ 0是无用的。

// 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 *,所以如果你不自己强制转换,你会有一个未定义的行为。

ou6hu8tu

ou6hu8tu5#

最后一行printf("%c\n",*argv[1]);既解引用argv又访问数组索引1,换句话说,这是在执行argv[1][0],就像前一行一样,因为数组下标访问[1]的优先级高于解引用操作符(*)。
但是,如果要将最后一行中的表达式括起来,以便首先处理取消引用运算符,则应执行以下操作:

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

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

相关问题