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
变量的内存分布
地址的值可能有所不同
栈的内存分布
地址 | 变量名 | 值 |
---|---|---|
0x64fe18 | i | 0x662540 |
0x64fe10 | j | 0x662560 |
0x64fe0c | k | 0 |
0x64fe08 | l | 0x64fe10 |
堆的内存分布
地址 | 值 |
---|---|
0x662540 | 1 |
0x662560 | 2 |
运行结果分析
前面的&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)