指针进阶(一)下

简介: 指针进阶(一)

5.数组参数与指针参数


在写代码时,难免有时会将数组名传递给参数,那么我们该如何设计函数中用于接收数组名的形参呢?有两个方法:


  1. 将形参设计成数组的格式
  2. 将形参设计成指针的格式


我们来判断如下的函数部分的形参设计是否恰当呢?


一维数组传参:


#include <stdio.h>
void test(int arr[])//ok?
{}
void test(int arr[10])//ok?
{}
void test(int *arr)//ok?
{}
void test2(int *arr[20])//ok?
{}
void test2(int **arr)//ok?
{}
int main()
{
     int arr[10] = {0};
     int *arr2[20] = {0};
     test(arr);
     test2(arr2);
     return 0;
}


  • 第2行:使用恰当。函数调用时传递的是一维数组的数组名,这里形参接收时,也可以写做一维数组的格式,但其本质上不是一维数组。
  • 第4行:使用恰当。函数调用时传递的是一维数组的数组名,这里形参接收时,也可以写做一维数组的格式,但其本质上不是一维数组,所以形参中,一维数组中的元素个数并不重要,这样写也是完全恰当的。
  • 第6行:使用恰当。函数调用时传递的是一维数组的数组名,数组名代表的是数组首元素的地址,也就是int数据类型的地址,形参可以用int*类型的指针进行接收。
  • 第8行:使用恰当。传参时传递的是一维数组的数组名,这里形参接收时,也可以写做一维数组的格式,但要知道其本质上不是一维数组。
  • 第10行:使用恰当。函数调用时传递的是一维数组的数组名,数组名代表的是数组首元素的地址,也就是int*数据类型的地址,形参可以用int**类型的指针进行接收。


二维数组传参:


void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//ok?
{}
void test(int* arr[5])//ok?
{}
void test(int (*arr)[5])//ok?
{}
void test(int **arr)//ok?
{}
int main()
{
 int arr[3][5] = {0};
 test(arr);
}


  • 第1行:使用恰当。函数调用时传递的是二维数组的数组名,这里形参接收时,也可以写做二维数组的格式,但其本质上不是二维数组。并且该二维数组的列数不能省略,行数可以省略。就等同于二维数组中每个一维数组的长度必须明确。
  • 第3行:使用不恰当。函数调用时传递的是二维数组的数组名,这里形参接收时,也可以写做二维数组的形式,并且列数是不能省略的。
  • 第5行:使用恰当。数调用时传递的是二维数组的数组名,这里形参接收时,也可以写做二维数组的形式,并且这里没有省略列数。
  • 第10行:使用不恰当。数组名代表的是数组首元素的地址,也就是数组中第一个一维数组的地址,形参部分应该使用数组指针进行接收,而这里是整型指针。
  • 第12行:使用不恰当。数组名代表的是数组首元素的地址,也就是数组中第一个一维数组的地址,形参部分应该使用数组指针进行接收,而这里是指针数组。
  • 第14行:使用恰当。数组名代表的是数组首元素的地址,也就是数组中第一个一维数组的地址,形参部分采用的是数组指针进行接收。
  • 第16行:使用不恰当。数组名代表的是数组首元素的地址,也就是数组中第一个一维数组的地址,形参部分应该使用数组指针进行接收,而这里是二级整型指针。


一级指针传参:


#include <stdio.h>
void print(int *p, int sz)
{
     int i = 0;
     for(i=0; i<sz; i++)
     {
      printf("%d\n", *(p+i));
     }
}
int main()
{
     int arr[10] = {1,2,3,4,5,6,7,8,9};
     int *p = arr;
     int sz = sizeof(arr)/sizeof(arr[0]);
     //一级指针p,传给函数
     print(p, sz);
     return 0;
}

当一个函数的参数部分是一级指针时,该函数可以接收哪些类型的参数呢?


void test(int* arr);test函数可以接收:整型变量的地址,一级整型指针,一维整型数组的数组名,整型指针数组的元素。(当然这里肯定没有说全)


二级指针传参:


#include <stdio.h>
void test(int** ptr)
{
  printf("num = %d\n", **ptr); 
}
int main()
{
     int n = 10;
     int*p = &n;
     int **pp = &p;
     test(pp);//传递的是二级指针,可以用二级指针进行接收。
     test(&p);//传递的一级指针的地址,可以用二级指针进行接收。
     return 0;
 }

当函数的参数为二级指针时,可以接收哪些参数呢?


void test(int **p);test函数可以接收:一级指针的地址,二级指针,一维指针数组的数组名……


6.函数指针


先看一段代码:


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


运行结果:


f642a12ef31b1be1194cb1167535e90d_27d84ee5012349c9988810db35df0dda.png


这里输出的是test函数的地址,那么函数的地址应该使用怎样的指针变量进行保存呢?


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


pfun1先与*结合,说明pfun1是个指针,指向的函数无参,返回值为void。说明pfun1能存放test函数的地址。


阅读下面两段代码:


         

代码1是将0转化成一个(void (*)())这个函数指针,再接着对这个指针进行解引用操作,并调用该函数指针指向的函数。


代码2中,由于小括号的优先级比*高,signal先和()结合,signal代表函数名,这个函数有两个参数,分别是int类型的参数和void(*)int(函数指针)类型的参数,这第二个参数是函数指针类型,指向的函数的参数是int,返回值是void。接着将 signal(int , void(*)(int))这部分去掉,剩下的部分,即 void(*)int;signal这个函数的返回值是一个函数指针。所以代码2其实就是signal函数的声明。


关于typedef的在指针中的使用:


下面这两段代码,哪个才能达到我们的效果呢?


typedef int(*parr)[10];
typedef int(*)[10] parr;


答案是前者第一种方式才是可行的。假若要被重新命名的类型中含有*,那么重新命名之后的类型名必须要在*的右边。


函数指针也是类似的:


typedef int(*)(int,int) pf;//错误
typedef int(*pf)(int,int);//正确


了解了typedef在指针中的使用了之后,就可以对上面的两段代码进行改进了。


//代码1
(*(void (*)())0)();
//改进
typedef void(*p)();
(*(p)0)();
//代码2
void (*signal(int , void(*)(int)))(int);//类型重定义。
//改进
typedef void(*pv)(int);
pv signal(int,pv);


本节内容暂时到这里,后面还会继续更新指针进阶的内容!!如有不足,敬请指正。


相关文章
|
6天前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
29天前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
6天前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
6天前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
6天前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
12天前
|
搜索推荐
指针进阶(2)
指针进阶(2)
28 4
|
12天前
指针进阶(3)
指针进阶(3)
21 1
|
12天前
|
C++
指针进阶(1)
指针进阶(1)
29 1
|
4天前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
11 0
|
27天前
|
存储 安全 编译器
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
14 2