C++学习笔记7[指针]
C++学习目录链接:
C++学习笔记目录链接(持续更新中)
文章目录
- 一、变量和指针
- 1.指针的声明
- 2.指针的赋值
- 3.关于指针使用的说明
- 4.指针运算符和取地址运算符
- 5.指针运算
- 二、指针和数组
- 1.数组的存储
- 2.指针与一维数组
- 3.指针与二维数组
- 4.指针与字符数组
- 三、指向函数的指针
- 四、引用
- 1.使用引用传递参数
- 2.使用指针传递参数
- 3.数组作为函数参数
- 五、指针数组
一、变量和指针
系统的内存就像是带有编号的小房间,如果想使用内存就需要得到房间号。如图所示,定义一个整型变量i,它需要4个字节,所以编译器为变量i分配了编号从4001到4004的房间,每个房间代表一个字节。
各个变量连续地存储在系统的内存中,如图所示,两个整型变量i和i存储在内存中。
在程序代码中通过变量名来对内存单元进行存取操作,但是代码经过编译后已经将变量名转换为该变量在内存的存放地址,对变量值的存取都是通过地址进行的。例如语句“i+j;” 的执行过程是根据变量名与地址的对应关系,找到变量i的地址4001,然后从4001开始读取4个字节数据放到CPU的寄存器中,再找到变量j的地址4005,从4005开始读取4个字节的数据放到CPU的另一个寄存器中,通过CPU的加法中断计算出结果。
在低级语言的汇编语言中都是直接通过地址来访问内存单元,而在高级语言中才使用变量名访问内存单元,C语言作为高级语言却提供了通过地址来访问内存单元的方法,C++语法也继承了这一特性。
由于通过地址能访问指定的内存存储单元,可以说地址“指向”该内存单元,例如房间号4001指向系统内存中的一个字节。地址可以形象地称为指针,意思是通过指针能找到内存单元。一个变量的地址称为该变量的指针。如果有-一个变量专门用来存放另一个变量的地址,它就是指针变量。在C++语言中有专门用来存放内存单元地址的变量类型,就是指针类型。
指针是一种数据类型,通常所说的指针就是指针变量,它是一个专门用来存放地址的变量,而变量的指针主要指变量在内存中的地址。变量的地址在编写代码时无法获取,只有在程序运行时才可以得到。
1.指针的声明
声明指针的一般形式如下
数据类型标识符*指针变量名
int *P_iPoint;//声明一个整数型指针
float *a,*b;//声明两个浮点型指针
2.指针的赋值
指针可以在初始化时赋值,也可以在后期赋值。
在初始化时赋值
int i=100;//声明一个变量
int *a=&i;//声明一个指针变量,并赋值
后期赋值
int i=100;
int *a;
a=&i;
3.关于指针使用的说明
(1)指针变量名是p,而不是*p。
p=&i的意思是取变量i的地址赋给指针变量p。.
下面的实例可以获取变量的地址,并将获取的地址值输出,。
/* 输出变量的地址*/
#include <iostream>
using namespace std;
void main()
{int i=100;
int *a;
a=&i;
printf("%d\n",a);
}
实例可以通过printf函数直接将地址值输出。由于变量是由系统分配空间,所以变量的地址不是固定不变的。
(2)指针变量不可以直接赋值。例如:
int i=100;
int *a;
a=i;
编译不能通过,有“error C2440: '= : cannot convert from ‘const int’ to 'int '”错误提示。
如果强行赋值,使用指针运算符提取指针所指变量时会出错。例如:
int i=100;
int *a;
a=(int*)i;//强行将100转换成指针变量赋值
printf("%d\n",a); //正确运行,显示100
printf("%d\n",*a);//出错,没有显示数据
算例:通过指针来比较两个数的大小
/* 比较两个数的大小*/
#include <iostream>
using namespace std;
void main()
{int *p1,*p2;//定义两个指针变量
int *p;//定义一个临时指针变量
int a,b;
cout<<"请输入一个数:"<<endl;
cin>>a;
cout<<"请输入另一个数:"<<endl;
cin>>b;
p1=&a;p2=&b;//指针赋值
if (a<b)
{p=p1;
p1=p2;
p2=p;
}
cout<<"较大值:"<<*p1<<endl;
cout<<"较小值:"<<*p2<<endl;
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
4.指针运算符和取地址运算符
*和&是两个运算符,*是指针运算符,&是取值运算符。
如图所示,变量i的值为100, 存储在内存地址为4009的地方,取地址运算符&使指针变量p得到地址4009。
如图所示,指针变量存储的是地址编号4009,指针通过指针运算符可以得到地址4009所对应的数值。.
#include <iostream>
using namespace std;
void main()
{int a=100;
int *p;
p=&a;//指针变量取值
cout<<"p ="<<p<<endl;
cout<<"*p ="<<*p<<endl;
}
指针运算符和取地址运算符的说明
声明并初始化指针变量时同时用到了*和&这两个运算符。例如:
int a=100;
int *p=&a;//声明一个指针变量并初始化
&p 和&a的区别
&和的运算符优先级别相同,按自右而左的方向结合,因此&p 是先进行运算,p 相当于变量a;再进行&运算,&p 就相当于取变量a的地址。&a 是先计算&运算符,&a就是取变量a的地址;然后进行运算,&a 就相当于取变量a所在地址的值,实际就是变量a。
5.指针运算
指针变量存储的是地址值,对指针作运算就等于对地址作运算。下面通过实例来使读者了解指针的运算。
#include <iostream>
using namespace std;
void main()
{int a=100;
int *p=&a;//声明一个指针变量并初始化
cout<<"p的地址:"<<p<<endl;
p--;
cout<<"p--的地址:"<<p<<endl;
p++;
cout<<"p++的地址:"<<p++<<endl;}
指针进行一次加 1运算,其地址值并没有加1,而是增加了4,这和声明指针的类型有关。p++是对指针作自加运算,相当于语句“p=p+1",地址是按字节存放数据,但指针加1并不代表地址值加1个字节,而是加上指针数据类型所占的字节宽度。要获取字节宽度需要使用sizeof 关键字,
例如整型的字节宽度是sizeof(int), sizeof(int)的值为 4;双精度整型的字节宽度是sizeof(double),其值为8。将实例中的int指针类型改为double,看看运行结果,代码如下:
二、指针和数组
1.数组的存储
数组,作为同名、同类型元素的有序集合,被顺序存放在一块连续的内存中,而且每个元素存储空间的大小相同。数组中第一个元 素的存储地址就是整个数组的存储首地址,该地址放在数组名中。对于一维数组而言,其结构是线性的,所以数组元素按下标值由小到
大的顺序依次存放在一块连续的内存中。 在内存中存储一维数组如图所示。对于二维数组而言,用矩阵方式存储元素,在内存中仍然是线性结构。
2.指针与一维数组
系统需要提供一定 量连续的内存来存储数组中的各元素,内存都有地址,指针变量就是存放地址的变量,如果把数组的地址赋给指针变量,就可以通过指针变量来引用数组。引用数组元素有两种方法:下 标法和指针法。通过指针引用数组,就要先声明一个数组,再声明一个指针。例如:
int a[10];
int *p;
然后通过&运算符获取数组中元素的地址,再将地址值赋给指针变量。例如:
把a[0]元素的地址赋给指针变量p,即p指向a数组的第0号元素,
p=&a[0];
通过指针变量获取数组中的元素
#include <iostream>
using namespace std;
void main()
{int i,a[10];
int *p;
//利用循环,分别为10个元素赋值
for(i=0;i<10;i++)a[i]=i;
//将数组中的10个元素输出到设备
p=&a[0];
for(i=0;i<10;i++,p++)
cout<<*p<<endl;}
如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。
p+i和a+i是a[i]的地址。a代表首元素的地址,a+i 也是地址,对应数组元素a[i]。
*(p+i)
*(a+i)
是p+i或a+i所指向的数组元素,即a[i]。
程序中使用指针获取数组首元素的地址,也可以将数组名赋值给指针,然后通过指针访问数组。实现代码如下
#include <iostream>
using namespace std;
void main()
{int i,a[10];
int *p;
//利用循环,分别为10个元素赋值
for(i=0;i<10;i++)a[i]=i;
//将数组中的10个元素输出到设备
p=a;
for(i=0;i<10;i++,p++)
cout<<*p<<endl;}
3.指针与二维数组
可以将一维数组的地址赋给指针变量,同样也可以将二维数组的地址赋给指针变量,因为一维数组的内存地址是连续的,二维数组的内存地址也是连续的,所以可以将二维数组看作是- -维数组。二维数组中各元素的地址如图7.24所示。
使用指针遍历二维数组
#include <iostream>
using namespace std;
void main()
{int i,a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};int *p;p=a[0];for(i=0;i<sizeof(a)/sizeof(int);i++,p++){cout<<"地址:";cout<<a[i];cout<<"是";cout<<*p<<endl;}
}
程序中通过*p对二维数组中的所有元素都进行了引用,如果想对二维数组中某一行中的某一列元素进行引用,就需要将二维数组不同行的首元素地址赋给指针变量。
(1) a+n表示第n行的首地址。
(2) &a[0][0]既可以看作数组0行0列的首地址,也可以看作二维数组的首地址。&a[m][n]就是第m行n列元素的地址。
(3) &a[0]是第0行的首地址,当然&a[n]就是第 n行的首地址。
(4) a[0]+n 表示第0行第n个元素的地址。
(5) *(*(a+n)+m)
表示第 n行第m列元素。
(6) *(a[n]+m)
表示第n行第m列元素。
#include <iostream>
using namespace std;
void main()
{int i,j,a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};for(i=0;i<3;i++)for(j=0;j<4;j++)cout<<*(*(a+i)+j)<<endl;
}
4.指针与字符数组
字符数组是一一个一维数组, 使用指针同样也可以引用字符数组。引用字符数组的指针为字符指针,字符指针就是指向字符型内存空间的指针变量,其一般的定 义语句如下:
char *p;
字将数组就是一个字符串, 通过字符指针可以指向一个字符串。 例如,语句
char *p="www.baidu.com";
等价于
char *p;
p="www.baidu.com";
示例:连接两个字符串
#include <iostream>
using namespace std;
void main()
{char str1[10],str2[5],*p1,*p2;p1=str1;p2=str2;cout<<"请输入第一个字符串:"<<endl;gets(str1);cout<<"请输入第二个字符串:"<<endl;gets(str2);while(*p1!='\0')p1++;while(*p2!='\0')*p1++=*p2++;*p1='\0';//添加结束符号cout<<"打印拼接后的字符串";puts(str1);
}
三、指向函数的指针
指针变量也可以指向一个函数。一个函数在编译时被分配给一个入口地址,这个函数入口地址就称为函数的指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。一个函数可以返回一个整型值、 字符值、实型值等,也可以返回指针型的数据,即地址。其概念与之前类似,只是返回的值的类型是指针类型而已。返回指针类型的值的函数简称为指针函数。
定义指针函数的一般形式为:
类型名*函数名(参数表列);
例如,定义一个具有两个参数和-一个返回值的函数的指针,其代码如下:
int *a(int x,int y);
示例:利用指针进行平均值计算
#include <iostream>
#include<iomanip>//omanip的作用:主要是对cin,cout之类的一些操纵运算子,比如setfill,setw,setbase,setprecision等等。它是I/O流控制头文件,就像C里面的格式化输出一样.
using namespace std;
int avg(int a,int b);//函数的声明
void main()
{int iWidth,iLenght,iResult;iWidth=10;iLenght=30;int(*Pfun)(int,int);//定义函数指针Pfun=avg;iResult=(*Pfun)(iWidth,iLenght);cout<<iResult<<endl;
}int avg(int a,int b)
{return (a+b)/2;
}
四、引用
引用实际上是一种隐式指针, 它为对象建立一个别名,通过操作符&来实现。&是取地址操作符,通过它可以获得地址
引用的形式如下:
数据类型&表达式;
例如
int a;
int &ia=a;//引用
ia=2;
定义了一个引用变量ia,它是变量a的别名,对ia的操作与对a的操作完全一样。 ia=2 把2赋给a,&ia返回a的地址。执行ia=2和执行a=2等价。
使用引用的说明:
(1)一个C++引用被初始化后,无法使用它再去引用另一个对象,它不能被重新约束。
(2)引用变量只是其他对象的别名,对它的操作与原来对象的操作具有相同作用。
(3)指针变量与引用有两点主要区别:一是指针是一种数据类型, 而引用不是一个数据类型,指针可以转换为它所指向变量的数据类型,以便赋值运算符两边的类型相匹配;而在使用引用时,系统要求引用和变量的数据类型必须相同,不能进行数据类型转换。二是指针变量和引用变量都用来指向其他变量,但指针变量使用的语法要复杂- 些;而在定义了引用变量后,其使用方法与普通变量相同。
例如:
int a;
int *ia=&a;
int &ia=a;
引用应该初始化,否则会报错
如下面算例编译器会报出“references must be initialized" 这样的错误,造成编译不能通过。
int a;
int b;
int &ia;
下面通过一个算例感受下引用
#include <iostream>
using namespace std;
void main()
{int a;int &ref_a=a;//引用a=100;cout<<"a="<<a<<endl;cout<<"ref_a="<<ref_a<<endl;a=2;cout<<"a="<<a<<endl;cout<<"ref_a="<<ref_a<<endl;int b=20;ref_a=b;cout<<"a="<<a<<endl;cout<<"b="<<b<<endl;cout<<"ref_a="<<ref_a<<endl;
}
1.使用引用传递参数
在C++语言中,函数参数的传递方式主要有两种,分别为值传递和引用传递。所谓值传递,是指在函数调用时,将实际参数的值赋值一份传递到调用函数中,这样如果在调用函数中修改了参数的值,其改变不会影响到实际参数的值。而引用传递则恰恰相反,如果函数按引用方式传递,在调用函数中修改了参数的值,其改变会影响到实际参数。
#include <iostream>
using namespace std;
swap(int &a,int &b)
{ int tmp;tmp=a;a=b;b=tmp;
}void main()
{int x,y;cout<<"请输入两个整数x,y:"<<endl;cin>>x;cin>>y;if(x<y){swap(x,y);}cout<<"x="<<x<<endl;cout<<"y="<<y<<endl;
}
2.使用指针传递参数
指针变量可以作为函数参数。使用指针变量传递参数和使用引用传递参数方式的执行效果相同,可以对同一个函数使用两种方式传递参数进行对比,观察程序的执行结果。为了使读者更好地了解指针作为参数进行传递的操作,下面通过指针传递参数实现变量值的交换功能。
#include <iostream>
using namespace std;
swap(int *a,int *b)
{ int tmp;tmp=*a;*a=*b;*b=tmp;
}void main()
{int x,y;int *ix,*iy;cout<<"请输入两个整数x,y:"<<endl;cin>>x;cin>>y;ix=&x;iy=&y;if(x<y){swap(ix,iy);}cout<<"x="<<x<<endl;cout<<"y="<<y<<endl;
}
3.数组作为函数参数
一、数组名作为函数的参数,传递的是一个地址(或常量指针)
#include<stdio.h>
void arr(int a[])//数组名作为函数的参数,传递的是一个地址(或常量指针)
{int i;for(i=0;i<5;i++){printf("%d\n",a[i]);}
}
int main()
{int a[] = {1,2,3,4,5};arr(a);return 0;}}
例子:输出平均值
#include <iostream>
using namespace std;int average(int array[10]) {int i, sum = 0;for(i = 0; i < 10; ++i) {sum += array[i];}return sum / 10;
}int main() {int i, score[10];cout << "请输入10个成绩:";for (i = 0; i < 10; i++) {cin >> score[i];}cout << "平均成绩是:" << average(score) << endl;return 0;
}
五、指针数组
数组中的元素均为指针变量的数组称为指针数组,- -维指针数组的定义形式为:
类型名*数组名[数组长度];
例如:int *P[4];
指针数组中的数组名也是一一个指针变量,该指针变量为指向指针的指针。
例如:
int *p[4];
int a=1;
*p[0]=&a;
p是一个指针数组,它的每一个元素是一个指针型数据(其值为地址),指针数组p的第-一个值是变量a的地址。指针数组中的元素可以使用指向指针的指针来引用。例如: .int *(*p);
*运算符表示p是一个指针变量,*(*p)
表 示指向指针的指针,*运算符的结合性是从右到左,因此“int *(*p)
;”可写成“int **p;
"。指向指针的指针获取指针数组中的元素和利用指针获取- -维数组中 的元素方法相同,如图所示。
第一次进行指针*
运算获取到的是一个地址值,再进行一次指针*
运算,就可以获取到具体值。
作者:电气-余登武
C++学习笔记7[指针]相关推荐
- 梓益C语言学习笔记之指针
梓益C语言学习笔记之指针 一.32位平台下,地址是32位,所以指针变量占32位,共4个字节 二.内存单元的地址即为指针,存放指针的变量称为指针变量,故:"指针"是指地址,是常量,& ...
- C/C++学习笔记之指针体系
铁律1:指针是一种数据类型 1)指针也是一种变量,占有内存空间,用来保存内存地址 测试指针变量占有内存空间大小 2)*p操作内存 在指针声明时,*号表示所声明的变量为指针 在指针使用时,*号表示 操作 ...
- C++学习笔记——智能指针
c++里不像java等语言设置了垃圾回收的功能,但是c++通过它的王牌指针实现了智能指针这一解决办法. 目录 异常 1.异常 2.异常的使用 3.异常的规则 4.异常安全 智能指针 概念 原理 aut ...
- c++学习笔记之指针
1.声明指针 如果声明多个指针,每个都必须加*,如int *aPtr, *bPtr 变量名最好以Ptr结尾,表明是指针变量 把指针初始化NULL和0是等价的 2.地址运算符和间接运算符 地址运算符&a ...
- Boost学习笔记-智能指针
1. 智能指针 scoped_ptr 只在作用域内生效,离开作用域既释放资源,不能复制和赋值.类似于标准库的auto_ptr,但它相对于auto_ptr的优势在于,他的要求更严格,使用起来更安全.a ...
- Rust 学习笔记——智能指针
https://doc.rust-lang.org/book/ch15-00-smart-pointers.html 智能指针是一种想指针一样的行为且具有其他能力的数据结构(Smart pointer ...
- C语言学习笔记--数组指针和指针数组
C 语言中的数组有自己特定的类型,数组的类型由元素类型和数组大小共同决定.(如 int array[5]类型为 int[5]) 1.定义数组类型 C 语言中通过 typedef 为数组类型重命名:ty ...
- go学习笔记-语言指针
语言指针 定义及使用 变量是一种使用方便的占位符,用于引用计算机内存地址.取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址. 一个指针变量指向了一个值的内存地址.类似于变量和常量, ...
- C 学习笔记 —— 高级指针话题
文章目录 高级声明 函数指针 函数指针的声明 赋值 调用 函数指针作为参数传递 实例(转移表+函数传参) 回调函数 命令行参数 字符串常量 高级声明 int f; //整型变量 int *f; //指 ...
最新文章
- Weex 版扫雷游戏开发
- 《MonkeyRunner原理剖析》第九章-MonkeyImage实现原理 - 概览
- Project Euler 1-25
- makefile 学习(一)
- 可重入锁(递归锁) 互斥锁属性设置
- Java中通过代理对类进行修改
- c++ boost多线程学习(一)
- java重_重拾JAVA,重识JAVA(一)
- foreach循环符合就不往下走了_游泳池循环方式及循环周期
- TokenInsight:反映区块链行业整体表现的TI指数较昨日同期下降3.29%
- 【PTA】520 钻石争霸赛 2021,119分
- p40_数据交换方式
- HDU 4540 威威猫系列故事——打地鼠(DP)
- html 滑动返回顶部,返回页面顶部的几种方式总结
- EL表达式和JSTL标签库
- PDF文件怎么转换成CAD格式?教你几种转换方法
- C语言实现24点游戏算法
- 缩减Centos7xfs磁盘空间
- 微信中怎么打开apk下载链接 微信跳转打开外部浏览器打开apk文件
- SIP与P2P的技术携手创造奇迹?
热门文章
- cdh jar包 sqoop2_安装sqoop1.4.6-cdh5.5.2
- oracle 按月累计求和,SQL Cumulative Sum累积求和
- SpringMVC获取请求参数-基本类型
- mybatis方法传入多参数
- SpringAOP中通过JoinPoint获取值,并且实现redis注解
- MyBatis Plus——忽略某个实体类属性和数据库表字段之间的映射关系
- Soldier and Traveling
- CG CTF RE Hello,RE!
- Fibonacci in the Pocket
- Little Sub and Triples