0
点赞
收藏
分享

微信扫一扫

关于函数的初学【1】 形参与实参

求阙者 2022-03-26 阅读 90
c语言

// memset 函数 strcpy()函数 
// memset - memory (计算机中翻译成内存)  set (设置)  value是值的意思 block of memory (内存块)  fill block of memory (设置内存块)  memset()函数中不可以塞字符进去
// 任何的字符在存储到内存的时候其实存的是它的ascii码值,仍然是以数据的形式存储   parameter(参数)
// 对于程序员而言更加重要的是自定义函数,自己来创造函数
// 自定义函数的基本组成分为四个 分别是函数名,函数的返回类型,函数的参数,以及最重要的函数的实现部分
如:

ret_type fun_name (paral,*)
{
    statement;  //这里就是语句项
}

整个大括号括起来的就是函数体,函数体交代的是函数的实现
ret_type 返回类型
fun_name 函数名
paral 函数参数

函数实例之比大小:

#include <stdio.h>

int(函数的返回类型) get_max(函数名)(int x, int y) 
//不管参数的形式是怎样的,只要放对了参数函数就会开始执行
//里面是函数的参数,注意参数的书写形式是参数的类型+参数名)
{
	if (x > y)
		return x;//在函数体中实现功能后要将结果返回,返回的类型在函数名的左边)
	else
		return y;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d",&a,&b);
	int max = get_max(a,b);  //引用函数的格式是函数名(输入对应的参数),用了函数后得到的是函数的返回值,既然返回的是值,自然也要设置一个变量来存
	printf("max=%d",max);
	return 0;
}

如何实现两个变量内容的交换呢? 关键点就在于引入第三个变量来解决计算机逻辑下的变量替换问题:

#include <stdio.h>
int main()
{
    int x = a;
    int y = b;
    //当我们要实现x,y内容的交换时,如果直接写 x=y y=x ,那么我们只能得到错误的答案
    //这是因为在计算机的逻辑语言下, x被赋值为y时,x=y ,y再被赋值为x时就有 x = y = y
    //因此无法实现内容交换,如果想解决这个问题就必须引入一个新的变量来存储
    int temp = x; // 此时 temp = x = a
    x = y;
    y = temp;
    //完美实现内容交换
    return 0;
}

练习:以函数形式来实现

#include <stdio.h>
int exchange (int x, int y)
{
    int temp = x;
    x = y;
    y = temp;
    printf("x = %d y = %d",x,y);
    return x;
    return y;
}
int main()
{
    int x = 10;
    int y = 100;
    exchange(x,y); 
// 函数可以直接输入后加上参数使用
// 函数的作用是用来实现某一功能,当然包括打印等等
// 函数的返回值可以有很多个 ,而函数的返回类型只有一个
// 函数不一定需要返回值!!! 没有返回值也就没有返回类型 ,至于是否要返回值则取决于函数的功能
// 比如此代码需要的功能是交换,并不需要它返回什么,所以可以直接删除返回值和返回类型
// 如果函数没有返回值时,要将被删掉的返回类型换为 void - 空白,虚无
    return 0;
}

函数根据功能判断是否需要返回值和返回类型,所以本代码修改如下

(取地址符号 & 就是取出对应变量存放空间的变量)

#include <stdio.h>
void exchange (int x, int y) //没有返回类型要改为 void - 空白 ,虚无
{
    int temp = x;
    x = y;
    y = temp;
    printf("x = %d y = %d",x,y);
}
int main()
{
    int x = 10;
    int y = 100;
    exchange(x,y);
    return 0;
}

监视代码块中的语句运行时,用快捷键 f10 就行

而监视函数块中的语句运行时,要用快捷键 f11

另外变量声明必须得放在代码块的最前面,不能有非变量声明的语句在它们前面

关于上面的这个交换函数有一个很容易出错的地方,如下:

#include <stdio.h>
void exchange (int x, int y)
{
    int temp = x;
    x = y;
    y = temp;

}
int main()
{
    int a = 10;
    int b = 100;
    exchange(x,y);
    printf("a = %d b = %d",x,y);
//如果不将printf写在函数里而是写在代码块中的话我们是无法实现交换的功能
//至于原因则是因为存储地址的改变
    return 0;
}

//在代码块中 x分得一个内存空间,活得地址1 ,y同理获得地址2
//而当我们在函数中输入参数时,函数又会自动申请新的内存空间来存储参数 
//比如上面那一行代码实际上是 x = a = 10 ; y = b = 100 ,x将10存在自己的内存空间,a也将10存在自己的内存空间 ,y和b同理;
//根据上面这一步操作导致我们实际交换的是x和y的值,而非a和b的值 !!!
//那么如何实现交换功能呢 ,答案就是直接在函数块中实现打印功能,且打印的数据得是x和y的数据
//因为我们实际交换的是x和y的值,而非a和b的

