(超级详细)一文看懂指针、地址、引用

(超级详细)一文看懂指针、地址、引用超级详细 一文看懂指针 地址 引用

内存地址

首地址

如果计算机分配的一块内存是连续的,那么第一个元素的内存空间地址就称为首地址

如数组、函数体,的存储方式为连续存储
例如:数组首地址加上一段地址的变化就能得到相应元素的地址,进而取得数组任意元素的值;
所以我们可以直接用首地址+地址增量来表示这一段内存的全部地址




例如:一栋楼一共有100户,我家在一单元一楼,门牌号为0x01001(假设从一开始);
你家在6楼,咱们中间一共有4个楼层(0x01002,0x01003,0x01004,0x01005),
那么你家的门牌号就为0x01006,依次类推第100楼的门牌号就为0x01100;
通过我家的门牌号跟楼层数就能得到所有楼层的门牌号;






指针的定义:

指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(Pointed to)存在电脑存储器中另一个地方的值。

简单的说:指针是一个变量,且这个变量是专门用来存放地址的。

举个栗子:你想给你朋友打电话,你朋友的电话号为,(你记不住)你拿一个小本本记下来,这个小本本就是指针变量,里面记的东西就是电话号,也就是地址,以后你想找你朋友都可以通过小本本里的电话号联系到。

1、指针变量

普通用法
既然叫做变量里面存储的肯定是常量,这个常量就是—–地址;
指针变量的定义形式为:




int * p ;//表示声明了一个能指向int类型内存空间的指针 

其中p为一个指针变量,里面可以存int类型普通变量的地址;

int a = 10;//定义一个int类型的变量,变量的值为10; 

a为一个普通变量,值为10;

p = &a;//表示p存了变量a的地址,这时候的p指向的就是a的内存空间; 

这时候想要取a的值就有两种情况:
第一种:直接输出变量;

cout << a << endl; 

第二种:通过指针取值;

cout << *p << endl; 

其中*号在此时作为取值符

特殊用法
用指针定义数组:

int *d; 
 int *d; int b[10];//假设分配10个内存空间 d = b; 
int *Arr = (int*)malloc(sizeof(int));//int类型的动态数组 

直观一点,直接上代码

#include  
     using namespace std; void main() { 
    int *c; int a = 10; char m = 'a'; char* p; p = &m; c = &a; int *d; int b[10]; b[0] = 11; b[1] = 12; d = b; int *Arr = (int*)malloc(sizeof(int));//动态数组 Arr[0] = 30; Arr[1] = 31; //由于< 
   <操作符重载,遇到字符型指针默认当作字符串,所以需要强制转换< span="">
     cout 
    << 
    "p: " 
    << 
    static_cast 
    < 
    void 
    * 
    > 
    (p 
    ) 
    << endl 
    ; 
    //输出16进制地址(m的地址) cout 
    << 
    "c: " 
    << c 
    << endl 
    ; 
    //输出16进制地址(a的地址) cout 
    << 
    "*c: " 
    << 
    *c 
    << endl 
    ; 
    //输出a的值:10 cout 
    << 
    "a: " 
    << a 
    << endl 
    ; 
    //输出a的值:10 cout 
    << 
    "b[0]: " 
    << b 
    [ 
    0 
    ] 
    << endl 
    ; 
    //输出b[0]的值:11 cout 
    << 
    "&b[0]: " 
    << 
    &b 
    [ 
    0 
    ] 
    << endl 
    ; 
    //输出16进制地址(b[0]的地址) cout 
    << 
    "d: " 
    << d 
    << endl 
    ; 
    //输出16进制地址(b[0]的地址) cout 
    << 
    "d[1]: " 
    << d 
    [ 
    1 
    ] 
    << endl 
    ; 
    //输出b[1]的值:12 cout 
    << 
    "Arr: " 
    << Arr 
    << endl 
    ; 
    //输出Arr[0]的地址 cout 
    << 
    "Arr[1]: " 
    << Arr 
    [ 
    1 
    ] 
    << endl 
    ; 
    //输出Arr[1]的值:31 
    } 
   

总结:
1、指针变量是一种变量(有内存也有地址),里面存的是地址。
2、地址指向的是空间,所以指针指向内存空间。(所以经常说某个指针指向某一块内存)
3、指针变量存的地址可以是连续内存里的首地址(可以用作数组)






2、 数组指针

int (*p)[10]; 

其中括号()的优先级最高,所以说这里的整个*p为一个指针变量的定义,p为指针,指向的是一个数组(匿名数组),数组里面存的是int类型的元素;(规定了数组的大小)

总结:数组指针是数组样子的指针;
(下面上代码)
例子:




