【进阶】C语言第三课:升级你的指针(2)
创始人
2024-04-22 22:57:19
0

目录

🍇前言🍇:

一、数组参数🤠:

        1.一维数组传参🍈:

        2.二维数组传参🍉:

二、指针参数🤩:

        1.一级指针传参🍊:

         2.二级指针传参🍒:

三、函数指针🤯:

        1.函数指针🥝:

        2.函数指针数组🍍:

四、总结🥳:


🛰️博客主页:✈️努力学习的銮同学

🛰️欢迎关注:👍点赞🙌收藏✍️留言

🛰️系列专栏:💐【进阶】C语言学习

        家人们更新不易,你们的👍点赞👍和👉关注👈真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!

        关注我,关注我,关注我,你们将会看到更多的优质内容!!!


🏡🏡本文重点 🏡🏡

🚅  数组参数  🚃  指针参数  🚃  函数指针🚏🚏

🍇前言🍇:

        有了前面的基础,在这节课中我们继续学习指针的进阶部分知识,继续向更高阶升级我们的指针,希望能对大家的学习有所帮助!

一、数组参数🤠:

        之前我们在编写【井字棋】与【扫雷游戏】时,我们发现常常会需要将【数组】或【指针】作为参数传递给函数,于是我们在复杂情况下还需要考虑函数参数的设计

        1.一维数组传参🍈:

        我们都知道,在对数组进行传参时并不会真实的在内存中创建临时数组,数组名的意义是作为数组内首元素的地址,因此当函数参数为数组名时,实际上传递的是数组中首元素的地址,于是我们可以发现下面三种传参方式都是可行的:

//方式1:标准传参方式
//完整的传递数组内容
void test1(int arr[3])
{int i = 0;for (i = 0; i < 3; i++){printf("%d ", arr[i]);}printf("\n");
}//方式2:省略数组大小
//形参部分的数组大小可以省略
void test2(int arr[])
{int i = 0;for (i = 0; i < 3; i++){printf("%d ", arr[i]);}printf("\n");
}//方式3:扩大形参数组大小
//实际仍为传递首元素地址,故可行,但不建议
void test3(int arr[100])
{int i = 0;for (i = 0; i < 3; i++){printf("%d ", arr[i]);}printf("\n");
}int main()
{int arr[3] = { 1,2,3 };//调用函数:test1(arr);test2(arr);test3(arr);return 0;
}

        这三种将形参写作数组形式的方式都是可行的,但是为了避免出现错误,推荐大家尽可能的使用第一种方式,其次是第二种方式。第三种方式虽然也可以运行,但有可能会出现难以预料的错误,不建议使用

        同时,以上三种将形式参数写成数组形式的写法,也可以改写为使用指针做形式参数的形式

//使用指针作为形式参数:
//一级指针:
void test1(int* p)
{int i;for (i = 0; i < 3; i++){printf("%d ", *(p + i));}printf("\n");
}//二级指针_形式1:
void test2(int** p)
{int i;for (i = 0; i < 3; i++){printf("%d ", *(p + i));}printf("\n");
}//二级指针_形式2:
void test3(int** p)
{int i = 0;for (i = 0; i < 3; i++){printf("%d ", **(p + i));}
}int main()
{int arr[3] = { 1,2,3 };int* parr = &arr;int arrA[3] = { 1,2,3 };int arrB[3] = { 4,5,6 };int arrC[3] = { 7,8,9 };int* arrD[3] = { &arrA,&arrA,&arrC };//调用函数:test1(arr);test2(parr);test3(arrD);return 0;
}

        并且同理,使用指针作为形式参数的另外两种形式也是可以(但最后一种方式同样不建议)的:

void test(int* p[3])
{...
}void test(int* p[100])
//可以但不建议使用
{...
}

        2.二维数组传参🍉:

        我们在前面初阶的部分学习二维数组传参时就知道了,二维数组在进行传参时可以不知道有多好行,但必须知道有多少列,这样计算机才知道应该在何时进行换行。如此只要知道了什么时候进行换行,对于行数就不需要再进行强制要求了,所以在数组进行传参时,允许写成以下三种形式:

