指针概览
什么是指针
指针是用来存放变量地址的,可以直接访问操作内存。
指针的定义和使用
- 指针变量 :
数据类型* 变量名;
//存储整形
int a=3;
int *p=&a;
printf("%d",*p);//3
--------------------
//存储字符
char ch='w';
char *pc=&ch;
printf("%c",*pc)//w
---------------------
//存储字符串
char *a="acbdef";
//或者调用数组的首地址
char arr[]="acbdef";
char *a=&arr;
printf("%s",a);//acbdef
- 指针数组:用来存放指针的数组
//简单使用
int a=10;
int b=20;
int c=30;
int d=40;
int * arr[4]={&a,&b,&c,&d};
for (int i = 0; i < 4; ++i) {
printf("%d",*(arr[i]));
}
//进阶使用
int arr1[]={1,2,3,};
int arr2[]={4,5,6,};
int arr3[]={7,8,9,};
int *parr[]={arr1,arr2,arr3};
for (int i = 0; i < 3; ++i) {
for (int j = 0; j <3 ; ++j) {
printf("%d",*(parr[i]+j));
}
}
- 数组指针:指向数组的指针(二维指针以上方便)
int arr[10]={1,2,3,4,5,6,7,8,9,10};
int (*p)[10]=&arr;
for (int i = 0; i <10 ; ++i) {
printf("%d",(*p)[i]);
}
- 函数指针:用来指向函数的指针
int Add(int x,int y){
return x+y;
}
void Print(char *str){
printf("%s\n",str);
}
int main() {
//函数地址
printf("%p\n",&Add);//00007ff72f6a1731
int (*pa) (int,int)=Add; //定义函数指针
printf("%p\n",pa);//00007ff6076d1731
printf("%d\n",pa(3,4));//调用函数
void (*str) (char *)=Print; //定义函数指针
str("Hello,World");//Hello,World
}
- 函数指针数组:用来指向函数的指针的数组
int Add(int x,int y){
return x+y;
}
int Div(int x,int y){
return x-y;
}
int Miu(int x,int y){
return x/y;
}
int main() {
int(* parr[3])(int,int)={Add, Div, Miu};//定义
for (int i = 0; i < 3; ++i) {
printf("%d",parr[i](2,3));5 -1 0
}
return 0;
}
- 回调函数:将参数作为函数的参数传递
void print(char *str){
printf("hello:%s",str);
}
void test(void (*p)(char *)){
p("World");
}
int main(){
test(print);
return 0;
}
------------qsort的使用------------
struct Stu{
char name[20];
int age;
};
int cmp_stu_by_age(const void *e1,const void *e2){
return ((struct Stu *)e1)->age-((struct Stu*)e2)->age;
}
int main(){
struct Stu s[3]={
{"zhangsan",26},
{"lisi",16},
{"wangwu",20}
};
qsort(s, sizeof(s)/ sizeof(s[0]), sizeof(s[0]), cmp_stu_by_age);
/*
第一个参数:待排序数组的首元素地址
第二个参数:待排序数组的元素个数
第三个参数:待排序数组的元素的大小
第四个参数:函数指针(排序规则,自己实现)
*/
for (int i = 0; i < 3; ++i) {
printf("%d",s[i].age);
}
return 0;
- 指针所占的内存空间
//64位
cout <<sizeof(int *)<<endl; //8
cout <<sizeof(double *)<<endl; //8
cout <<sizeof(float *)<<endl; //8
cout <<sizeof(bool *)<<endl; //8
cout <<sizeof(char *)<<endl; //8
//32位
cout <<sizeof(int *)<<endl; //4
cout <<sizeof(double *)<<endl; //4
cout <<sizeof(float *)<<endl; //4
cout <<sizeof(bool *)<<endl; //4
cout <<sizeof(char *)<<endl; //4
问题:为什么所占内存一样,要有这么多的类型呢?
指针类型决定了指针解引用操作的时候能有多大的权限(能限制几个字节),比如char *的解引用只能访问一个字节,而int *的指针解引用就能访问四个字节。
几种特别的指针
- 万能指针(void *):可以接收任意类型的指针
int a=10;
void *p=&a;
*p=0;//error,不能进行解引用
p++;//error 不能进行运算
- 空指针
指针变量指向内存中编号为0的空间,空指针指向的内存是不可访问的。
0~255的内存编号是系统占用的,不可访问。
- 野指针
定义:指针变量指向非法的内存空间
内存地址没有申请是不可以访问的!!!
int * p = (int *)0x1100;
cout << *p << endl;
- const修饰指针
const修饰指针有三种情况:
1,常量指针(const int * p = &a)
指针的指向可以修改,但是指针指向的值不可以修改
int a = 10;
int b = 20;
const int * p = &a;
*p = 20;//错误,指针的值不可以改
p = &b;//正确,指针指向可以改
2,const修饰常量——指针常量(int * const p = &a)
值可以改,但是指向不可以改
int a = 10;
int b = 20;
const int * p = &a;
*p = 20;//正确,指针的值可以改
p = &b;//错误,指针的指向不可以改
3,const既修饰指针,又修饰常量
指针的指向和值都不可以修改
int a = 10;
int b = 20;
const int * p = &a;
*p = 20;//错误,指针的值不可以改
p = &b;//错误,指针的指向不可以改
指针的快捷写法
写法 | 意义 |
---|---|
*(p++),*p++ | 值还是*p,但p指向了后一位 |
(*p)++ | p指向的元素加1 |
*++p, *(++p) | 先p++,此时p指针已经移动至下一个位置;然后再*,表示p指针移动之后所指向的值 |