指针进阶

C++中变量都储存在内存中,先在内存中开辟变量类型大小的空间,然后将数值存储在其中

1、指针和指针变量

定义:指针的实质就是数据在内存中的地址,而指针变量是用来保存这些地址的变量

1
2
int a = 10;(在内存中分配四个字节的空间,首字节存储值)
int *p=&a;
示例图片

1、int p为指针:指向的是*数据在内存中的地址

2、p为指针变量:指向的是保存地址的变量(地址的编号)

3、通过取址运算符&获取指针变量的地址编号:&p

4、通过取值运算符*获取指针变量的内存空间存放的内存数据

示例图片

左侧连续的十六进制编号就是内存地址,每个内存地址对应一个字节的内存空间(一个内存单元占一个字节)。而指针变量保存的就是这个编号,也即内存地址

2、指针和数组

1
2
int *arr[10]    // 声明一个指针数组,该数组有10个元素,其中每个元素都是一个指向 int 类型对象的指针
int (*arr)[10] // 声明一个数组指针,该指针指向一个 int 类型的一维数组

2.1、数组指针

数组指针本质是一个指针变量,指向了一个数组(行指针)

1
2
3
4
int a[3][4];
int (*p)[4]; //p是一个数组指针,指向了一个包含4个int型元素的数组
p=a; //将二维数组的首地址赋给p,即a[0]或a[0][0]
p++; //跨过第一行,p指向了a[1][0]

2.2、指针数组

指针数组本质是一个数组,该数组中的每个元素都是一个指针

1
2
3
4
5
6
7
int a[3][4];
int *p[3]; //定义了一个数组,该数组中有3个int*指针变量,分别为p[0]、p[1]、p[2]
//p++; //若执行此语句,则数组p指向下一个数组元素
for(int i=0;i<3;i++)
{
p[i]=a[i]; //数组p中有3个指针,分别指向二维数组a的每一行
}

本质:()的优先级最高,[]会优先与arr结合,然后再与*符号汇合。

2.3、利用指针访问一维数组

1
2
3
4
5
6
7
int a[4]={1,2,3,4};
int *p=a; //数组首地址,p指向数组的首地址
int n=sizeof(a)/sizeof(a[0]);
for(int i=0;i<n;i++)
{
printf("a[%d]=%d\n",i,*p++);
}

数组中的各元素在内存中是连续分布的,故p++可以访问到数组的下个元素

②p++实际上是指针变量p的地址编号+sizeof(int *)

2.4、通过指针访问二维数组

2.4.1、指向元素的指针
1
2
3
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int *p=&a[0][0];
a[i][j]=*(p+i*j+j)---->(二维数组按行存储)
2.4.2、指向每一行的指针(指针数组方式)

这种方式是定义指针来指向二维数组的某一行,定义方式如下:

1
2
3
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int *p=a[0];
a[i][j]=*(p[i]+j)=p[i][j]
2.4.3、指向整个数组的指针(数组指针方式)

这种方式是定义指针来指向整个数组,定义方式如下:

1
2
3
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*p)[4]=a;--->行指针
a[i][j]=*(p[i]+j)=p[i][j]

3、指针和常量

3.1、指针常量

指针常量:const修饰的是常量,指向不能更改,指针对应的值可以更改

1
int * const p //指针常量

3.2、常量指针

常量指针:const修饰的是指针,指针对应的值不能更改,指向能更改

1
2
const int *p;
int const* p;

4、指针和函数

4.1、函数指针

1、函数指针定义:函数指针是指向函数的指针变量。 因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,只不过这里是指向函数。

1
2
int (*fun)(int x)  //函数指针的定义
int (*fun)(int x,int y) //函数指针的定义

2、函数指针的赋值

1
2
fun = &Function          //函数指针的赋值方式1(这个用的多一点)
fun = Function //函数指针的赋值方式2

3、函数指针的调用

1
2
x = (*fun)(1,1);    //函数指针的调用方式1
x = fun(2,3); //函数指针的调用方式2

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <stdlib.h>

int add(int x,int y){
return x+y;
}

int sub(int x,int y){
return x-y;
}

int main()
{
//利用函数指针实现加减法
//1、函数指针的定义
int (*fun)(int x,int y);
//2、函数指针的赋值1(初始化)
fun=&add;
//3、函数指针的调用
int x=(*fun)(1,1);
int y=(fun)(2,1);
printf("x=%d\n",x); //2
printf("y=%d\n",y); //3

//4、函数指针的赋值2(初始化)
fun=sub;
//5、函数指针的调用
int m=(*fun)(1,1);
int n=(fun)(2,1);
printf("m=%d\n",m); //0
printf("n=%d\n",n); //1

return 0;
}

用途:在C语言中,结构体不能直接包含函数。不过,你可以通过函数指针的方式将函数存储在结构体变量的成员中,从而在结构体对象中使用该函数

4.2、指针函数

1、指针函数定义:指针函数的落脚点是一个函数,这个函数的返回值是一个指针,与普通函数int function(int,int)类似,只是返回的数据类型不一样而已。

1
2
3
int  *fun(int x)        //指针函数的定义1
int * fun(int x,int y) //指针函数的定义2
int* fun(int x,int y) //指针函数的定义3(更明义)

2、指针函数的初始化

1
int *p=fun(2,3)

3、实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>

typedef struct _Data{
int a;
int b;
}Data;

Data* fun(int x,int y){
Data *data=new Data;
data->a=x;
data->b=y;
return data;
}

int main(){
//获取指针函数的返回值
Data* data=fun(2,3);

printf("a=%d\n",data->a); //2
printf("b=%d\n",data->b); //3

return 0;
}

5、指针和参数

将指针作为函数参数,形参与实参的区别(地址传递和值传递的区别,形参可以影响实参)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void swap(int *,int *);
int main()
{
int a=5,b=10;
printf("a=%d,b=%d\n",a,b); //5,10
swap(&a,&b);
printf("a=%d,b=%d\n",a,b); //10,5
return 0;
}

void swap(int *pa,int *pb)
{
int t=*pa;*pa=*pb;*pb=t;
}

经过swap函数后,实参a和b的值已经发生了变化

6、指针和结构体

如果p是一个结构体指针,则可以使用p ->【成员】的方法访问结构体的成员

7、指针大小

32位系统下:sizeof(int *)=4,64位系统下,sizeof(int *)=8

8、

1、