首页 > 其他分享 >计算机小白的成长历程——函数(2)

计算机小白的成长历程——函数(2)

时间:2023-09-18 12:32:08浏览次数:32  
标签:调用 函数 形参 int 小白 num 实参 历程

大家好,很高兴又和大家见面了!在上一篇的内容中我们遗留了一个问题,我们在编写交换两个整型变量数值的时候不能直接编写函数,而是要将参数取地址之后再传送给函数,然后函数需要通过指针来接收,最后解引用来完成交换,可是为什么我们在正常比较大小输出最大值的时候就不用呢?这就是我们今天要探讨的问题——函数的参数。

三、函数的参数

参数的分类

1.实际参数(实参)

定义:真实传给函数的参数,叫实参。实参可以是:变量、常量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

2.形式参数(形参)

定义:形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成后就自动销毁了。因此形式参数只在函数中有效。

怎么来理解这两个参数,下面我们继续借用上一篇的例子:

//函数的参数
void swap2(int* x, int* y)//这里的x、y就是形式参数;
{
	int z = *x;
	*x = *y;
	*y = z;

}
void swap(int x, int y)//这里的x、y就是形参;
{
	int z = x;
	x = y;
	y = z;
}
int main()
{
	int a = 1;
	int b = 2;
	printf("a=%d  b=%d\n", a, b);
	swap(a, b);//这里的a,b就是实参;
	swap2(&a, &b);//这里的&a和&b就是实参;
	printf("a=%d  b=%d\n", a, b);
	return 0;
}

简单的理解就是我在调用函数时,传给函数的参数就叫做实参,在定义函数的时候,定义的参数就是形参。这里对于实参和形参的关系,我们需要了解一下:

当实参传给形参时,形参其实是实参的一份临时拷贝,对形参的修改是不会改变实参的。

有了这个结论之后我们再回过头来分析swap和swap2这两个函数:

对于函数swap来说,形参x,y就是实参a,b的一份拷贝,这里拷贝的内容是a,b的数值,所以无论怎么修改形参,对a,b本身的值都是没有影响的;

但是在swap2中形参x,y是对实参&a,&b数值的一份拷贝,这里拷贝的内容是a,b的地址,这里我们可以理解为就是把a和b的家整个拷贝了过去,在通过解引用操作符把a和b从家里给叫出来,然后再对其进行操作;

所以在swap中发生变化的是形参x,y,但是在swap2中看似发生变化的是形参x,y实际上真正发生变化的是实参a,b。

为了帮助大家更好的理解这些内容,接下来咱们继续探讨下一个内容——函数的调用。

四、函数的调用

调用函数的方式

1.传值调用

简单的理解就是将实参的值传给形参,函数的实参和形参分别占用不同的内存块,此时对形参的修改不会影响实参。

2.传址调用

●传址调用就是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。

●这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。

在上面的例子中swap就是传值调用,因为实参和形参分别占用不同的内存块,也就是它们是张三、李四、王五、赵六四个人,对形参的修改,不会影响实参,也就是对王五、赵六的修改并不会影响张三和李四两个人;

swap2就是传址调用,此时形参是创建实参的内存地址,就好比形参是张三和李四的家,此时我们对*x和*y的修改就相当于是对画了妆的张三和李四进行修改,虽然外观变了,但是实质上还是它们俩儿,所以在函数内部可以直接操作实参;

3.调用情景

我们在函数中进行的操作的对象如果是实参的值,并不会改变实参本身,那我们就可以用传值调用,也就是我们上一篇提到的比较大小找出两数中的最大值;

我们在函数中进行的操作对象如果是实参本身,在函数体内需要对实参本身进行修改,那我们就要用传址调用,也就是我们刚刚的例子,交换两整型变量的值;

4.习题演练

在前面的学习中,我们是直接在主函数中完成了这些题的内容,现在我们需要通过自定义函数来完成,以此来帮助大家增强对自定义函数的理解及调用。

