第一节:指针变量
说明:1.指针是存地址的
2.NULL 其实就是0,特殊的空地址
不允许把一个数赋值给指针变量,
给指针变量赋值俩种方法:
A:
int a;
int *p=&a;
B:
int a;
int *p;
p=&a;
说明 | 样例 |
指针定义:类型说明符 *指针变量名 |
int a=10; int p=&a; |
取地址运算符: & | p=&a; |
间接运算符:* | *p=20; |
指针变量直接存取的是内存地址 |
cout<<p; 可能是:0x4097ce |
间接存取的才是存储类型的值 |
cout<<*p; 结果是:20 |
指针变量同普通变量一样,使用之前不仅要定义说明,而且必须被赋予具体的值,未经赋值的指针变量不能使用。
int a;
int *p=&a;
则*p表示p指向的整型变量,而p中存放的是变量a占用的起始地址,所以*p实际上访问了变量a,也就是说*p与a等价。
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int a,b;
int *pa,*pb;
pa=&a;
pb=&b;
a=10;
b=20;
cout<<*pa+*pb<<endl;//30
cout<<*pa * *pb<<endl;//200
a=150;
cout<<*pa<<endl;//150;
*pa=100;
cout<<*pa<<" "<<a<<endl;//100 100
return 0;
}
指针的引用与运算
p |
&a |
*p | a |
*p=3 | a=3 |
1.指针变量的初始化
方法 | 说明 |
int *p=NULL; | NULL是特殊的地址0,叫零指针 |
int a; int *p=&a; |
p初始化为a的地址 |
int *p=new(int) | 申请一个空间给p,*p内容不确定 |
强调:对定义的局部指针变量,其内容(地址)是随机的,直接对它操作可能会破坏程序或系统内存的值,引发不可预测的错误。所以编程中指针变量要保证先初始化或赋值,给予正确的地址在使用
2.指针变量的+ - 运算
#include<iostream>
#include<cstdio>
using namespace std;
int s[101]={0,2,1,6,0};
int n=4;
int main()
{
int *p=&s[1];
for(int i=1;i<=n;i++){
cout<<*p<<" ";//2 1 6 0
p++;
}
return 0;
}
说明:p++的意思是"广义的加1",不是p的值(地址)加1,而是根据类型int增加sizeof(int),即刚好跳过一个整数的空间,达到下一个整数。
a:p--就是向前跳过一个整数的空间,达到前一个整数
b:(p+3)就是指向后面第三个整数的地址
3.无类型指针
#include<iostream>
#include<cstdio>
using namespace std;
int a=10;
double b=3.5;
void *p;
int main()
{
p=&a;
cout<<*(int *)p<<endl;
p=&b;
cout<<*(double *)p<<endl;
cout<<*(long long *)p<<endl;
return 0;
}
必须明确p指向的空间的数据类型,类型不一样的不仅空间大小不相同,存储的格式也不同如改成long long 类型的结果是不一样的
4.多重指针
#include<iostream>
#include<cstdio>
using namespace std;
int a=10;
int *p;
int * *pp;
int main()
{
p=&a;
pp=&p;
cout<<a<<" "<<*p<<" "<<**pp<<endl;//10 10 10
}
第二节 指针与数组
1.指针与数组的关系
指向数组的指针变量称为数组指针变量。一个数组是一块连续的内存单元组成的,数组名就是这块连续内存单元的首地址。一个数组元素的首地址就是指它所占有的几个内存单元的首地址。一个指针变量既可以指向一个数组,也可以指向一个数组元素,可把数组名或第一个元素的地址赋予它。如要使指针指向第i号元素,可以把i元素的首地址赋予它,或把数组名加i赋予它。
设有数组a,指向a的指针变量为p,则有以下关系:
p , a ,&a[0] 均指向同一个单元,是数组a的首地址,也就是0号元素的首地址。
p+1, a+1, &a[1]均指向1号元素a[1]的首地址
注意:p是变量,而 a,&a[i]是常量,在编程中要注意
2.指向数组的指针
引入指针变量后,就可以用俩种方法访问数组元素了
如:int a[5];
int *p=a;
第一种:下标法,即用p[i]访问a的数组元素
第二种:指针法,即采用*(p+i)形式,用间接访问的方法访问数组元素
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int a[5];
int *p=a;
for(int i=0;i<5;i++){
scanf("%d",a+i);//可以写成p+1和&a[i];
}
for(int i=0;i<5;i++)
cout<<*(a+i)<<endl;//可写成*(p+i)或p[i]或a[i];
return 0;
}
说明:
a:直接拿a当指针用,a指向数组的开始元素,a+i是指向数组的第i个元素指针的指针。
b:指针变量p是变量,可以变得,但是数组a是静态的变量名,不可变,只能当做常量指针使用。例如:p=p+2合法,a=a+2是 非法的
c:最早在使用标准输入scanf()时就用了指针技术,读入一个变量要加取地址运算符“&”传递给scanf一个指针。对于数组,可以直接用数组当指针
3.指针也可以看成数组名
指针可以动态申请空间,如果一次申请多个变量空间,系统给的地址是连续的,就可以当成数组使用,这就是传说中的动态数组的一种
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int n;
cin>>n;
int *a;
a=new int[n+1];//向操作系统申请了连续的n+1个int型空间
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
return 0;
}
说明:在比赛中,对于大数据可能超过空间的情况是比较纠结的事,用小数组只能得部分分,大数组可能爆空间(得0分)。使用动态数组可以确保小数据没有问题的前提下,尽量满足大数据的需求