//二维数组传参:
//方式1:标准传参
void test1(int arr[3][3])
{int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 3; j++){printf("arr[%d][%d] = %d ", i, j, arr[i][j]);}printf("\n");}
}//方式2:行数可以省略
void test2(int arr[][3])
{int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 3; j++){printf("arr[%d][%d] = %d ", i, j, arr[i][j]);}printf("\n");}
}//方式3:行数可以超出原数组上限
void test3(int arr[100][3])
{int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 3; j++){printf("arr[%d][%d] = %d ", i, j, arr[i][j]);}printf("\n");}
}int main()
{int arr[3][3] = { {1,2,3},{4,5,6},{7,8,9} };//函数调用:test1(arr);test2(arr);test3(arr);return 0;
}

        同样的,二维数组除了可以使用数组作为函数的参数以外,也可以使用指针作为函数的参数进行传参,区别于一维数组,二维数组在传参时传递的不是首元素的地址而是首行元素的地址

void test(int(*p)[3])
//此处的数组大小3为列数
{int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 3; j++){printf("%d ", (*p + i * 3)[j]);//这里注意p+(i*3)是因为i为行号,跳过行时需要跳过i*3个数据元素}printf("\n");}
}int main()
{int arr[3][3] = { {1,2,3},{4,5,6},{7,8,9} };test(arr);return 0;
}

        但是要格外注意,二维数组与一维数组不同,不可以使用二级指针进行传参。其原理是,二级指针的作用是用于存储一级指针的的地址,而传递过来的参数是二维数组第一行(这里可以简单理解为一个一维数组,但本质上不是)的地址,无法使用二级指针进行存储。

二、指针参数🤩:

        1.一级指针传参🍊:

        当我们在函数调用,并使用一级指针作为参数时,很容易理解:一级指针 p 中存放的是数组 arr 中首元素的地址,即传址做参,于是我们就可以在函数参数设计时,使用一级指针进行接收,就可以达到我们的目的。

void test(int* p)
//传递的是一级指针,存储的是arr首元素的地址,使用一级指针进行接收
{int i = 0;for (i = 0; i < 5; i++){printf("%d ", *p + i);}
}int main()
{int arr[5] = { 1,2,3,4,5 };int* p = arr;//数组名为首元素地址test(p);//等价于:test(arr);return 0;
}

         2.二级指针传参🍒:

        首先最基础的用法很好理解,无非是传递二级指针,就使用二级指针进行接收,无需过多阐述。我们直接上示例即可:

void test(int** p)
//传递二级指针,使用二级指针进行接收
{printf("%c", **p);
}int main()
{char a = 'w';char* pa = &a;char** ppa = &pa;test(ppa);return 0;
}

        作为进阶部分的知识,我们就要去研究更深层的东西。我们想一想,当函数参数为二级指针时,都可以接收什么参数?

        我们都知道,二级指针是用来存储一级指针的地址的,那么除了定义二级指针存储一级指针地址,我们在前面还学过一个知识点也是用来存储地址的——指针数组。那么指针数组可以做为函数参数进行传递吗?答案是,可以:

//指针数组做函数参数:
void test(int** p)
{int i = 0;for (i = 0; i < 3; i++){printf("%c ", **p + i);}
}int main()
{char a = 'a';char b = 'b';char c = 'c';char* arr[3] = { &a,&b,&c };test(arr);return 0;
}

三、函数指针🤯:

        1.函数指针🥝:

        我们都知道,在我们的程序中,各种值和组成成分都有自己的一片空间,我们的自定函数也不例外:

void test()
{printf("hehe\n");
}int main()
{printf("%p\n", test);printf("%p\n", &test);return 0;
}

        我们看到哪怕是我们的自定函数,也有着自己的储存空间

        那么当我们想要将函数的地址储存起来时,又该如何进行处理呢?函数指针给出了答案。其定义格式为:

🦑🦑函数返回类型( * + 函数指针名 )(函数参数类型)= 函数名;🦑🦑

        例如:

int Add(int x, int y)
{int z = x + y;return z;
}int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int ret = Add(a, b);printf("a + b = %d\n", ret);printf("\n");int(*p)(int, int) = Add;//Add函数的返回类型为int类型,函数指针名为p,两个参数类型分别为int类型、int类型printf("%p\n", p);return 0;
}

        我们很清楚的看到,通过使用函数指针就可以将函数的地址存储起来

        并且我们可以通过使用函数指针优化我们的代码,大幅度提升我们代码的可读性

🍱我们先来看一段代码:

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

🍝很明显这段代码的可读性非常差,理解起来非常麻烦,于是我们可以通过使用函数指针来提升我们代码的可读性:

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

        2.函数指针数组🍍:

        对于函数指针,同样可以使用函数指针数组存储多个函数指针