#include  
     using namespace std; void main() { 
    int arr[10]; arr[0] = 10; arr[1] = 11; arr[2] = 12; int(*p)[10] = &arr;//赋值的是地址,所以是指针 p[0][0] = 0; p[0][1] = 1; p[0][2] = 2; //数组指针 cout << "p[0][0]:" << p[0][0] << endl; //输出为0;输出第一个指针p[0]指向连续存储空间的的第一个元素 cout << "p[0][1]:" << p[0][1] << endl; //输出为1;输出第一个指针p[0]指向连续存储空间的的第二个元素 cout << "p[0][2]:" << p[0][2] << endl; //输出为2;输出第一个指针p[0]指向连续存储空间的的第三个元素 cout << "p[0]:" << p[0] << endl;//输出为第一个指针中存的地址,也就是arr的地址 cout << "p[1]:" << p[1] << endl;//输出为第二个指针中存的地址,未赋值, cout << "p[2]:" << p[2] << endl;//输出为第三个指针中存的地址,未赋值 cout << "p[3]:" << p[3] << endl;//输出为第四个指针中存的地址,未赋值 cout << "*p[0]:" << *p[0] << endl; //输出为输出为0;第一个指针p[0]指向连续存储空间的的第一个元素 cout << "*p[1]:" << *p[1] << endl; //输出为输出为(-)无穷;第二个指针p[1]指向连续存储空间的的第一个元素 cout << "arr[0]:" << arr[0] << endl; //输出arr[0]的值 cout << "&arr[0]:" << &arr[0] << endl; //输出arr[0]的地址,也就是arr的地址 cout << "arr[1]:" << arr[1] << endl; //输出arr[1]的值 cout << "&arr[1]:" << &arr[1] << endl; //输出arr[1]的地址 } 

在这里插入图片描述

3、 指针数组

int *p[10]; 
int **p; 

与二级指针的区别在于预先定义的指针数组的一维大小;

解释一下,p为数组的名字,申请了10个空间,每个空间里面存的是int *(指向存放int类型空间的指针),所以说p[0]里面存的是指针,与上面数组指针不同的是,数组指针是申请的空间本身就是指针(只不过名字看起来像数组),这里申请的是数组,但是里面存的是指针。

总结:指针数组实际上就是内存空间里面存的是指针的数组;

#include  
     using namespace std; void main() { 
    int arr[10]; arr[0] = 10; arr[1] = 11; arr[2] = 12; int*p[10] = { 
   arr}; //首先赋值方式不一样就能体现是指针还是数组,这是数组的一般赋值方式; p[0][0] = 0; p[0][1] = 1; p[0][2] = 2; //指针数组 cout << "p[0]:" << p[0] << endl;//指针的值(也就是arr的首地址),输出为16位16进制的地址 cout << "p[1]:" << p[1] << endl;//输出为16位16进制的0; cout << "&p[0]:" << &p[0] << endl;//输出为p[0]这个存储空间的地址 cout << "&p[1]:" << &p[1] << endl;//输出为p[1]这个存储空间的地址 cout << "*p[0]:" << *p[0] << endl; //输出为p[1]这个存储空间存的值指向空间的值(有点yao口) //p[0]是指针的值,里面最终存的是地址 //这么一来跟指针变量的用法一样,*号可以取相应地址的值 cout << "p[0][0]:" << p[0][0] << endl; //输出arr[0]的值 cout << "p[0][1]:" << p[0][1] << endl; //输出arr[1]的值 cout << "&p[0][0]:" << &p[0][0] << endl; //实际上就是arr[0]的地址也就是arr首地址 cout << "&p[0][1]:" << &p[0][1] << endl; //实际上就是arr[1]的地址 cout << "arr[0]:" << arr[0] << endl; //输出arr[0]的值 cout << "&arr[0]:" << &arr[0] << endl; //输出arr[0]的地址,也就是arr的地址 cout << "arr[1]:" << arr[1] << endl; //输出arr[1]的值 cout << "&arr[1]:" << &arr[1] << endl; //输出arr[1]的地址 } 

在这里插入图片描述

4、函数指针

int (*fun)(int x,int y); 

表示的是这个fun指针可以指向类型为返回值为int类型,参数为int x,int y的函数的那一段内存空间

例如两个函数声明为:

int func(int x, int y); int fun0000(int x); 

定义为:

int func(int x, int y) { 
    return 0; } int fun0000(int x) { 
    return 0; } 

函数指针的定义为:

int(*fun)(int x, int y); 

调用类型为:

fun = &func; 

5、指针函数

int func(); 
int* func(); 

6、特殊指针

①空指针

定义为:

// Define NULL pointer value  #ifndef NULL  # ifdef __cplusplus  # define NULL 0  # else  # define NULL ((void *)0)  # endif  #endif // NULL  
short *pa=NULL;//pa保存0地址,pa保存空指针 
short *pa = 0; 

②Void类型指针

无类型指针,这个就厉害了,在定义上是无类型指针,但是实际上用起来却包罗万象
通过强制类型转换可以变为所有类型的指针;
例如可以将上文函数指针赋值给它:




int function(int x, int y) { 
    return 0; } 
 int(*fun)(int x, int y); fun = &function; void * p_void; p_void = fun; 

可以将函数地址赋值给它:

 int(*fun)(int x, int y); fun = &func; void * p_void; p_void = &function; 

甚至可以将函数指针的地址赋值给它:

 int(*fun)(int x, int y); fun = &func; void * p_void; p_void = &fun; 

这就是无中生有,道法自然 ?????

③nullptr指针

nullptr是C++11 新标准引入的方法,在之前使用的是NULL,NULL是一个预处理变量,它的值为0。

int *p1 = nullptr; // 等价于int *p1 = 0 int *p2 = 0; // 直接将p2初始化为字面常量0 int *p3 = NULL // 等价于int *p3 = 0 

④结构体指针(类指针)

class Point { 
    int x; int y }; struct Student { 
    char* name; char* sex; int number; int age; }; 

定义结构体指针为:

Point *pt; Student *stu; 

使用为:

pt->x = 100; pt->y = 100; stu->name = "卡尔曼确实慢"; stu->sex = "未知"; stu->number = 1; stu->age = 23; 

⑤this指针

引用

一句话,引用相当于是别名,指的是同一个东西。
引用常用于函数中的参数传递。

例子

 int a = 1; int b = 1; int &x = a; x = 20; cout << a << endl; 

结果为20;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/220098.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午9:15
下一篇 2026年3月17日 下午9:15


相关推荐

  • 多模态情感识别_多模态融合的情感识别研究「建议收藏」

    多模态情感识别_多模态融合的情感识别研究「建议收藏」摘要:情感是人们在沟通交流的过程中传递的重要信息,情感状态的变化影响着人们的感知和决策。情感识别是模式识别的重要研究领域,它将情感维度引入人机交互。情感表达的模态包括面部表情、语音、姿势、生理信号、文字等,情感识别本质上是一个多模态融合的问题。提出一种多模态融合的情感识别算法,从面部图像序列和语音信号中提取表情和语音特征,基于隐马尔可夫模型和多层感知器设计融合表情和语音模态的情感分类器。建立面部…

    2022年6月21日
    36
  • socketpair原理_socket负载均衡

    socketpair原理_socket负载均衡描述先看下传统的CS模型,如下:总是一方发起请求,等待另一方回应。当一次传输完成之后,client端发起新的请求之后,server端才作出回应。那如何才能做到双向通信? 一种解决办法就是client端即使client,又是server,server端即使client也是server,如下:但是上述方面比较复杂,这时候就引入要分析的socketpair了。

    2022年10月14日
    5
  • linux系统静态路由配置,详解linux静态路由配置

    linux系统静态路由配置,详解linux静态路由配置学习 linux 时 你可能会遇到配置静态路由的问题 这里将介绍配置 linux 静态路由问题的解决方法 在这里拿出来和大家分享一下 现在有五个设备 PC1 接 ROUT1 ROUT1 再接 ROUT2 ROUT2 再接 ROUT3 ROUT3 再接 PC2 拓扑图见下 PC1ROUT1ROUT 五个设备的 linux 静态路由 IP 地址分别为 PC1192

    2026年3月18日
    1
  • 奇异矩阵与非奇异矩阵的定义与区别

    奇异矩阵与非奇异矩阵的定义与区别讨论非奇异矩阵与奇异矩阵的前提 该矩阵 A 为方阵 即 n m 行列数相等非方阵矩阵谈不上奇异与非奇异 奇异矩阵判别方法 判断矩阵 A 行列式是否为 0 若行列式 A 0 则矩阵 A 为奇异矩阵 一个矩阵 A 方阵 半正定 且它的每个特征值大于或等于 0 则 A 为奇异矩阵 一个矩阵 A 方阵 正定 且它的每个特征值都大于 0 为奇异矩阵 一个方阵非奇异当且仅当它代表的线性变换是个自同构 为奇异矩阵 非奇异矩阵判别方法 判断 若矩阵 A 方阵 行列式 A 0 则矩阵 A 为非奇异矩阵 若矩阵 A 方阵 的秩 R A

    2026年3月17日
    3
  • Json的FastJson与Jackson

    Json的FastJson与JacksonJson的FastJson与Jackson

    2022年4月22日
    53
  • admixture 报错 Size of G: 324×13928 Segmentation fault (core dumped)

    admixture 报错 Size of G: 324×13928 Segmentation fault (core dumped)admixture 运行示例数据报错 dengfei DESKTOP PJ6RTVA admixture linux 1 3 0 admixturehap bed3ADMIXTUR 3 0Copyright20

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号