指针其实存储的是变量在内存中的地址,将指针指向变量后,就可以使用该指针来获取变量的值或者为变量赋新值。
一、指针的基本用法
指针是用来指向某个变量的,将指针指向变量后,指针存储的是该变量在内存中的地址。要使用指针,首先要申明指针,然后就可以将指针指向变量。将指针指向变量后,就可以使用该指针来获取变量的值或者为变量赋新值:
#include<iostream>
using namespace std;
int main()
{
int n = 123;
int *p; //申明int*类型指针p,这样的指针可以指向int类型变量
p = &n; //通过取地址运算将指针p指向变量n
cout<<n<<endl;
cout<<*p<<endl; //通过指针获取其指向的变量的值
*p = 0; //通过指针修改其指向的变量的值
cout<<n<<endl;
cout<<*p<<endl;
(*p)++; //指针指向变量的值自加,这里的括号不能省略
cout<<n<<endl;
cout<<*p<<endl;
int *q = p; //指针q的值赋值为指针p的值,q也指向p指向的变量n
*q = *q + 1;
cout<<n<<endl;
cout<<*p<<" "<<*q<<endl;
return 0;
}
指针实际上存储的是其指向的变量在内存中的地址,运行下面的程序:
#include<iostream>
using namespace std;
int main()
{
int n = 123;
int *p; //申明int*指针p,可以指向int类型变量
p = &n; //指针p指向变量n
cout<<n<<" "<<*p<<endl; //变量的值
cout<<&n<<" "<<p<<endl; //变量在内存的地址
return 0;
}
程序运行结果如下(自行测试时第2行可能和下面的结果不一致):
123 123 0x6dfe78 0x6dfe78
第2行输出的就是变量n在内存的地址(是一个十六进制数)。
对于scanf语句:scanf("%d",&n);,我们已经知道int类型变量n前面必须加上取地址符号&,现在我们清楚了,这里&n其实是指向变量n的指针,scanf函数要求从第2个参数开始后面的参数必须是指针,所以需要在普通变量前加上取地址符号&。
二、数组与指针
先来看下面的程序:
#include<iostream>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
cout<<a<<endl;
return 0;
}
运行程序会发现,直接输出数组名a,输出的是一个十六进制的地址,原来数组名其实也是一个指针(其实是一个常量指针),指向的是数组的第0个元素。那么指针a+i指向的是数组第i个元素a[i]。来看下面的程序:
#include<iostream>
using namespace std;
int main()
{
int a[5];
for(int i=0;i<5;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<5;i++){
printf("%d ",a[i]);
}
return 0;
}
#include<iostream>
using namespace std;
int main()
{
int a[5];
for(int i=0;i<5;i++){
scanf("%d",a+i);
}
for(int i=0;i<5;i++){
printf("%d ",*(a+i));
}
return 0;
}
现在我们应该清楚scanf输入字符串时:char str[1010];scanf("%s",str);,这里用字符数组存储字符串,str已经是指针了,就不能在str前添加取地址符号&。
需要特别注意的是,数组名是一个常量指针,可以将数组名赋值给其他指针,但是不能将其他指针赋值给数组名:
#include<iostream>
using namespace std;
int main()
{
int a[5];
//指针pa赋值为数组名a,pa指向a[0]
int *pa = a;
for(int i=0;i<5;i++){
scanf("%d",pa+i);
}
for(int i=0;i<5;i++){
printf("%d ",*(pa+i));
}
return 0;
}
#include<iostream>
using namespace std;
int main()
{
int a[5],n = 100;
int *pa = &n;
a = pa; //编译错误
return 0;
}
三、结构体与指针
当然可以用一个指针指向结构体变量:
#include<iostream>
using namespace std;
struct Circle{
double r;
Circle(){}
Circle(double r){ //构造函数
this->r = r; //this是指向结构体自身的指针
}
double length(){ //成员函数,计算返回圆周长
return 2*3.14*r;
}
double area(){ //成员函数,计算返回圆面积
return 3.14*r*r;
}
};
int main()
{
Circle c(12.56);
cout<<c.length()<<" "<<c.area()<<endl;
Circle *p = &c;
cout<<(*p).r<<" "<<(*p).length()<<" "<<(*p).area()<<endl; //原始写法
cout<<p->r<<" "<<p->length()<<" "<<p->area()<<endl; //简便写法
return 0;
}
甚至可以使用new关键字来直接生成指向结构体的指针:
#include<iostream>
using namespace std;
struct Circle{
double r;
Circle(){}
Circle(double r){ //构造函数
this->r = r;
}
double length(){ //成员函数,计算返回圆周长
return 2*3.14*r;
}
double area(){ //成员函数,计算返回圆面积
return 3.14*r*r;
}
};
int main()
{
Circle *p = new Circle(12.56);
cout<<(*p).r<<" "<<(*p).length()<<" "<<(*p).area()<<endl; //原始写法
cout<<p->r<<" "<<p->length()<<" "<<p->area()<<endl; //简便写法
return 0;
}
四、函数参数与指针
如果函数的参数是指针,那么在函数体内通过指针参数来修改指向变量的值,能够影响实际参数的值。将参数设置为指针类型也是函数参数采用地址传递的常用方法。
仍然以交换两个变量的值的函数为例,如果函数参数为指针,那么可以这样设计(注意和前面形式参数名前加&——引用传参——的区别):
#include<iostream>
using namespace std;
//参数是指针(地址传递)
void swap(int *x,int *y){
int t = *x;
*x = *y;
*y = t;
}
int main()
{
int a = 1,b = 2;
cout<<a<<" "<<b<<endl;
swap(&a,&b);
cout<<a<<" "<<b<<endl;
return 0;
}
#include<iostream>
using namespace std;
//引用传参
void swap(int &x,int &y){
int t = x;
x = y;
y = t;
}
int main()
{
int a = 1,b = 2;
cout<<a<<" "<<b<<endl;
swap(a,b);
cout<<a<<" "<<b<<endl;
return 0;
}
前面我们已经遇到过函数的参数是数组的情况,此时在函数体内修改形式参数数组元素的值,实际参数数组元素也会受影响。其实数组参数可以直接写成指针形式:
#include<iostream>
using namespace std;
int a[1001];
void read(int arr[],int n){
for(int i=0;i<n;i++)
cin>>arr[i];
}
void exec(int arr[],int n){
for(int i=0;i<n;i++)
arr[i] *= arr[i];
}
void out(int arr[],int n){
for(int i=0;i<n;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
int main()
{
int n;
cin>>n;
read(a,n);
out(a,n);
exec(a,n);
out(a,n);
return 0;
}
#include<iostream>
using namespace std;
int a[1001];
void read(int *arr,int n){
for(int i=0;i<n;i++)
cin>>arr[i];
}
void exec(int *arr,int n){
for(int i=0;i<n;i++)
arr[i] *= arr[i];
}
void out(int *arr,int n){
for(int i=0;i<n;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
int main()
{
int n;
cin>>n;
read(a,n);
out(a,n);
exec(a,n);
out(a,n);
return 0;
}
现在回顾一下使用scanf函数输入数据存储到变量中:
int n;
scanf("%d",&n);
调用scanf函数后,变量n的值会被修改成输入的整型数据(实际参数的值在函数内部被修改),scanf函数中实际参数n对应的形式参数就是指针类型。
NOIP学习小站