C++017-C++指针及其应用
在线练习:
C++指针及其应用
参考:
CSP-J目标
【 4 】指针
【 4 】基于指针的数组访问
【 4 】字符指针
【 4 】指向结构体的指针
1. 指针
C/C++指针是一种变量,其值为另一个变量的地址。指针可以通过解引用操作符(*)用于存储和检索地址所指向的值。通过指针,可以在函数之间传递和操作内存中的数据。指针在C/C++语言中是非常重要的概念。
1.指针变量的定义、赋值
在使用指针之前要先定义指针,对指针变量的类型说明,一般形式为:
类型说明符 *变量名;
其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示该指针变量所指向的变量的数据类型。先通过例子看看指针与普通的变量有什么不同。
1、普通变量定义
int a=3;
定义了变量 a,是 int 型的,值为 3。内存中有一块内存空间是放 a 的值,对 a 的存取操作就是直接到这个内存空间存取。内存空间的位置叫地址,存放 3 的地址可以用取地址操作符“&”对 a 运算得到:&a。
#include <iostream> using namespace std; int main() { int a=3; cout<<a<<endl; cout<<&a<<endl; return 0; }
2、指针变量定义
int *p=NULL;
定义了一个指针变量 p,p 指向一个内存空间,里面存放的是一个内存地址。现在赋值为 NULL(其实就是 0,表示特殊的空地址)。
#include <iostream> using namespace std; int main() { int a=NULL; cout<<a<<endl; // 0 cout<<&a<<endl; // 0x61fe1c int *p=NULL; cout<<p<<endl; // 0 cout<<&p<<endl; // 0x61fe10 return 0; }
3、给指针变量 p 赋值
P=&a;
即把 a 变量的内存空间地址(比如:XXX)给了 p。显然,直接对 p 存取,操作的是地址。通过这个地址间接地操作,才是整数 3。P 的间接操作
要使用指针操作符*, 即*p 的值才是 3。设有指向整型变量的指针变量 p,如要把整型变量 a 的地址赋予 p 可以有以下两种方式:
①指针变量初始化的方法
int a; int *p=&a;
②赋值语句的方法
int a; int *p; p=&a;
不允许把一个数赋予指针变量,故如下的赋值是错误的:
int *p; p=1000;
。被赋值的
指针变量前不能再加“*”说明符,故如下的赋值也是错误的:
*p=&a;
完整代码:
#include <iostream> using namespace std; int main() { int a; int *p; p=&a; // *p = &a; // invalid conversion from 'int*' to 'int' [-fpermissive]| // p=1000; invalid conversion from 'int' to 'int*' [-fpermissive]| cout<<&a<<" -- "<<p<<endl; // return 0; }
指针的几个相关操作说明表
说明 | 样例 |
指针定义: 类型说明符 *指针变量名; | int a=10; int *p; |
取地址运算符: &; | p=&a; |
间接运算符: *指针变量名; | *p=20; |
指针变量直接存取的是内存地址; | cout<<p; 结果可能是:0x4097ce; |
间接存取的才是储存类型的值; | cout<<*p; 结果是:20 |
指针变量同普通变量一样,使用之前不仅要定义说明,而且必须被赋值具体的值,未经赋值的指针变量不能使用。如定义了
int a; int *p=&a; // 则*p 表示 p 指向的整型变量
而p 中存放的是变量 a 占用单元的起始地址,所以*p 实际上访问了变量 a,也就是说*p 与 a等价。
2.指针的引用与运算
【例 2】输入 N 个整数,使用指针变量访问输出。
#include<cstdio> using namespace std; int a[101],n; int main() { scanf("%d",&n); for (int i=1; i<=n; i++) scanf("%d",&a[i]); int *p=&a[1]; //定义指针变量 int *p,初始化为数组开始元素的地址,即 a[1]; printf("&a[1] %d \n",&a[1]); for (int i=1; i<=n; i++) { printf("%d --> %d \n",*p,p); p++; //p 指向下一个数,详见说明 } return 0; }
【说明】
“p++”的意思是“广义的加 1”,不是 p 的值(地址)加 1,而是根据类型 int 增加 sizeof(int),即刚好“跳过”一个整数的空间,达到下一个整数。
类似的:
①、“p–”就是向前“跳过”一个整数的空间,达到前一个整数。
②、(p+3)就是指向后面第 3 个整数的地址。
【例 3】无类型指针运用举例。
有时候,一个指针根据不同的情况,指向的内容是不同类型的值,我们可以先不明确定义它的类型,只是定义一个无类型的指针,以后根据需要再用强制类型转换的方法明确它的类型。
#include<iostream> using namespace std; int a=10; double b=3.5; void *p; int main() { p=&a; //p 的地址赋值 cout<<*(int*)p<<endl; //必须明确 p 指向的空间的数据类型,详见说明 p=&b; cout<<*(double*)p<<endl; p=&b; cout<<*(long long*)p<<endl; return 0; }
必须明确 p 指向的空间的数据类型,类型不一样的不仅空间大小不相同,储存的格式也不同。如果把
cout<<*(double*)p<<endl;
改成
cout<<*(long long*)p<<endl;
输出的结果将
是:4615063718147915776。
2. 基于指针的数组访问
#include<cstdio> using namespace std; int main() { int a[5],i,*pa=a; //定义整型数组和指针,*pa=a 可以在下一行 pa=a; for (i=0;i<5;i++) scanf("%d",a+i); //可写成 pa+i 和 &a[i] for (i=0;i<5;i++) printf("a[%d]=%d\n",i, *(a+i)); //指针访问数组,可写成*(pa+i)或 pa[i]或 a[i] return 0; }
【例 6】动态数组,计算前缀和数组。b 是数组 a 的前缀和的数组定义:
b[i]=a[1]+a[2] +…+a[i],即 b[i]是 a 的 i 个元素的和。
#include<cstdio> using namespace std; int n; int *a; //定义指针变量 a,后面直接当数组名使用 int main() { scanf("%d",&n); a=new int[n+1]; //向操作系统申请了连续的 n+1 个 int 型的空间 for (int i=1; i<=n; i++) scanf("%d",&a[i]); for (int i=2; i<=n; i++) a[i]+=a[i-1]; for (int i=1; i<=n; i++) printf("%d ",a[i]); return 0; }
【说明】
动态数组的优点:在 OI 中,对于大数据可能超空间的情况是比较纠结的事,用小数组只的部分分,大数组可能爆空间(得 0 分)。使用“动态数组”,可以在确保小数据没问题的前提下,尽量满足大数据的需求。
3. 指针与字符串
#include<cstdio> using namespace std; int n; int *a; //定义指针变量 a,后面直接当数组名使用 int main() { char str1[]="I love China!"; printf("%s\n", str1); char *str="I love China!"; printf("%s\n", str); return 0; }
二、字符串指针作函数参数
将一个字符串从一个函数传递到另外一个函数,可以用地址传递的方法,即用字符数组名作参数或用指向字符的指针变量做参数。在被调用的函数中可以改变字符串内容,在主调函数中可以得到改变了的字符串。
【例 8】输入一个长度最大为 100 的字符串,以字符数组的方式储存,再将字符串倒序储存,输出倒序储存后的字符串。(这里以字符指针为函数参数)
#include<cstdio> #include<cstring> using namespace std; void swapp(char &a,char &b) //交换两个字符的位置 { char t; t=a; a=b; b=t; } void work(char* str) { int len=strlen(str); //strlen(str)这个函数返回的是 str 的长度, //需包含头文件 cstring //这个函数的原型是"size_t strlen(const char* str)" for (int i=0; i<=len/2; ++i) swapp(str[i],str[len-i-1]); } int main() { char s[110]; char *str = s; gets(s); work(str); printf("%s",s); return 0; }
4. 结构体与指针
#include<cstdio> using namespace std; struct student { char name[20]; char sex; int score; } s[3]= {{"xiaoming",'f',356}, {"xiaoliang",'f',350}, {"xiaohong",'m',0} }; int main() { student *p; printf("Name Sex Score\n"); for (p=s; p<s+3; p++) printf("%-9s%3c%7d\n",p->name,p->sex,p->score); return 0; }
在线练习:
总结
本系列为C++学习系列,会介绍C++基础语法,基础算法与数据结构的相关内容。本文为C++指针及其应用案例,包括相关案例练习。