(1)写一个函数可以判断一个数是不是素数;

//写一个函数可以判断一个数是不是素数
int prime_number(int x)//viod——无返回类型;prime_number——素数——函数名;x——函数形参;
{
	int a = 0;//函数体——函数如何实现;
	for (a = 2; a <= sqrt(x); a++)//sqrt——开平方——数学函数,需要调用头文件<math.h>;
	{
		if (x % a == 0)
		{
			return 1;
		}
	}
	if (a > sqrt(x))
	{
		return 2;
	}
}
int main()
{
	int i = 0;
	scanf("%d", &i);
	//判断是否为素数,只需要判断就行
	int j = prime_number(i);//i——函数实参
	if (1 == j)
		printf("%d不是素数\n", i);
	else
		printf("%d是素数\n", i);
	return 0;
}

这里我们分别输入5和50来看看结果:

计算机小白的成长历程——函数(2)_传址调用

计算机小白的成长历程——函数(2)_传址调用_02

(2)写一个函数判断一年是不是闰年;

//写一个函数判断一年是不是闰年
int leap_year(int x)//void——无返回类型;leap_year——闰年——函数名;x——函数形参
{
	if ((x % 4 == 0 && x % 100 != 0) || (x % 400 == 0))//函数体——函数如何实现;
	{
		return 1;
	}
	else
		return 0;
}
int main()
{
	int year = 0;
	scanf("%d", &year);
	//判断是不是闰年,只需要有判断的功能就行
	int a=leap_year(year);//year——函数实参;
	if (a == 1)
		printf("%d是闰年\n", year);
	else
		printf("%d不是闰年\n", year);
	return 0;
}

现在测试一下1991和2020:

计算机小白的成长历程——函数(2)_形参与实参_03

计算机小白的成长历程——函数(2)_传址调用_04

(3)写一个函数,实现一个整形有序数组的二分查找;

//写一个函数,实现一个整形有序数组的二分查找
int dichotomy(int arr[], int a, int b)
{
	int left = 0;//左侧下标;
	int right = b - 1;//右侧下标;
	while (1)
	{
		int mid = (left + right) / 2;
		if (a < arr[mid])
		{
			right = mid - 1;
		}
		else if (a > arr[mid])
		{
			left = mid + 1;
		}
		else
		{
			return mid;
		}
		if (right < left)
		{
			return 2;
		}
	}
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int k = 0;
	scanf("%d", &k);
	int sz = sizeof(arr1) / sizeof(arr1[0]);//数组元素个数;
	int result=dichotomy(arr1, k, sz);
	if (result == 2)
	{
		printf("没找到,数组里没有%d", k);
	}
	else
	{
		 printf("找到了,%d的下标是%d", k, result);
	}
	return 0;
}

下面我们输入10和11分别测试一下:

计算机小白的成长历程——函数(2)_传址调用_05

计算机小白的成长历程——函数(2)_传址调用_06

(4)写一个函数,每调用一次这个函数,就会将num的值增加1;

//写一个函数,每调用一次这个函数,就会将num的值增加1
void add(int* x)
{
	(*x)++;//操作符优先级:() > ++ > *;
	//*x++;这种编写方式,是先对x进行++再对x++进行解引用;
}
int main()
{
	int num = 0;
	//调用函数,使得num每次增加1;
	//对实参本身进行修改,这里需要用传址调用;
	add(&num);
	printf("num=%d\n", num);
	add(&num);
	printf("num=%d\n", num);
	add(&num);
	printf("num=%d\n", num);
	return 0;
}

下面我们看一下运行结果:

计算机小白的成长历程——函数(2)_传址调用_07

到这里咱们的内容就全部结束了,希望通过这几道习题能够帮助大家更好的理解形参与实参还有传址调用与传值调用的区别,接下来随着学习的深入,我会继续给大家分享我在学习过程中的感受,感谢大家的翻阅,咱们下一篇见。

