1,指针的基本概念
指针的作用:可以通过指针间接访问内存
- 内存的编号是从0开始记录的,一般用十六进制数字表示
- 可以利用指针变量保存地址
上图中的p就是a变量的指针,也可以记作*a
2,指针变量的定义和使用
指针变量定义语法:数据类型*变量名;
int main(){
//1,指针的定义
int a=10;
int *p;
p=&a;//指针指向变量a的地址
cout<<"a的地址为 "<<&a<<endl;//打印数据a的地址:0x6ffe14
cout<<"指针p为 "<<p<<endl;//打印指针变量p:0x6ffe14
//2, 使用指针
//可以通过解引用的方式来找到指针指向的内存
//指针前加*代表解引用,找到指针指向的内存中的数据
*p=1000;
cout<<"a= "<<a<<endl;
cout<<"*p= "<<*p<<endl;
}
*p——解引用的含义,可以通过指针来保存一个地址:
3,指针所占内存空间
指针与数组一样,也是一种数据结构,既然是一种数据结构,那么所占的内存空间是多少呢?
- 在32位操作系统下,指针是占4个字节空间大小,不管是什么数据类型。
- 在64位操作系统下,指针是占8个字节空间大小。(博主这里的os用的是64位的)
4,空指针和野指针
空指针:指针变量指向内存中编号为0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的
int main(){
//指针变量p指向内存地址编号为0的空间
int *p=NUll;
//访问空指针报错
//内存编号为0~255为系统所占内存,不允许用户访问
cout<<*p<<endl;
}
野指针:指针变量指向非法的内存空间
int main(){
//指针变量p指向内存地址编号为0x1100的空间
int *p=(int *)0x1100;
//访问野指针报错
cout<<*p<<endl;
}
(int *)0x1100的作用在于将后面的0x1100十六进制数强制转换为内存地址。
5,const修饰指针
const——n.常数;恒量 adj.恒定的;不变的
假设有以下情景,a,b,p的值如下
const修饰指针有三种情况:
1,const修饰指针——常量指针
特点:指针的指向可以修改,但指针指向的值不可以修改
const int *p=&a;
*p=20;//错误,指针指向的值不可以修改
p=&b//正确,指针的指向可以改
(红框为不允许)
2,const修饰常量——指针常量
特点:指针的指向不可以改,指针指向的值可以改,与常量指针正好相反。
int * const p=&a;
*p=20;//正确,指向的值可以改
p=&b;//错误,指针指向不可以改
(红线为不允许)
3,const既修饰指针,又修饰常量
特点,指针的指向和指针指向的值都不可以改
const int * const p=&a;
*p=20;//错误
p=&b;//正确
(红线红框均不可改)
6,指针和数组
作用:利用指针访问数组中元素
#include<bits/stdc++.h>
using namespace std;
int main(){
int arr[]={1,2,3,4,5,6,7,8,9,10};
int *p=arr;
for(int i=0;i<10;i++){
cout<<*p<<endl;
p++;//因为p是整形指针,p++的时候地址就会移动四个字节,到数组的下一个数据。
}
}
输出结果:
7,指针和函数
作用:利用指针做函数参数,可以修改实参的值
#include<bits/stdc++.h>
using namespace std;
void swap1(int a,int b){
int temp=a;
a=b;
b=temp;
}
//地址传递
void swap2(int *p1,int *p2){
int temp=*p1;
*p1=*p2;
*p2=temp;
}
int main(){
//指针和函数
//1,值传递
int a=10;
int b=20;
//swap1(a,b);a=20,b=10
//2,地址传递
//如果是地址传递,可以修饰实参
swap2(&a,&b);
cout<<"a= "<<a<<"b= "<<b<<endl; //a=20,b=10
}
a,b更换前后,内存空间的内容变化。
8,指针,数组,函数
案例:封装一个函数,利用冒泡排序,实现对整型数组的升序排序
例如数组:int arr[10]={4,3,6,9,1,2,10,8,7,5}
#include<bits/stdc++.h>
using namespace std;
void swap(int *arr,int len){//冒泡排序
for(int i=0;i<len-1;i++){
for(int j=0;j<len-i-1;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
void printarr(int *arr,int len){
for(int i=0;i<len;i++){
cout<<arr[i]<<endl;
}
}
int main(){
int arr[10]={4,3,6,9,1,2,10,8,7,5};
int len=10;
swap(arr,len);
printarr(arr,len);
}
此案例的重点在于让我们学会:
- 将数组传进函数中,即是把数组首地址传入即可
- 冒泡排序熟练的运用
- 为使函数体更加灵活,在数组长度方面选择一个形参,而非固定长度