三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

【C语言指针进阶】一篇搞懂数组指针与指针数组、二级指针、指针函数与函数指针的区别

【C语言指针进阶】一篇搞懂数组指针与指针数组、二级指针、指针函数与函数指针的区别

一、数组指针

数组指针:本质是指针,指向数组整体的指针。

语法:

int (*变量名)[5]; // 定义了一个指针变量,指针变量自己占 8 字节空间,可以指向一个具有 5 个元素的整型数组。 // 定义了一个指向 5 个整形元素的数组的指针。 a:首元素地址 ---> &a[0] ---> int* &a:数组的指针 ---> int (*)[5]; &a+1:数组指针+1 ---> 代表偏移整个数组(sizeof(a)字节)

注意:

int a[5] = {1,2,3,4,5}; a:首元素地址 ---> int * 除了 2 种场景: 1.sizeof(a/数组名); a 不能当作 int * 类型,当作数组整体,代表整个数组。 2.&a; 数组指针,该指针类型为 int (*)[5]; 指向一个数组整体。

二、指针和二维数组

二维数组的数组名是首元素地址,首元素是一维指针,所以二维数组数组名本质是一维数组指针。

int a[5] = {1,2,3,4,5}; a ---> 首元素地址 ---> &a[0] ---> int * ---> 指针 a[n] ---> *(a+n) int a[2][3] = {1,2,3,4,5,6}; a ---> 首元素地址 ---> &a[0] ---> int (*)[3] ---> 数组指针 a[m][n] ---> *(a[m]+n) ---> ((a+m)+n) ---> *(a+m)[n]

二维数组的数组名作为函数参数传递:

int a[2][3] = {1,2,3,4,5,6}; void print_2D_array(int a[][列数], int row) {} void print_2D_array(int (*pa)[列数], int row); {} print_2D_array(a, 2); char str[2][100] = {"hello world", "how are you"}; void print_str_array(char str[][100], int row) {} void print_str_array(char (*pstr)[100], int row) {} print_str_array(str, 2);

三、指针数组

指针数组:本质是数组,该数组中保存的是指针。

语法:

int a[5]; int *a[5]; // int *:数组中保存的数据类型,该数组中保存的是 int * 指针。 // [5]:该数组中可以保存 5 个指针(int *)。 // 定义了一个可以保存 5 个整形指针的数组,整体占 40 个字节。 char *p[5];

(1)指针数组的定义

指针类型 数组名[元素个数];

(2)指针数组的初始化

char *p = NULL; char *p[5] = {NULL}; // 将 5 个字符型指针初始化成 NULL char *p = "hello"; char *p[5] = {"hello", "world", "how", "are", "you"}; // p[0] ---> char * ---> p[0] 指针保存字符串常量 "hello" 的首地址 // p[1] ---> char * ---> p[1] 指针保存字符串常量 "world" 的首地址 // p[2] ---> char * ---> p[2] 指针保存字符串常量 "how" 的首地址 // p[3] ---> char * ---> p[3] 指针保存字符串常量 "are" 的首地址 // p[4] ---> char * ---> p[4] 指针保存字符串常量 "you" 的首地址 char *p1 = "hello"; char *p2 = "world"; char *p3 = "how"; char *p[3] = {p1, p2, p3};

(3)指针数组和二维字符型数组的区别

char str[3][100] = {"hello", "world", "how"}; sizeof(str) = 300 字节 char *pstr3[3] = {"hello", "world", "how"}; sizeof(pstr) = 24 字节 ---> sizeof(char *) = 8 字节 区别: 二维字符型数组中保存的是多个字符串本身;指针数组中保存的是多个字符串的首地址。 要保存多个字符串用二维字符型数组;要操作多个字符串用指针数组。

四、二级指针

二级指针:本质还是指针,是一个指针变量的地址。

int **指针名称; // 保存整形指针的指针 char **指针名称; // 保存字符型指针的指针

C 语言中主要有两个二级指针的应用场景:

(1)想要在被调函数中修改主调函数中的指针变量,实参需要传递该指针变量的地址;形参用二级指针接收;

(2)指针数组的数组名,是一个二级指针,实参传递指针数组的数组名时,形参用二级指针接收。

char *str[3] = {"hello", "world", "how"}; // str[0] ---> char * ---> 保存了字符串常量 "hello" 的地址 // str ---> &str[0] ---> char ** ---> 二级指针
  • 值传递:无法在被调中修改主调中的变量,只能使用该变量。

  • 指针传参:可以在被调中修改主调中定义的变量,也可以使用该变量。

  • 值传递:恰好传递的值是一个指针变量,无法在被调用修改主调中定义的指针变量,可以使用该指针变量。

  • 指针传参:可以在被调函数中修改主调函数中定义的指针变量,也可以使用该变量。

五、指针函数

指针函数:本质是函数,具有指针类型返回值的函数。

指针函数能返回什么指针?

(1)局部变量的地址不能被返回(变量,数组);

char str[32] = {"hello world"}; char *str = "hello world";

(2)具有静态生命周期的变量的地址可以被返回;

1)static 修饰的静态变量的地址;

2)全局变量的地址。

(3)可以返回字符串常量的地址;

(4)可以返回通过参数传递给该函数的地址;

(5)可以返回堆区申请的且没有被释放的空间地址。

六、函数指针

函数指针:本质是指针,指向函数的指针。

函数:函数的函数名,为函数的入口地址。

(1)定义函数指针

函数声明: int fun(int , int ); int *pfun(int , int ); 函数指针: int (*pfun)(int , int ); // 定义了一个函数指针变量,该指针在内存中占 8 字节, // 该函数指针可以指向一个具有 int 返回值、两个 int 类型参数的函数。 char *(*pfun)(char *); 总结: 返回值类型 (*指针名称)(形参表);

(2)函数指针初始化

int (*pfun)(int, int) = NULL;

(3)函数指针赋值

int add(int num1, int num2) {} int (*pfun)(int, int) = NULL; pfun = add;

(4)函数指针调用函数

函数名(实参表); 函数指针的名称(实参表);

(5)函数指针的应用

  • 回调函数

    <p>将函数作为某个函数的参数传递,传递的函数称为回调函数;</p> <p>主要为了降低代码的耦合度(关联度),减少重复代码。</p> </li>
← 返回列表