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

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

数组下标操作a[i]定义为*(a + i) – 给定地址a ,偏移该元素的元素( 不是字节 )并取消引用结果。 因此,给定指针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] | | +—+

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

 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

如果argv[1]是指向char的指针,则*argv[1]取消引用该指针并获取argv[1]处字符串的第一个字符,因此它与argv[1][0]并打印使用"%c"格式说明符。

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

  1. 这不是char *特有的。
  2. 您可以简化* ptr和ptr [0]之间的区别。
  3. 没有区别,因为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 auto会将指针提升为void *printf()使用变量参数列表。 关于这个有很多规则,如果你愿意,我让你阅读文档 。 但是char * wiil不会被提升为void *并且像我说的printf()除了void *所以你有一个未定义的行为,如果你不自己施展它。

最后一行printf("%c\n",*argv[1]); 是取消引用argv和访问数组索引1 。 换句话说,就像前一行一样,这是做argv[1][0] ,因为数组下标access [1]的优先级高于解除引用运算符( * )。

但是,如果要在最后一行中括起表达式以使取消引用运算符首先被处理,则执行以下操作:

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

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