甚么!!你这麽传参是吧,好好

简介: 甚么!!你这麽传参是吧,好好

甚么!!你这麽传参是吧,好好


前言

在使用自定义函数时,会用到函数传参,今天给大家分享一下函数的传参是设计的呢??


数组参数

一维数组传参

#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);//传入指针数组的首地址
}
void test(int arr[])
{}

这个应该是容易理解的,用一个同类型的数组接收,数组名表示首元素地址,相当于把地址传过去,对该地址的元素进行处理,可以验证一下,我们可以通过test函数传参过去,对主函数中的arr[]进行修改,然后在主函数中打印出arr[]函数,如果被修改,则是传地址过去,因为test函数也没有返回值,只能是通过传过去地址修改了主函数中的arr[]函数

#include <stdio.h>
void test(int arr[])//ok?
{int i;
for(i=0;i<10;i++)
{arr[i]=10-i;
}
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//数组,
test(arr);//传入该数组的首地址
for(i=0;i<10;i++)
{printf("%d",arr[i]);
}
}

上面情况是传地址过去

void test(int arr[10])//ok?->ok的
{}

这个情况与第一个一样不管接受的数组元素是多少个,都是传地址过去

void test(int *arr)//ok?------>OK的
{}

这个也容易理解,一级指针可以接收数组的首地址,然后通过对arr+i,就是后面的地址,加1,int类型指针一次访问4个字节,对(arr+i)进行解引用操作,得到的就是对应该地址下主函数arr[]数组对应地址的那个元素,并且可以修改。

那如果是下面这个函数,阁下又应该如何对付勒??

void test2(int *arr[20])//ok?------>ok的
{}
int main()
{
int *arr2[20] = {0};//指针数组,数组里每个元素存放的是地址
test2(arr2);//传入指针数组的首地址
}

你传过去的还是地址,用指针可以接收,可是为什么不用一级指针p呢?是因为这个是一级指针数组,数组元素的元素是int呀,这个数组里存放的都是地址,你要存放一级指针数组的地址应该用个二级指针接收啊! *p只能访问到arr2[]里面的元素(地址),而不能访问到arr2[]里面的地址解引用得到的值,因为还要解引用一次,所以可以用二级指针接收。

用一级指针只能访问&b,不能得到b,如果不用二级指针的话,用一级指针数组的话是可以访问到b的。传参过去拿到的是主函数数组首地址,并没有创造一个真的数组,在test2函数里面arr[1]等于主函数arr2[1],&arr[1]等于&arr2[1],这里不要看他的类型,就把他当一个数组一样,要访问b的话解引用就行

二维数组传参

void test(int arr[3][5])//ok?------>ok的
{}
void test(int arr[][])//ok?------->不行
{}
void test(int arr[][5])//ok?------->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);
}
void test(int *arr)//ok?------->可以
{}

二维数组连续存放可以把arr[3][5]当成arr[15];

void test(int* arr)//ok?------->可以
{
    int i = 0;
    for (i = 0; i < 15; i++)
    {
        *(arr + i) = i;
    }
}
int main()
{
    int arr[3][5] = { 0 };
    test(arr);
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        int j = 0;
        for (j = 0; j < 5; j++)
        {
            printf("%d ", arr[i][j]);
        }
    }
}
void test(int* arr[5])//ok?------>不行

传地址过去,对于形参arr[0]对应的地址就是主函数arr[0][0]的地址,但是形参是int*类型的,和主函数的arr数组类型int不对应的

void test(int (*arr)[5])//ok?------>可以的

用数组指针接收二维数组在我之前的文章里面讲过

数组指针

void test(int **arr)//ok?------>不行

二级指针接收一级指针的地址,怎么能接收二维数组的地址呢?头给你打破咯哈哈哈哈哈哈哈哈哈

昨天写的很晚了,今天续上

|

|

|

指针传参

一级指针传参

#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;
}

二级指针传参

#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;
}

ptr存放一级指针p的地址,一次解引用得到p指针的内容,也就是n的地址,再解引用一次得到n.

现在有一个疑问,有指向单个类型的指针,有指向数组的指针,有指向指针的指针,有没有指向函数的指针呢????????

函数指针

看一下这个代码

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

这两个都是函数的地址,那要怎么将函数的地址存起来呢??

指针

函数指针

定义一个指针*p,这个指针的类型应该和函数的类型一样,也就是同样的参数,同样的返回类型

void (*p)();

这个就是

void test()

的函数指针,满足上面的要求。

我们可以用这个函数指针调用这个函数

#include <stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
    void (*p)()=test;//声明函数指针并初始化
    (*p)();//p存放test的地址,*p就是该函数,调用该函数一般test();所以(*p)();就可以调用这个函数
