【C语言】指针 精准讲解(下)

简介: 【C语言】指针 精准讲解(下)

3.4 回顾并看看下面代码的意思


int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];


☀️解析:


int arr[5]

arr 是一个5个元素的整形数组

i n t ∗ p a r r 1 [ 10 ]

parr1 是一个数组,数组有10个元素,每个元素的类型是int*,parr1是指针数组

i n t   ( ∗ p a r r 2 ) [ 10 ]

是一个指针,该指针指向了一个数组,数组有10 个元素,每个元素的类型是int - parr2是数组指针

i n t   ( ∗ p a r r 3 [ 10 ] ) [ 5 ]

该数组有10个元素,每个元素是一个数组指针该数组指针指向的数组有5个元素,每个元素是int, 可能理解起来有点难,那就看看下面的内存步图吧


0e46ab14671f45beb1bb3f6152efadd1.png


4:数组参数、指针参数



💫在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?


4.1 一维数组传参


假如有这样一个一维数组


int a[5]

test(a)传过去给函数, 函数参数应该怎么接收?(无需返回类型)


☀️答案:


void test(int arr[])

void test(int arr[5])

一维数组传参可以用一维数组接收,[ ]可以省略不写


void test(int *arr)

当然也可以要指针来接收


当然也还有其他接收的方式,但是最常用和常见的还是这两个,其他的就不一一介绍了。


4.2 二维数组传参


假如有这样一个二维数组


int a[5][5];

test(a)传过去给函数, 函数参数应该怎么接收?(无需返回类型)


☀️答案:


void test(int arr[ ][5])

二维数组传参,用二维数组来接收,但是函数形参的设计只能省略第一个[]的数字。

因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。

这样才方便运算。


void test(int (*arr)[5])

传递的a是二维数组,其实相当于第一行的地址,可以数组指针来接收


4.3 一级指针传参


假如有这样一个一级指针


int arr[10] = {1,2,3,4,5,6,7,8,9};

int *p = arr;

test( p );传过去给函数, 函数参数应该怎么接收?(无需返回类型)


☀️答案:


void test(int *p)

一级指针传参,当然可以用一级指针来接收


但是我们思考一下:

当一个函数的参数部分为一级指针的时候,函数能接收什么参数?


比如:

  • void test1(int *p) test1() 或号里面用什么形式传过去给形参一级指针

☀️答案:


int a ;

test1 (&a)

我们把一个整型的地址取出来传过去,当然也是用一级指针来接收的。


int a ; int *p1 = &a;

test1( p )

我们传一个整型指针过去,同样也可以用一级指针来接收


int arr[10]

test1(arr)

我们也可以把数组传过去,数组名代表首元素地址,整型的地址,也是可以用一级指针来接收的


4.4 二级指针传参


假如有这样一个二级指针


int main()
{
 int n = 10;
 int*p = &n;
 int **pp = &p;
 test(pp);
 test(&p);
 return 0;
}


传过去给函数, 函数参数应该怎么接收?(无需返回类型)


☀️答案:


void test(int** ptr)

test(pp);二级指针传参,形参当然也可以使用一个二级指针接收

同样test(&p)的时候也是用二级指针来接收,因为二级指针就是接收一级指针变量的地址


还是一样我们反过来思考一下:

当函数的参数为二级指针的时候,可以接收什么参数?


比如

  • void test(int **p) test() 或号里面用什么形式传过去给形参二级指针


☀️答案:


其实上面已经写过了,传一个二级指针变量,和一级指针变量地址都是可以的

test(二级指针变量) test(一级指针变量地址)


然还可以传一个指针数组:当我们有一个int* a[5] 我们传一个test(a),因为数组名代表首元素的地址,数组每个元素都是int*,首元素地址就是int*的地址,就是二级指针,用二级指针接收也是妥妥的

int * a[5] test (a)


5:函数指针



函数指针是 指向函数的指针

难道函数也有相当于的地址吗?


  • 首先看一段代码:


#include <stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}


  • 输出的结果:


40f09942565949adad2c89a58ddfcc29.png

☀️ 函数同样也是有着自己相对应的地址。而且函数名 和 &函数名 都是函数的地址,没有区别。


输出的是两个地址,这两个地址是 test 函数的地址。 那我们的函数的地址要想保存起来,怎么保存?当然是用到我们函数指针!


  • 下面我们看代码:


void test() 
{ 
 printf("hehe\n"); 
 }
//下面pfun1和pfun2哪个有能力存放test函数的地址?
 void (*pfun1)(); 
 void *pfun2(); 


首先,能给存储地址,就要求pfun1或者pfun2是指针,那哪个是指针?

⭐️

答案是:pfun1


pfun1可以存放。pfun1先和*结合,说明pfun1是指针 ,指针指向的是一个函数,指向的函数无参数,返回值类型为void。


5.1阅读两段有趣的代码:


该两个代码是什么意思呢?


//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);


☀️解析:


(* (void (*)( ) ) 0 )( );

  • :将 0 强制类型转换成一个void(*)()的函数指针
  • 这就意味着0地址处放着一个函数,函数没参数,返回类型是void
  • 调用0地址处的这个函数


☀️该代码是一次函数调用


