C/C++指针入门详解(一)

news2025/2/25 9:42:55

一、引言

指针是一个地址,这个地址不仅可以是变量的地址,也可以是其它数据结构的地址。为了方便调用这个地址,C/C++是通过指针变量来使用这个地址的。而我们常说的指针,其实在一定程度上说的是指针变量,但是我们必须清楚认识到指针和指针变量是有着严格的不同的,是两个完全不同的概念。
在C/C++语言中, 数组、数据结构和函数往往都占有一组连续的内存单元,通过访问指针变量取得了数组或函数的首地址,也就找到了该数组或函数。 但是用“地址”这个概念并不能很好地描述一种数据类型或数据结构, 而“指针”虽然实际上也是一个地址,但它却是一个数据结构的首地址,它是“指向”一个数据结构的,因而表示更为明确。这也是引入“指针”概念的一个重要原因。
如下图所示,有两个变量a和b,其在内存中的地址分别是0x1000和0x10040,这两个地址就是指针。
在这里插入图片描述
如果想通过地址来访问变量a或者b,可以提高程序的运行速度,而为了方便使用这些内存地址,在C/C++中就引入了指针变量的概念,用指针变量存储a和b等这些变量的地址。例如用指针变量p存储变量a的地址,用指针变量q存储变量b的地址,则得到如下的图。
在这里插入图片描述
如果想通过直接访问内存地址的方式获取变量a的值,就可以使用*p的方式来获取。如果变量a是一个数组,则p就是指向数组a首地址的指针变量,也就是指针变量的值是数组a的首地址。

二、指针的特点

1.指针是C/C++语言中广泛使用的一种数据类型。
2.运用指针编程是C/C++语言最主要的风格之一。
3.利用指针变量可以表示各种数据结构;
4.能很方便地使用数组和字符串;
5.能象汇编语言一样处理内存地址,从而编出精练而高效的程序。

因此,指针极大地丰富了C/C++语言的功能。学习指针是学习C/C++语言中最重要的一环, 能否正确理解和使用指针是我们是否掌握C/C++语言的一个重要标志。

三、引入指针的优势

1.提高程序的编译效率和执行速度
C/C++中的变量和数据都是存储在计算机内存中,而访问数据都是通过变量来实现。每个变量都是存储在内存中固定的位置,且拥有唯一的地址。通过变量获取数据,需要先转换到内存地址,再提取数据。C/C++增加了一种可以直接访问内存地址中数据的方法——指针,这样使得程序运行效率更高。
2.数组动态化
即动态数组,也就是可以根据实际需要为数组动态的分配存储空间。
例如:数组求和问题。每一次参与求和运算的元素个数不相同,如果使用静态数组来实现,则数组的长度不好定,如果给的太大,可能会浪费空间,如果太小又无法存储全部的元素。为了方便实现该运算就可以根据每一次参与运算的元素个数动态分配存储空间。
3.函数参数的双向传值
对于函数的参数,如果是普通的变量,则只能是由“实参”传递给“形参”,反之不可以。但是指针可以实现参数的双向传递功能,也就是通过指针可使主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯。
4.快捷交换两个数组的元素
对于静态数组,想交换一下这两个数组的内容,只能逐个元素交换。但是指针却是可以实现直接交换两个数组的内容。就像2位老师分别给两个班级讲授不同的课程,如果下一节课两个班级的课对调,那么是老师不动而学生换教室呢,还是学生不动老师换教室?哪个操作更简单?答案是很显然的,即老师换教室而学生不换教室。班级的学生如果看做是数组的话,而任课老师是数组名,这里就相当于交换了两个数组名。但是静态数组是不允许这样操作的,而引入指针后就可以轻松实现此功能。因为此时老师就是指针变量,而班级就是指针变量对应存储空间里的数据。
5.在类的组合中指针发挥了重要作用
如果有两个类,如下:

class A;
class B
{
private:
	A *p1, *p2;
	......
};