return 0;
}

果然写不下,动动发财的小手往右滑滑呗

函数指针数组

数组是存放相同类型数据的存储空间,指针数组存放的是地址,把好多函数的地址能存在什么数组里面呢???当然是函数指针数组,这个应该怎么定义呢,我们看一下函数指针 void (*p)(),这个可以存放一个数组的地址,我们把变量p换成数组的话 void (*arr[5])(),这样就可以存放5个函数的地址了。

#include <stdio.h>
void test()
{
printf("hehe\n");
}
void test1()
{
    printf("haha\n");
}
int main()
{
    void (*arr[2])() = { &test1,&test };
    (*arr[0])();
    (*arr[1])();
return 0;
}

先调用了test1();在调用了test();

总结

本文分享了数组传参,指针传参,函数指针,函数指针数组,如果哪里不对的话,求大佬多多指教,谢谢大家了,点赞的大佬offer多多!!!

目录
相关文章
|
Dart 安全 前端开发
【教程】混淆Dart 代码
代码混淆是一种将应用程序二进制文件转换为功能上等价,但人类难于阅读和理解的行为。在编译 Dart 代码时,混淆会隐藏函数和类的名称,并用其他符号替代每个符号,从而使攻击者难以进行逆向工程。
|
自然语言处理 算法 机器人
PaddleNLP通用信息抽取技术UIE【一】产业应用实例:信息抽取{实体关系抽取、中文分词、精准实体标。情感分析等}、文本纠错、问答系统、闲聊机器人、定制训练
PaddleNLP通用信息抽取技术UIE【一】产业应用实例:信息抽取{实体关系抽取、中文分词、精准实体标。情感分析等}、文本纠错、问答系统、闲聊机器人、定制训练
PaddleNLP通用信息抽取技术UIE【一】产业应用实例:信息抽取{实体关系抽取、中文分词、精准实体标。情感分析等}、文本纠错、问答系统、闲聊机器人、定制训练
|
前端开发 API
react如何进行项目配置代理
react如何进行项目配置代理
508 0
|
前端开发 大数据 数据库
🔥大数据洪流下的决战:JSF 表格组件如何做到毫秒级响应?揭秘背后的性能魔法!💪
【8月更文挑战第31天】在 Web 应用中,表格组件常用于展示和操作数据,但在大数据量下性能会成瓶颈。本文介绍在 JavaServer Faces(JSF)中优化表格组件的方法,包括数据处理、分页及懒加载等技术。通过后端分页或懒加载按需加载数据,减少不必要的数据加载和优化数据库查询,并利用缓存机制减少数据库访问次数,从而提高表格组件的响应速度和整体性能。掌握这些最佳实践对开发高性能 JSF 应用至关重要。
509 1
|
存储 缓存 安全
Java性能优化(二):Java基础-String对象及其性能优化
在深入探讨了String字符串的性能优化后,我们认识到优化字符串处理对提升系统整体性能的重要性。Java在版本迭代中,通过精心调整成员变量和内存管理机制,不断对String对象进行优化,以更高效地使用内存资源。String对象的不可变性是Java语言设计中的一个关键特性,它不仅确保了字符串的安全性,也为字符串常量池的实现提供了基础。通过减少相同值的字符串对象的重复创建,常量池有效地节约了内存空间。然而,不可变性也带来了挑战。在处理长字符串拼接时,我们需要显式使用类来避免性能下降。
384 1
Java 8 Collectors 深入解析与示例
Java 8 Collectors 深入解析与示例
316 0
|
SQL Java API
Flink(十五)【Flink SQL Connector、savepoint、CateLog、Table API】(3)
Flink(十五)【Flink SQL Connector、savepoint、CateLog、Table API】
|
安全 C++ Windows
C++调用外部应用程序的方法的整理总结(常用)
一、三个SDK函数:  WinExec,ShellExecute ,CreateProcess可以实现调用其他程序的要求,其中以WinExec最为简单,ShellExecute比WinExec灵活一些,CreateProcess最为复杂。
3454 0
|
资源调度 JavaScript 前端开发
❤Nodejs 第十五章(简单websocket聊天实现)
【4月更文挑战第15天】本文介绍了在Node.js中实现简单WebSocket聊天的过程。首先通过`yarn`创建项目并安装`ws`和`express`依赖。接着,编写`WebSocketServer.js`建立WebSocket服务器,处理客户端连接、消息收发及错误。然后,用`server.js`创建一个静态文件服务器,提供`index.html`。`index.html`包含客户端的WebSocket连接和消息处理。启动两个服务器后,可以在浏览器中打开`index.html`进行聊天。最后,讨论了在Node.js 20+Vite环境下使用WebSocket时可能遇到的问题
316 0