int Add(int x, int y)
{return x + y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;;
}int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int ret1 = Add(a, b);int ret2 = Sub(a, b);int ret3 = Mul(a, b);printf("ADD = %d SUB = %d Mui = %d\n", ret1, ret2, ret3);//使用函数指针从存放函数地址:int(*padd)(int, int) = Add;int(*psub)(int, int) = Sub;int(*pmul)(int, int) = Mul;//函数指针数组:int(*p[3])(int, int) = { padd,psub,pmul };//通过函数指针数组打印函数地址:int i = 0;for (i = 0; i < 3; i++){printf("指针p[%d]中存放的地址为:%p\n", i, p[i]);}//通过函数指针数组调用函数:for (i = 0; i < 3; i++){int RET = p[i](a, b);printf("%d ", RET);}printf("\n");return 0;
}

四、总结🥳:

        今天我们学习了数组参数、指针参数以及函数指针的相关知识⛵⛵,希望我的文章和讲解能对大家的学习提供一些帮助🌞🌞。各位小伙伴们下去以后可不要疏于练习喔!!!

        🔥🔥通向梦想的路上的确有一道高墙,但它只阻挡不够热爱的人!!!🔥🔥

        辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~  最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

相关内容

热门资讯

描写夏天景色的句子精选636... 描写夏天景色的句子 精选73句1. 今天真热啊!我被太阳晒得满头冒汗,我把电风扇找到,马上打开电源,...
结婚的唯美句子 关于结婚的唯美句子  1、我要怎样才能躲掉,命运的心血来潮,关于结婚的唯美句子。  2、如花美眷,似...
用还字写一个句子精选117句 用还字写一个句子 精选89句1. 人生舞台的大幕随时都可能拉开,关键是你愿意表演,还是选择躲避。能把...
含有望眼欲穿的句子精选262... 含有望眼欲穿的句子 精选120句1. 一夜高风凋碧树,凋落了记忆沧桑的羽翼。一个人淡淡地期盼,时光如...
描写春天桃花的句子 描写春天桃花的句子  灿烂的阳光照射着无边的大地,也照射着美丽的桃花,桃花又美丽又迷人。下面是小编收...
英语朋友句子精选291句 英语朋友句子 精选130句1. 真友情需要选择,不是刻意挑剔,而是淘尽黄沙始见金的沉淀,以及日久见人...
唯美爱情散文句子精选203句 唯美爱情散文句子 精选63句1. 我喜欢你七分,告诉了你三分,你喜欢我三分,却说十分喜欢我。2. 为...
适合各种心情的句子 表达心情... 适合各种心情的句子 表达心情的句子发朋友圈  在日常学习、工作抑或是生活中,大家一定都接触过一些使用...
小学生关于自嘲的句子精选47... 小学生关于自嘲的句子 精选47句1. 当你开始质疑一件事的时候,准确率总是出奇的高。2. 一倍的奢望...
人生何处不江湖下句子精选68... 人生何处不江湖下句子 精选68句1. 俗话说人生何处不相逢,只要有缘总能遇到。我真的很少来悠唐,谁知...
当谎话被揭穿了句子精选561... 当谎话被揭穿了句子 精选45句1. 半真半假的谎言是最恶毒的谎言。——德国2. 那么…就…那么有了故...
对你寒心的句子精选159句 对你寒心的句子 精选47句1. 心里难受,无比的伤感,那么想念你。2. 因为这段感情没有任何人知道,...
关于钱的英语句子精选125句 关于钱的英语句子 精选102句1. 最令人伤心的事莫过于丢钱。2. Wealth does not ...
痛恨一个人的经典句子 痛恨一个人的经典句子  一直以来,对于恨,很多人都会自然的觉得这就是爱的对立面,但是事实来看,爱的对...
唯美梦幻爱情句子 唯美梦幻爱情句子集锦  1.薰衣草无望的等待,只不过是他的宿命。  2.一首完美的节奏演绎了这个冬天...
难眠之夜的优美句子精选247... 难眠之夜的优美句子 精选92句1. 感动的情绪最难放开,心里的人最难放开。一旦爱成真,一旦人在心中。...
描写民国女人的句子 描写民国女人的句子  1. 女人们的言语里却带着怨怼,说一个摆地摊的,还穿什么旗袍?后来却一个一个跑...
好友毕业留言唯美句子简短 好友毕业留言唯美句子简短  毕业了,多么想留住那些温暖的日子,但又多么渴望着能早日投进生活的洪流,以...
英语写动物的句子少精选244... 英语写动物的句子少 精选96句1. 爱鸟护鸟是人类的美德。2. 关注候鸟,保护家园。3. xxxWe...
春天的句子 春天的句子大全  在日常生活或是工作学习中,大家都接触过比较经典的句子吧,借助句子,我们可以更好地表...