请看我写的如下代码:

#include&

int main()
{
int value = 1;
int* ptr = value; // *ptr = value
printf("%d
", value); //输出值 |
printf("%d
", *ptr); //输出值 |
printf("%p
", value); //输出地址 |
printf("%p
", ptr); //输出地址 |
printf("%d
", *ptr == value); //ture *ptr == value
printf("%d
", ptr == value); //true
/*

*/
return 0;
}

从输出的情况可以看出ptr是value的地址也即value,而*ptr代表value的值。即ptr == value,而*ptr == value。

可是在赋值的时候是*ptr = value,那么*ptr应该与value等价才对,可在使用时两者并不等价(见上)。这种赋值语句的写法虽然不影响我正常地使用指针编写程序,但对于我这种有强迫症的人来说这种赋值语法显得很拧巴,并且有一定的误导性。

所以从底层实现上来说这段代码是怎样被编译的呢?指针是*ptr还是ptr呢?谢谢!


嗯哼,你问到了指针这个东西,最容易迷惑人的一个地方。

int* ptr = value;

这一行是声明的语法,是规定出来的,即声明ptr是一个指针,同时ptr= value

这跟平时使用这个指针的时候,赋值 *ptr = value 不是一回事。

所以你才会有这个疑问。说穿了不值一提。

你其他理解都是对的


在题主的代码中可以看到int* ptr、value、value、*ptr、ptr、 *ptr == value)、ptr == value等写法,是不是看上去眼花缭乱、傻傻搞不清楚?其实啊,与其花费大精力给你解释什么「地址」、「指针」、「指向」等这些费解的抽象的概念,还不如用我发明的「己他」概念来解释这个问题。

  1. ptr和value就是ptr的己值
  2. *ptr就是ptr的他值
  3. value就是ptr的他值

从2和3就可以得知,*ptr就是value,都是他值;ptr就是value,都是己值,所以用我的「己他」法一句话就解释完毕,一句话你就能理解,还费啥劲儿再去解释什么地址不地址的!

关于指针的「己他」文章在我的圈子「C语言解惑课堂」从【第104篇】开始有讲,题主有兴趣的话可以在我的微信公众号「C语言编程技术分享」的主页回复「1111」加入圈子,从【第104篇】开始查看,也可以回复「1112」查看圈子所有的C语言答疑文章。


其实理解就行,这是「定义即初始化「,比如数组只有在定义时才能初始化

char a[10] = {0};而定义之后是不能这样写的a = {0};

同样引用int a= x;指针 int *p = x;都是定义即初始化的写法,

和赋值写法是不一样的(当然引用没有赋值写法)。

再反过来理解,可以使用#define或者typedef将指针类型定义成PINT

那么PINT p = x;就不难理解了,所以在读写代码的时候,将*号和类型一起来看就好理解了


在C语言和C++中,运算符 * 有以下含义

  1. 二元运算符,表示乘法。例如: x = 3 * 2;
  2. 类型说明,表示指针。 例如: char x = c; char* p = x; 这里的 * 号放在变数定义中,与其前面的类型char结合,表明 p 是一个字元指针变数。p后面的 「=」 则表示将变数 p 初始化为 字元变数 x 的地址。
  3. 一元运算符,表示解引用(dereference)。此时它只能放到已定义好的指针变数前面(不能用来定义变数)。例如: *p = e; 表示将 p 所指的那块存储区域(或者理解为p变数中保存的地址值所表示的那块存储区域)内存放的数据改写为字元 e。

注意上面「2」中,我们说 char* p = x; 是对p初始化,而不说「为p赋值」。初始化通常与变数定义相关,而赋值与变数定义无关。区分初始化和赋值有助于我们理解指针变数、C++中的构造函数及构造函数初始化列表等概念。


在C语言中,还有其它一些运算符是多义的。

: 二元运算符位与运算,或者一元运算符取地址

-: 一元运算符负号,或者二元运算符减法

++和--: 前置自增/减; 后置自增/减


运算符多义很正常。

在C++中,运算符是可以像函数一样重载的。本质上,运算符就是函数。只不过C++在重载运算符的时候,不能改变运算符的元属性,比如不能将二元运算符 变成一元运算符。最经典的运算符重载是左移位运算符 &

在 Haskell中,甚至可以发明新的运算符。比如发明一个「?+?」运算符

x ?+? y = show x ++ " + " ++ show y ++ " = " ++ show (x + y)

这样,编译运行如下代码

2 ?+? 3

得到输出:

2 + 3 = 5


根据评论中的讨论,补充关于 char* x, y; 的问题

指针变数定义时,有两种写法:(我们以 T 代表某种类型)

T* p; T *q;

不管哪种写法,*作为指针类型的标识,仅仅对与其相邻的那个变数起作用。也就是

T* p1, q1; T *p2, q2;

中仅p1和p2是T类型指针,而 q1和q2则是T类型。

C++他爹关于这个*的位置有如下说法:(C++ Style and Technique FAQ)

The choice between "int* p;" and "int *p;" is not about right and wrong, but about style and emphasis. C emphasized expressions; declarations were often considered little more than a necessary evil. C++, on the other hand, has a heavy emphasis on types.

A "typical C programmer" writes "int *p;" and explains it "*p is what is the int" emphasizing syntax, and may point to the C (and C++) declaration grammar to argue for the correctness of the style. Indeed, the * binds to the name p in the grammar.A "typical C++ programmer" writes "int* p;" and explains it "p is a pointer to an int" emphasizing type. Indeed the type of p is int*. I clearly prefer that emphasis and see it as important for using the more advanced parts of C++ well.


你可以这样想:

int *ptr=i;

现在出现了一个变数ptr,给他赋值i;

向左看,这个ptr是一个指针。什么样的指针呢?再向左看,int类型的。


推荐阅读:
相关文章