此时类A作为类B的前导声明,而在类B中又定义了A的对象,则A的对象必须使用指针,即指针对象。

四、指针变量的定义

1.指针和指针变量的含义
指针:地址
指针变量:存放变量地址的变量。作用是用来指向另外一个变量。并且指针变量在使用前必须初始化。
2.指针变量的定义

    类型说明符  *指针变量名;

其中,* 表示这是一个指针变量,类型说明符表示该指针变量所指向的变量的数据类型。
例如:

int *pr;

表示p是一个整型的指针变量,它的值是某个整型变量的地址,或者说p指向一个整型变量。

char *q;

表示q是一个字符型的指针变量,指向了存储字符型变量的首地址。
需要说明的是,由于在 C/C++语言中,地址本身是整型数据,因此对上述的指针变量p和q而已,他们本身也是变量,但因为存储的是地址,因此p和q在内存中所占用的存储空间大小和存储整型数据的空间大小相同。这可以利用sizeof函数来测试。例如在DEV-C++环境下,sizeof(q)和sizeof§的值均是4,即存储变量p和q的存储空间的长度均是4个字节。
3.指针变量的运算
两个有关的运算符分别是 & 和 *,

& :取地址运算符
    *  :指针运算符(或称”间接访问”运算符), 其结合性为自右至左 。
  • 运算符之后跟的变量必须是指针变量。
    需要注意的是指针运算符 * 和指针变量说明中的指针说明符 * 不是一回事。在指针变量说明中,* 是类型说明符,表示其后的变量是指针类型。而表达式中出现的 * 则是一个运算符用以表示指针变量所指的变量。
    4.指针变量之间的运算
    1)指针变量自身的算术运算
    假设p是一个指针变量,且指向一个数组a,则:
    a)p++表示指针偏移一个存储单元,即指向下一个元素的地址。一个存储单元即是数组一个元素所占的字节数,和数组的类型有关。
    b)p++相当于(p++),即先使用p,然后执行p = p + 1。
    c)p+i则表示指针偏移i个存储单元。
    d)
    (p+i)或p[i]表示的是数组元素a[i]。
    e)(p)++是先取出p,然后让*p加1。
    2)指针变量之间的算术运算
    两个指针变量只能做减法运算!!!
    两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。实际上是两个指针值(地址) 相减之差再除以该数组一个元素的存储空间长度。
    例如p和q是指向同一浮点数组的两个指针变量,设p的值为0x2010,q的值为0x2000,而浮点数组每个元素占4个字节,所以p-q的结果为(0x2010 - 0x2000)/4=4,表示p和q之间相差4个元素。
    3)指针变量之间的关系运算
    两指针变量可以进行关系运算。如果p和q是指向同一数组的两指针变量,则可以进行如下关系运算:
    p == q 表示p和q指向同一数组元素,通常用于数据的缓存。
    p > q 表示p处于高地址位置
    p < q 表示p处于低地址位置

五、指针的相关应用范例

指针的在实际软件开发中应用非常普遍,这样应了那句“不会指针就没有真正掌握C/C++”,当然这话说的有点绝对,其实即使会了指针,也未必精通C/C++,因为单纯的学习编程语言容易,但是要熟练应用,你又会发现设计算法是最难的。
1.直接访问内存
需要说明的是,使用指针变量就是直接访问内存地址。此处仅仅用一个简单的例子演示说明而已。
例1:利用指针指向存储某个变量的地址,然后利用指针直接读取内存中的数据。

#include "stdio.h"
int main()
{
	int a = 100;
	int *p;
	p = &a;	//指针变量p指向变量a的首地址。
	printf("*p = %d\n", *p);//输出*p的值,即p指向内存地址中的变量 
	return 0; 
}

运行结果:
在这里插入图片描述
2.动态数组
例2:从键盘读入一个整数表示动态数组元素的个数,之后依次读入数组的元素,并向屏幕输出数组。

