C/C++ 的指针是什么?int* ? *(int*)var? 是什么鬼???

指针就是地址,与其说指针,地址更容易理解。

指针变量的定义

一般的定义一个指针变量:数据类型* 变量名= new 数据类型();

int* i = new int(1);
Sheep* sheep = new Sheep("mmm");

一个指针变量是有类型的(这不是废话?)为什么要有类型?地址大小不都是一样的吗?一般是32位或64位啊。
但是如果指针变量没有类型的话用*运算符怎么取值?是取32位还是64位还是其他的?所以定义指针变量时声明的变量类型就是这个道理。
如果你学过了汇编,下面的例子可以帮助你理解,看例子1,这里将2020h移入一个内存空间,为什么要加word ptr? 2020h不就是2个字节吗,你再声明写入一个2字节的内存空间不是有点多余?这里看起来有点多余,但是如果有这样的汇编指令(例子2和3),他们的行为一样吗?
实际上是不一样的mov word ptr [addr],20h可以理解为mov word ptr [addr],0020h是实际上写入了2个字节的数据,例子3只写入了一个字节。再看例子4,如果不加word ptr你怎么区分例子2和例子3?(就是说你不知道你要写入多少数据)

mov word ptr [addr],2020h    ;例子1
mov word ptr [addr],20h      ;例子2
mov byte ptr [addr],20h      ;例子3
mov [addr],20h               ;例子4
mov ax,[addr]                ;例子5

可以运行、修改下面的汇编代码测试上面的说法。

DATA SEGMENT
    num dd 660F0655H
DATA ENDS

CODE SEGMENT
    ASSUME CS:CODE,DS:DATA
START:
    mov ax,data
    mov ds,ax
    lea si,num
    mov word ptr [si],2020h
    mov ah,4ch
    int 21h
CODE ENDS
    END START

指针的具体使用

代码

#include <iostream>
using namespace std;

int main()
{
    int* i = new int(1);
    int* j = new int(2);
    int k = 0;

    int l = 0x64fe10; // 或者 &j
    /**
     * l为j变量的地址,理论上**l就可以取j的值 *l取j的内存地址,再取值。
     * 实际上因为int类型不能直接取值,要转换成对应的数据类型的指针,再取值。
     * 即*(int*)(*(int*)l)
     */
    cout << "变量的内存地址" << endl;
    cout << "&i: " << &i << endl;
    cout << "&j: " << &j << endl;
    cout << "&k: " << &k << endl;
    cout << "&l: " << &l << endl
         << endl;

    cout << "变量的值" << endl;
    cout << "i: " << i << endl;
    cout << "j: " << j << endl;
    cout << "k: " << k << endl;
    cout << "l: " << l << endl
         << endl;

    cout << *i << endl;
    cout << "l的值转成\"int*\"类型后取值" << endl;
    cout << *(int*)l << "\thex: " << (int*)(*(int*)l) << endl;
    cout << "l的值指向的地址的值,再取前面的值指向的地址的值:" << *(int*)(*(int*)l) << endl
         << endl;
    return 0;
}

运行结果

变量的内存地址
&i: 0x64fe18
&j: 0x64fe10
&k: 0x64fe0c
&l: 0x64fe08

变量的值
i: 0x2632540
j: 0x2632560
k: 0
l: 6618640

1
l的值转成"int*"类型后取值
40052064        hex: 0x2632560
l的值指向的地址的值,再取前面的值指向的地址的值:2

变量的内存分布

地址的值可能有所不同
栈的内存分布

地址变量名
0x64fe18i0x662540
0x64fe10j0x662560
0x64fe0ck0
0x64fe08l0x64fe10

堆的内存分布

地址
0x6625401
0x6625602

运行结果分析

前面的&i,&j……i,j……应该都没有问题。看下面的简要介绍和上面的内存分布图应该可以很容易明白。
&变量:取变量的地址
*变量:取变量的值所指向的内存地址的值,类似于间接寻址。
下面两个汇编语句,一个是寄存器间接寻址,另一个是直接寻址。

mov ax,[si]    ;把si的值指向的地址的值放到ax中
mov ax,si      ;把si的值             放到ax中

对 *(int*)l 和 *(int*)(*(int*)l)的分析

  • *i的值是多少?
    i的值为0x662540,*i就是i的值指向的内存地址的值,也就是内存地址为0x662540的变量的值,是1。
  • 那么*l的值是多少?
    类似上面*i的解释,*l的值应该是0x662560?
    这里有个问题是*l是合法的吗,l的变量类型是int,不是一个地址,如果要取值的话又怎么知道取多大的内存?因为这里我们知道l的值和j变量的内存地址是一样的,而变量j的类型是int*所以这里我们把i转换为int*(这样就可以知道取多大的内存了),然后再取值,也就是*(int*)l,得到0x662560。
  • 那么**l的值是多少?
    和上面一样是不能直接使用*的,要使用强制类型转换。为了描述方便文本里还是不使用强制类型转换。
    *l的值是0x662560,那么**l的值也就是0x662560得内存地址得值:2。
    同样得因为取值要知道取多大得内存,这里要使用强制类型转换,实际上得表达式就是*(int*)(*(int*)l)