指针变量的定义与使用
普通变量的定义与使用不存在很大的区别,定义了直接使用即可。但指针的定义与使用是需要作区分的。
int* p = nullptr; //定义时*指内存地址,或说指向的内存区域首地址
cout << *p << endl; //指针使用时*是指对p存放的地址解引用,按p的数据类型读取内存数据。
这对指针类型作解析:
(int*) 类型中的* 为内存地址类型,指向某个内存地址首地址。再加上旁边的int则约定这个内存区域存放的数据类型为Int型,按int类型读取内存4字节偏移量。
(*p),对p变量中存放的内存首地址解引用,读取内存数据。读取内存方式取决于定义时p的类型。
结构体的比较特殊,结构名为首地址,使用->符号或.号过行以首地址为基地址偏移读取内存数据,偏移量的大小取决于结构成员变量类型。
其它基础数据类型的内存模型就不画了,这里画下结构体变量的内存模型
#include <iostream>
#include <string>
#include <thread>
#include <string.h>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
struct stu{
int age;
int height;
};
int main(int argc, char** argv)
{
struct stu* ts = (struct stu*)malloc(sizeof(struct stu));
ts->age = 110;
ts->height = 180;
struct stu ts2 = {
120, 190 };
printf("The Person age:%d, height:%d \n", ts->age, ts->height);
printf("The Person2 age:%d, height:%d \n", ts2.age, ts2.height);
return 0;
}
如果使用指针定义结构,则在初始化之前需要申请结构变量空间。结构体使用结构名称来访问成员变量,解引用使用符号->,如果是直接生成结构体对象,则使用.(dot)来访问成员。使用->相当于是在结构体首地址时进行偏移,偏移大小为成员数据类型所点内存大小。
指针与二级指针
指针变量只是一个正常的变量,只是内存放的数据值为其它内存址首地址。二级指针变量,也只是一个正常的变量,只是内存里存放的是指针的指针变量即(int**)类型。
int main(int argc, char** argv)
{
struct stu t = {
120, 190 };
struct stu* tp = &t;
tp->age = 110;
tp->height = 180;
struct stu** tpp = &tp; //对变量使用取地址符&,相当于变量增加一个*地址符
printf("The stu structure addr:%p\n", *tpp);
printf("The stu first member age addr:%p \n", &t.age);
printf("The Person age:%d\n", (*tpp)->age);
return 0;
}
运行结果:
The stu structure addr:0x7ffd72db4630 //结构体首地址
The stu first member age addr:0x7ffd72db4630 //结构体第一个成员变量地址与结构体首地址相同。
The Person age:110
对p1进行解引用一次p1则, p1变量的类型由(int** )变成 (int)类型,但还是指针类型。再进行一次解引用则是按struct stu类型读取内存数据。
指针的解引用,引用时碰到什么类型就按什么类型数据读取内存,一层层的从右向左剥(((struct stu)struct stu*)struct stu**)。
二级指针直接这样使用没什么效果,一般是在申请内存或二维数组中使用到二级指针,用来方便对数据遍历访问。