#include"stdio.h"
#include"malloc.h"
int main()
{
	int i, num;
	int *p;
	printf( "Input array's length:" );
	scanf( "%d", &num );
	//为指针变量p(动态数组)分配存储空间,长度是num 
	p = (int *)malloc( num * sizeof(int) );
	
	//为动态数组p赋值 
	for( i = 0; i < num; i++ )
	{
		printf( "Input No. %d element: ", i );
		scanf( "%d", &p[i] ); 
	}
	//输出动态数组p中的元素 
	for( i = 0; i < num; i++ )
	{
		printf( "Output No. %d element: %d\n", i, p[i] );
	}  
	/*下面代码演示了指针的其它操作 
	//上述操作也可以用下面代码实现。
	//但是存在个问题就是容易“丢失”数组的首地址,为了避免此问题,可以再引入一个指针缓存p 
	int *q; 
	q = p;
	//为动态数组p赋值 
	for( i = 0; i < num; i++ )
	{
		printf( "Input No. %d element: ", i );
		scanf( "%d", p++ );//指针变量p连续向后移动一个存储单元 
	}
	//输出动态数组p中的元素 
	for( i = 0; i <num; i++ )
	{
		printf( "Output No. %d element: %d\n", i, *(q+i) );//*(q+i)表示动态数组p中的第i个元素 
	} 
	*/
	return 0; 
}

运行结果:
在这里插入图片描述
3.函数参数的双向传值
例3:利用函数实现对一组整数进行逆序。

#include"stdio.h"
#define N 5 
void InverseArr( int *p, int n );
int main()
{
	int i, arr[N]={ 1, 2, 3, 4, 5 };
	int *p = arr;
	InverseArr( p, N );
	printf( "inverse element:" );
	for( i = 0; i < N; i++ )
	{
		printf( " %5d", *p++ );
	}
	return 0; 
}
//参数p既是输入参数,也是输出参数
void InverseArr( int *p, int n ) 
{
	int temp;
	for( int i = 0; i < n/2; i++ )
	{
		temp = p[i];
		p[i] = p[n-i-1];
		p[n-i-1] = temp;
	}
}

运行结果:
在这里插入图片描述
例4:利用指针实现函数参数的双向传值(C++)

#include<iostream>
using namespace std;
//交换m和n所指向地址中数据
void swap(int *m, int *n)
{
	int temp;
	temp = *m;
	*m   = *n;
	*n   = temp;
}
int main()
{
	int a = 5, b = 10;
	swap( &a,  &b );
    cout<<"swaped:"<<endl;
	cout<<"a= "<<a<<"  b= "<<b<<endl;
	return 0;
}

运行结果:
在这里插入图片描述
4.交换两个数组
例5:有两个数组,利用指针变量交换数组元素。即指针变量p和q分别指向两个数组,利用更改指针变量值的方式交换p和q指向的数组,以达到交换两个数组元素的目标。

#include"stdio.h"
#define N 5
#define M 6 
void InverseArr( int *p, int n );
int main()
{
	int i, *p, *q;
	int arr1[N]={ 1, 2, 3, 4, 5 };
	int arr2[M]={ 6, 7, 8, 9, 10, 11 };
	p = arr1;
	q = arr2;
	printf( "\n交换前—数组p的数据:" );
	for( i=0; i<N; i++ )
	{
		printf( "%5d", p[i] );
	}
	printf( "\n交换前—数组q的数据:" );
	for( i=0; i<M; i++ )
	{
		printf( "%5d", q[i] );
	}
	//交换两个数组 
	p = arr2;
	q = arr1;
	printf( "\n交换后—数组p的数据:" );
	for( i=0; i<M; i++ )
	{
		printf( "%5d", p[i] );
	}
	printf( "\n交换后—数组q的数据:" );
	for( i=0; i<N; i++ )
	{
		printf( "%5d", q[i] );
	}
	return 0; 
}

运行结果:
在这里插入图片描述
5.类的组合之前导类声明
例6:利用前导类实现计算坐标屏幕上两个点直接的距离。其中坐标点为一个类,计算点之间的距离为另外一个类。

