问题是:
char c = 'a';
char *p = &c;
和
char c = 'a';
char *p;
*p = &c;
执行的结果非常不同(第一个是预期的,第二个是编译错误)。我刚开始写"指针",所以请耐心点。
声明一个变量和赋值一个已存在的变量时,*有不同的含义。
声明变量时*表示变量p是指向char类型的指针,而不仅仅是指向char类型的指针。
另一方面,在对现有变量赋值时,*将取消对指针的引用。也就是说,赋值不是操作指针本身,而是操作指针
所指向的位置。所以你的第二个例子是双重破碎
首先对未初始化的指针进行解引用。其次,当它尝试赋值时,它有一个类型不匹配。
正如评论所指出的,如果您认为在C中声明是type
,然后是names
列表,则会有所帮助。
char c = 'a';
c
为名称,char
为类型。
当你声明
char *p = &c;
有点奇怪,容易引起混淆。星号在C中根据位置的不同有不同的含义:
- 是乘法的运算符。
- 它也是解引用操作符,也被称为间接操作符,好像它还不够混淆似的。
- 在声明中表示一个指针。
我们不能责怪C语言,因为它是为系统编程而设计的,而不是为教学而设计的,而Pascal是多年后为教学而设计的。
回到问题,在
一行char *p = &c;
p
是名称,类型是char*
,编译器有时会在错误消息中告诉你。
实际上编译器看到的是
char* p = &c;
p
是指向char
的指针。
但是你在*p
中看到了什么?*p
表示p
所指向的内容。
Spaceship* p = &some_ship; // *p is Spaceship
int* p = NULL; // *p is an int
char**** p = some_stuff; // *p is char***
从这个意义上讲,当您学习指针时,请记住操作符&
的地址与操作符*
间接操作符之间的关系,因为它们表示逆操作。并保持*
靠近声明中的类型。
如果pc
是char****
则
*pc
ischar***
**pc
是char**
***pc
是char*
****pc
是声明中单独的char
。&pc
是指向char
的指针的指针的指针的地址。
通过写char *p
而不是char* p
,暴露了这种C特性:如果p
是char*
,那么*p
是char
。如果你把星号放在离字体很远的地方,放在名字旁边,你可能会读错……
看到
#include <stdio.h>
int main(void)
{
char c = 'a';
char* p = &c;
printf("c is '%c' at %p, sizeof(c) is %lun", c, &c, sizeof(c) );
printf("p is char* at %p, sizeof(p) is %lun", p, sizeof(p) );
printf("and in that address we have *p = '%c'n", *p );
return 0;
}
显示
so> gcc -o tst -Wall f30.c
so> ./tst
c is 'a' at 0x7fffdfa36d3f, sizeof(c) is 1
p is char* at 0x7fffdfa36d3f, sizeof(p) is 8
and in that address we have *p = 'a'
so>
char *p = &c;
是指向变量c地址的指针p的初始化,而
*p = &c;
是一种赋值操作,其中指针p被忽略,c的地址被写入p指定的内存地址。对于你的代码,这取决于上下文,可以是地址0(如果p是一个零指针)或一些随机地址在大多数情况下(因为p没有初始化)。
代码的第一部分是正确的,但第二部分不是,因为您试图将值分配给具有不同类型的变量。
也就是说,*p
和&c
是两种不同类型的变量。为了纠正它,你需要写:
p = &c;
C允许初始化,即同时声明和赋值。对于指针,*
是否包含很重要:
char *p = &c;
^^^^^^^
| ^^^^^^
| |
decl. |
ass.
只有p
重叠。被赋值的是p
,而不是*p
。两行:
char *p;
p = &c
p
是地址/指针。但是只要使用*p
(或p[0]
或p[…]),它就会变成一个字符。在上面的初始化中,指针的两边几乎是重叠的。
第一个被解析为
(char *) p = & c;
。,类型为char *的变量p,用c的地址初始化。
后者
*p = &c;
解析为"取变量p,对其指向的内容进行解引用,并将其赋值为c的地址"。这是失败的,因为p指向的是一个char,而不是char*。