标签:调用,函数,形参,int,小白,num,实参,历程
From: https://blog.51cto.com/u_16231477/7509100

相关文章

  • JAVA从小白到微服务学习路线
    JAVA基础教程开发环境搭建JAVA基础语法数据类型流程控制数组面向对象方法重载封装继承多态抽象类接口枚举常用类泛型集合泛型注解异常处理多线程IO流反射StreamAPILambda表达式计算机基础数据结构与算法数据结构与算法基础(青岛大学-王卓)数......
  • Sql中的窗口函数
    在开发过程中,经常会遇到对分数进行排名的需求,通常的写法大部分都是子查询,而窗口函数可以更加便利的进行分数排列.窗口函数窗口函数是一种在查询结果集的特定窗口或分组中计算结果的函数。它可以根据指定的排序规则和窗口范围进行计算,并返回每个行的结果。窗口函数通常与OVER......
  • 函数指针与指针函数
    int*test(inta,charb){ printf("%d\n",a);}voidtest1(inta){ printf("%d\n",a*a);}voidtest2(inta){ printf("%d\n",a*5);}intmain(){ int*(*p)(int,char)=test; p(10,'1'); return0;......
  • 纯虚函数
    首先记录下虚函数必须是非静态成员函数,访问权限是public和protected。纯虚函数在虚表中的值为0,带有纯虚函数的类为抽象类,不能实例化。抽象类的作用:在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。......
  • C语言学习记录 ----函数2
    #include<stdio.h>#include<string.h>#include<windows.h>#include<stdlib.h>#include<time.h>#include<math.h>判断素数intis_prime(intn){intj=0;for(j=2;j<=sqrt(n);j++){if(0==n%j)......
  • jQuery与Ajax:“特别的”load()方法(筛选文档、传递方法、回调函数)
    “大名鼎鼎的”jQuery因为其极简的引用方式而在N年前备受追捧,而今“浪潮”过去,还剩下什么?我认识jQuery,只是在去年接触ajax时了解,从而感兴趣,进而深入探究(其实也没多深入,只是相关的看了一下)。不得不说,jQuery对ajax支持的四个type:post(一般用于发送)、get(一般常用于接收)、put(修改)、dele......
  • 2021-6-5-stm32系统板历程
    这份笔记是我离开团队的第一份笔记不是想纪念而是想让自己明白以后要更加努力AD部分不要用中文名!!常用封装0805规格104电容代表10*10的4次方,对应是100nf105电容就是0.1ufstm32引脚OSC接外部高速晶振(8M),OSC32接外部低速晶振VDD接3.3电VSS接地VBAT就引出即可自动布线UU......
  • 学习后的顺序表(结点内容只设学号、姓名),表内采用数组,数组0位存放数据,相关的函数均按此
    #include<iostream>#include<string.h>usingnamespacestd;typedefstruct{ intid; stringname;}Node;//结点定义typedefstruct{ Node*element;//基地址(动态长度) intlength;//表长}Linklist;#defineMAXSIZE100//最大长度voidmenu();//声明菜单函数voidCreatelist(Lin......
  • 模板函数的函数参数为函数或函数对象的传参
    模板函数有模板参数和函数参数,重载调用操作符的类及函数指针作为模板参数,其函数参数及函数参数的传参,测试代码如下:#include<iostream>usingnamespacestd;//keystrings1("Hello");strings2("World");//重载了调用操作符的类其对象称为函数对象classcmp{pub......
  • 7-MySQL函数
    1.分组groupby在MySQL中,GROUPBY的意思是“分组查询”,它可以根据一个或多个字段对查询结果进行分组。GROUPBY的作用是通过一定的规则将一个数据集划分成若干个小的区域,然后针对若干个小区域进行数据处理。这可以理解为将数据按照某个字段或者多个字段进行分组。使用GROUPBY......