void (* signal(int , void( * )(int) ) )(int);

  • 函数的名字是signal
  • signal函数的参数第一个是int类型,第二个是void(*)(int)类型的函数指针,该函数指针指向的函数参数是int,返回类型是void
  • signal函数的返回类型也是一个函数指针
  • 该函数指针指向的函数参数是int,返回类型是void


☀️上述的代码是一个函数的声明

其实代码二还可以在简化:如下

  • typedef void(*pfun_t)(int); 注意pfun_t要放在 * 旁边才符号C语言语法规定。
  • pfun_t signal(int, pfun_t); 化简后


6:函数指针数组



数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组.

那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?


  • 下面我们来看代码吧


int (*parr1[10])();
int *parr2[10]();
int (*)() parr3[10];


☀️答案是:parr1

parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢?

是 int (*)() 类型的函数指针。


那函数指针的使用途径是什么?其实是转移表


转移表例子:(计算器)


int add(int a, int b)
{
  return a + b;
}
int sub(int a, int b)
{
  return a - b;
}
int mul(int a, int b)
{
  return a * b;
}
int Div(int a, int b)
{
  return a / b;
}
void menu()
{
  printf("************************\n");
  printf(" 1:add            2:sub \n");
  printf(" 3:mul            4:Div \n");
  printf("         0 退出         \n");
}
int main()
{
     //把第一个元素置0,更方便下面的do while退出
  int (*p[])(int, int) = {0,add,sub,mul,Div};//函数指针数组
  int pur = 0;
  int x = 0;
  int y = 0;
  do
  {
    menu();
    printf("请选择一个操作数->");
    scanf("%d",&pur);
    if (pur >= 1 && 4 >= pur)
    {
      printf("请输入两个操作数");
      scanf("%d %d", &x, &y);
      int ret = (*p[pur])(x, y);
      printf("%d\n", ret);
    }
    else if (pur == 0)
    {
      printf("退出计算机成功\n");
      break;
    }
    else
      printf("选择错误,请重新选\n");
  } while (pur);
  return 0;
}


7. 指向函数指针数组的指针



指向函数指针数组的指针是一个 指针

指针指向一个 数组 ,数组的元素都是 函数指针 ;


void test(const char* str)
{
 printf("%s\n", str);
}
int main()
{
 //函数指针pfun
 void (*pfun)(const char*) = test;
 //函数指针的数组pfunArr
 void (*pfunArr[5])(const char* str);
 pfunArr[0] = test;
 //指向函数指针数组pfunArr的指针ppfunArr
 void (*(*ppfunArr)[5])(const char*) = &pfunArr;
 return 0;
}


void (*(*ppfunArr)[5])(const char*) = &pfunArr

这就是函数指针数组的的指针

☀️解析:


首先,ppfunArr和* 结合说明是一个指针,之后与[ ]结合,说明是一个数组指针,再与*结合说明该 * 指针指向了数组指针,该指针类型是一个函数指针,该函数有一个char * 类型参数,返回值是void。


指向函数指针数组的指针的用法-其实跟指向数组的指针用法类型,这里不过多陈述 !


8:回调函数



回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。


字面上的理解,回调函数就是一个参数,将这个函数作为参数传到另一个函数里面, 另一个函数在某一些条件成立时调用该传过来的函数


8f072ce444e842b39232ffc636727043.png


目录
相关文章
|
17天前
|
安全 C语言
【C语言】如何规避野指针
【C语言】如何规避野指针
20 0
|
19天前
|
C语言
C语言:数组和指针笔试题解析(包括一些容易混淆的指针题目)
C语言:数组和指针笔试题解析(包括一些容易混淆的指针题目)
|
1月前
|
存储 程序员 编译器
爱上C语言:指针很难?来来来,看看这篇(基础篇)
爱上C语言:指针很难?来来来,看看这篇(基础篇)
|
7天前
|
C语言
c语言指针总结
c语言指针总结
13 1
|
13天前
|
存储 程序员 C语言
【C 言专栏】C 语言指针的深度解析
【4月更文挑战第30天】C 语言中的指针是程序设计的关键,它如同一把钥匙,提供直接内存操作的途径。指针是存储其他变量地址的变量,通过声明如`int *ptr`来使用。它们在动态内存分配、函数参数传递及数组操作中发挥重要作用。然而,误用指针可能导致错误,如空指针引用和内存泄漏。理解指针的运算、与数组和函数的关系,以及在结构体中的应用,是成为熟练 C 语言程序员的必经之路。虽然挑战重重,但掌握指针将增强编程效率和灵活性。不断实践和学习,我们将驾驭指针,探索更广阔的编程世界。
|
14天前
|
算法 搜索推荐 程序员
C语言中的函数指针和回调函数
C语言中的函数指针和回调函数
10 2
|
17天前
|
存储 编译器 C语言
【C语言】初步解决指针疑惑
【C语言】初步解决指针疑惑
7 0
|
18天前
|
存储 C语言
指针深入解析(C语言基础)带你走进指针,了解指针
指针深入解析(C语言基础)带你走进指针,了解指针
|
19天前
|
C语言 C++
C语言:指针运算笔试题解析(包括令人费解的指针题目)
C语言:指针运算笔试题解析(包括令人费解的指针题目)
|
20天前
|
存储 安全 编译器
C语言怎样定义指针变量
C语言怎样定义指针变量
7 0