#include<iostream>
#include<cmath>
using namespace std;
class CPoint;
class CDistance
{
private:
	CPoint *p1, *p2;
	double dist;
public:
	CDistance(CPoint *a, CPoint *b);
	double GetDist()
	{	return dist;}
};
class CPoint
{
private:
	int m_x, m_y;
public:
	CPoint(int x, int y)
	{	
		m_x = x; 
		m_y = y;
	}
	int GetX(); 
	int GetY();
};
int CPoint::GetX()
{	
	return m_x;
}
int CPoint::GetY()
{	
	return m_y;
}
CDistance::CDistance(CPoint *a, CPoint *b):p1(a), p2(b)
{
	double x, y;
	x = double(p1->GetX() - p2->GetX());
	y = double(p1->GetY() - p2->GetY());
	dist = sqrt(x*x + y*y);
}
int main()
{
	CPoint pa(1,1), pb(3,5);
	CDistance dis(&pa, &pb);
	cout<<"Distance of the two points is ";
	cout<<dis.GetDist()<<endl;
	return 0;
}

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/39687.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通用后台管理系统前端界面Ⅺ——信息列表页(弹窗复用增改、CRUD前端基础实现)

因为需求发生了点变化&#xff0c;所以把之前的代码稍改一下&#xff0c;把之前的信息列表全复制到用户列表中&#xff0c;最后效果一样。UserList.vue <template><div class"UserList"><!-- 查询、重置 --><el-form :inline"true" :…

UnityShader_基础理论

渲染流程 此处的渲染流程只是一个概念流水线。大概分为应用阶段、几何阶段、光栅化阶段。 应用阶段 主要输出渲染所需的几何信息&#xff0c;包括点、线、三角面等&#xff0c;传递给下一阶段使用&#xff1b;这一阶段主要CPU处理&#xff0c;该阶段产生的产物就是渲染图元…

【ML特征工程】第 6 章 :降维:用 PCA 压缩数据薄饼

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

Java并发-synchronized使用方法

synchronized 关键字介绍 Java 中的每个对象都可以把它当作一个同步锁来使用&#xff0c;这些 Java 内置的使用者看不到的锁被称为内部锁&#xff0c;也叫作监视器锁。代码在进入 synchronized 代码块前会自动获取内部锁&#xff0c;这时候其他线程访问该同步代码块时会被阻塞…

十七、CANdelaStudio深入-创建新工程

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio创建新工程的过程,欢迎各位朋友订阅、评论…

别卷了!今年局势不一样开始裁员濒临失业

我被优化了&#xff0c;公司劳动合同都当天解除完&#xff0c;电脑也今天全部打包完&#xff0c;非常快&#xff0c;我也是惊呆了&#xff0c;刚刚和他们部门的人吃完饭&#xff0c;感觉今天就是一场梦&#xff0c;昨天还是催着做需求&#xff0c;今天说散就散”&#xff0c;前…

论文浅尝 | Efficient RDF graph storage based on RL

笔记整理&#xff1a;郑国鹏&#xff0c;天津大学硕士链接&#xff1a;https://link.springer.com/article/10.1007/s11280-021-00919-x动机知识是人工智能的基石&#xff0c;它通常以RDF图的形式表示。各个领域的大规模RDF图对图数据管理提出了新的挑战。关系型数据库因其成熟…

Java8 Collectors.toMap() 的使用

目录一、简单介绍用法1&#xff1a;根据某一属性&#xff0c;对对象的实例或属性做映射用法2&#xff1a;根据某一属性&#xff0c;对对象集合进行去重二、Duplicate key 异常1&#xff09;异常重现&#xff1a;2&#xff09;异常截图&#xff1a;3&#xff09;异常说明&#x…

点云梯度下采样

点云下采样又称点云精简。 均匀网格下采样 均匀网格下采样法是建立在空间包围盒精简算法之上对散乱点云快速简化的一种算法&#xff0c;其基本思想为&#xff1a;根据点云数据的密度确定最小三维网格&#xff08;体素&#xff09;的边长为a∗b∗ca*b*ca∗b∗c&#xff0c;计算…

