https://i.stack.imgur.com/7Fgkp.jpg输出)这是输出图像的链接
my code ---->
#include <stdio.h>
const int MAX = 5;
int main () {
char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali",
"Zara Ali"
};
int i = 0;
for ( i = 0; i < MAX; i++) {
printf("Value of *names[%d] = %c charn", i, *names[i] );
}
for ( i = 0; i < MAX; i++) {
printf("Value of *(names+%d) = %dn", i, *(names+i) );
}
for ( i = 0; i < MAX; i++) {
printf("Value of names[%d] = %dn", i, names[i] );
}
for ( i = 0; i < MAX; i++) {
printf("Value of *(names+%d) = %sn", i, *(names+i) );
}
for ( i = 0; i < MAX; i++) {
printf("Value of names[%d] = %sn", i, names[i] );
}
printf("Value of names = %dn",names );
printf("Value of names+1 = %dn",names+1 );
return 0;
}
时,names
和names[0]
的值不相同。我在哪里可以正确地学习这个主题。问题是"我不知道……"哪个变量存储了哪个地址或值
首先,下面一行是错误的:
printf("Value of names = %dn",names );
使用%d
格式说明符不是打印指针的正确方式。虽然它可以在大多数32位平台上工作(指针的大小通常为4
),但它肯定不能在64位平台上正常工作(指针的大小通常为8
)。
打印指针的正确方法是使用%p
格式说明符并将指针强制转换为void*
:
printf( "Value of names = %pn", (void*)names );
在大多数平台上,没有必要强制转换为void*
,因此您可以安全地忽略它(即使ISO C正式要求强制转换)。
正如在评论部分已经指出的那样,根据定义,编写names[i]
等同于编写*(names+i)
。
names
和names+1
之间的差异是8
的原因是因为在两个表达式中,数组names
衰减为指向其第一个元素的指针,即指向&names[0]
。给一个指针增加1
不会使地址增加1
,而是使它指向下一个元素。由于数组names
的每个元素都是一个指针,并且在您的平台上似乎具有8
的大小(您似乎在具有64位指针的64位平台上),因此当您将指针增加1
时,地址将增加8
。
在你的图片中,你似乎也在问为什么*(names+0)
和*(names+1)
之间的差异是9
。表达式*(names+0)
相当于names[0]
,后者是指向字符串字面值"Zara Ali"
的指针。表达式*(names+1)
等价于names[1]
,后者是指向字符串字面值"Hina Ali"
的指针。所以这两个表达式都表示字符串字面量的地址,即编译器存储某个字符串字面量的地址。编译器存储字符串字面量的位置由编译器决定,编译器的行为可能不同。然而,在这种情况下,编译器似乎决定在内存中相邻地存储两个字符串字面值。字符串字面值"Zara Ali"
的长度为9
(包括空终止字符),因此这就解释了为什么地址的差异是9
。
图片会有帮助:
char * char
+–––+ +–––+
| | names[0] ––––> |'Z'| names[0][0]
+–––+ +–––+
| | names[1] ––+ |'a'| names[0][1]
+–––+ | +–––+
... | ...
| +–––+
| |'i'| names[0][7]
| +–––+
| | 0 | names[0][8]
| +–––+
|
| +–––+
+-> |'H'| names[1][0]
+–––+
|'i'| names[1][1]
+–––+
...
+–––+
|'i'| names[1][7]
+–––+
| 0 | names[1][8]
+———+
每个字符串字面值("Zara Ali"
,"Hina Ali"
等)存储在内存中的某个地方,作为char
的零终止数组(字符串字面值的存储方式是在程序的整个生命周期内都可用)。
每个names[i]
存储每个字符串字面值的第一个字符的地址。
表达式names
的类型为"指向指向char
的指针";(char **
)1并求值为names
数组第一个元素的地址——相当于写&names[0]
。表达式names[0]
求值为"Zara Ali"
字符串字面量中第一个字符的地址——这与写&names[0][0]
是一样的。
使用%p
转换说明符来打印指针值而不是%d
-%d
期望其对应的参数类型为int
,并且指针不是整数:
printf( "Value of names[%d] = %pn", i, (void *) names[i] );
printf( "Value of names = %pn", (void *) names );
printf( "Value of names+1 = %pn", (void *) (names + 1) );
在c中,这几乎是唯一需要显式转换指向void *
的指针的时候。
- 除非它是
sizeof
或单元&
操作符的操作数,或者它是用于在声明中初始化字符类型数组的字符串字面值,否则类型为"T
的n元素数组"的表达式将被转换或"衰减"为类型为"指向T
的指针"的表达式,该表达式的值将是数组的第一个元素的地址。
变量names
被声明为指向char
(char *[]
)的指针数组。但是,当names
出现在表达式中,并且它不是sizeof
或一元&
的操作数时,它被转换为"指向char
(char **
)的指针"类型。
这就是为什么names
是char *
的数组——每个字符串字量本身就是一个数组表达式("char
的9元素数组"),但在这种情况下"衰减"为类型char *