其实上面这个将printf交给函数来实现的方法是一种伪交换,因为其本质上是x和y在交换而非a和b在交换,那么我们该怎么实现真交换呢? 

方法很简单,就是直接用指针变量存地址后,再通过解引用指针变量来实现变量的跨代码块使用

首先我们介绍一下指针变量

#include <stdio.h>
int main()
{
    int a = 10; 
//我们在这里创建一个变量,并申请一个内存空间来存储这个变量
//同时这个内存空间具有独属于它的地址
    int* pa = &a;
//在这里我们用取地址符号 & 获取a的地址后,有&a = a的地址
//而用来存放的地址的变量 pa(这只是一个变量名) 就是指针变量,且指针变量的类型是 int* 
//创建变量时都要声明它的类型!
//此时指针变量pa中存放的就是存放变量a的内存空间的地址了
    printf("%d",*pa);
//指针变量的一个重要作用就是被我们进行解引用操作
//所谓解引用操作其实就是将指针变量变为它所存储的地址对应的内存空间中存的变量
//如 *pa = a  ps : 解引用的格式是 *指针变量名
    return 0;
}

有了指针变量后我们就可以通过地址来调用变量了

#include <stdio.h>
void exchange(int* pa , int* pb)
{
    int tmp = 0;
    tmp = *pa; 
//解引用后 *pa是一个变量,且*pa是一个和a数值相等,地址相同的变量
//没错,*pa就是a本身
    *pa = *pb;
    *pb = tmp;
}
int main()
{
    int a= 10;
    int b = 100;
    exchange(&a , &b);
    printf("a=%d b=%d",a,b);
    return 0;
}

//关于函数的参数传递,以上面的代码块中的exchange()和函数中的 void exchange(int* pa,int* pb)为例
//我们在代码块中输入exchange(&a,&b);这一行语句的意思其实是在告诉电脑执行传递参数的命令
//那么这个参数传递到了哪了呢? 答案是传递到了我们在创建函数时写在括号里面的 ”参数“ 
//其实我们创建函数时写”参数“这一行为的本质也是在创建变量,而这个创建的变量是用来接收从代码块中传来的参数的
//如本代码中我们传递的是地址,所以写参数时要用指针变量来接收地址
//对地址解引用之后得到的就是地址对应的内存空间中存放的变量

这样我们就能够实现真正的交换了

ps:如果我们不再函数块中实现打印功能(注意是打印已经交换的x和y)而是在代码块中打印呢?

即在代码块中直接输入   printf("a = %d b = %d",x,y);  呢?

答案是仍然无法打印正确结果,这是因为 x 和 y变量是在局部变量,生命周期是从函数块运行开始到运行结束,如果在代码块中使用x和y的话,则x和y是未声明变量!

总结 :

创建函数时, 函数类型 函数名 (函数参数) 

这里面这个函数参数是我们真真切切创建的局部变量,生命周期是从函数块运行开始到运行结束

所以当我们在代码块中引用函数参数时会得到 报错 - 未声明的标识符 (函数参数的生命周期已经结束了,他又回归了 ” 0 “ 想再使用它时我们必须重新声明)

当我们在代码块中输入参数时,其实就相当于给函数参数赋值而已 

其实上面的问题总结起来就是函数的实际参数和形式参数的问题

函数的实际参数:(实参)

实参是真是传递给函数的参数,它可以是常量,变量,表达式(注意是表达式而不是判断式,表达式是300+1 22*2这种 ,而判断式则是 a>=100这种,不能传判断式只能传表达式),函数等。并且实参必须在具有确定的值后才能够被传递,如果没有确切的值是不能被传递的。

ps: 关于实参可以是函数这一条,必须要求这个作为实参的函数具有确定的返回值才行,也就是说这个函数是已经求解出来的函数

总之无论如何实参都必须得是确定的值

函数的形式参数:(形参)

形式参数是函数名后括号内的变量,因为形参只有在函数被调用的过程中才实例化(即分配内存空间),当没别被函数调用时,形参就是一些无作用的符号,所以叫形式参数。形式参数当函数调用完成之后就自动销毁,因此形式参数只在函数中有效

#include <stdio.h>
void exchange(int* pa , int* pb)  //指针变量pa , pb就是形参
{
    int tmp = 0;
    tmp = *pa; 
    *pa = *pb;
    *pb = tmp;
}
int main()
{
    int a= 10;
    int b = 100;
    exchange(&a , &b); // &a , &b就是实参
    printf("a=%d b=%d",a,b);
    return 0;
}

// 实参赋予给形参,形参在函数中被调用,用完后自动销毁,所以形参只能在函数中使用

总结:当实参传给形参的时候,形参只是实参的一份临时拷贝,对形参的修改不会影响到实参

但是当我们取地址的时候我们是在直接对实参进行修改

举报

相关推荐

0 条评论