理解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
本身,而不是一个指针,所以它不是可以解释的。
- 这不是
char *
特有的。 - 您可以简化* ptr和ptr [0]之间的区别。
- 没有区别,因为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]
,即命令行中用于执行程序的第二个字符。