含电热联合系统的微电网运行优化matlab程序(yalmip+cplex)(yalmip+gurobi)

含电热联合系统的微电网运行优化matlab程序&#xff08;yalmipcplex&#xff09;&#xff08;yalmipgurobi&#xff09; 参考文献&#xff1a;含电热联合系统的微电网运行优化 在当前能源互联网迅速发展及电热联系日渐紧密的环境下&#xff0c;提出基于电热联合调度的区域并网…

个人电影网站web网页设计制作—— 影视公司5页 DIV+CSS制作 浮动布局

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 精彩专栏推荐&#x1f4…

【Vim】更改Vim编辑器的字体大小、改变字号;永久改变字号;改变字体颜色、字体显示样式

一、问题背景 初次使用Vim&#xff0c;由于电脑分辨率较高&#xff0c;在编辑器上显示的文本字号较小&#xff0c;不甚看清。 我使用的是Gvim for Windows。 二、网上的已有方法小结 2.1 快捷键ctrl 和ctrl - 标题中提到的号&#xff0c;需要按下shift才能输入&#xff0c…

用DIV+CSS技术设计的公益主题网站——防止电信诈骗(web前端网页制作课作业)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

狂神说MybatisPlus学习笔记

MyBatis-Plus 学习MyBatis-Plus之前要先学MyBatis–>Spring—>SpringMVC 为什么要学它?MyBatisPlus可以节省我们大量的时间,所有CRUD代码都可以自动完成 JPA, tk-mapper ,MyBatisPlus 偷懒用的! 1.简介 是什么? 2.特性 无侵入&#xff1a;只做增强不做改变&am…

C语言第十二课(上):操作符详解【算数、移位、位、赋值操作符】

目录 前言&#xff1a; 一、操作符分类&#xff1a; 二、操作符详解&#xff1a; 1.算术操作符、-、*、/、%&#xff1a; 2.移位操作符>>、<<&#xff1a; 1.原码、反码与补码&#xff1a; 2.左移操作符&#xff1a; 3.右移操作符&#xff1a; 4.警告⚠&#xf…

Qt5开发从入门到精通——第十二篇三节(Qt5 事件处理及实例——多线程应用、服务器端编程、客户端编程)

提示&#xff1a;欢迎小伙伴的点评✨✨&#xff0c;相互学习c/c应用开发。&#x1f373;&#x1f373;&#x1f373; 博主&#x1f9d1;&#x1f9d1; 本着开源的精神交流Qt开发的经验、将持续更新续章&#xff0c;为社区贡献博主自身的开源精神&#x1f469;‍&#x1f680; 文…

用DIV+CSS技术设计的抗击疫情网页与实现制作(web前端网页制作课作业)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

基于C++实现的游客信息管理系统

目 录 一、 项目技术路线说明 1 二、 项目需求分析 2 2.1 项目介绍 2 2.2 功能需求 2 三、 系统分析与设计 3 3.1 本程序需解决的关键技术问题 3 3.2 程序流程 3 3.2.1 注册或登陆流程图 3 3.2.2 信息日期判断流程图 4 3.2.3 操作功能选择模块 5 3.3 功能模块 6 3.3.1 增删改查…

让Unity打包AssetBundle更轻松

AssetBundle作用1、AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至整个场景&#xff0c;可以在游戏运行的时候被加载&#xff1b; 2、AssetBundle自身保存着互相的依赖关系&#xff1b; 3、压缩包可以使用LZMA和LZ4压缩算法&#xff0c;减少包大小&#xff0c;更快…

HTML小游戏13 —— 仿《神庙逃亡》3D风格跑酷游戏《墓地逃亡》(附完整源码)

&#x1f482; 网站推荐:【神级源码资源网】【摸鱼小游戏】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f4ac; 免费且实用的计…