广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言学习之函数知识总结
  • 241
分享到

C语言学习之函数知识总结

2024-04-02 19:04:59 241人浏览 独家记忆
摘要

目录前言一、引入二、认识函数三、函数的作用四、函数的返回值五、定义函数六、函数的类型七、return语句与break语句的区别八、函数的分类九、主函数十、函数使用举例十一、函数的声明

前言

函数是C语言的基本单位,学好函数有利于程序的模块化以及避免写出重复的代码从而减少代码量,并且可以提高程序的复用性与可读性。

一、引入

引例:定义6个整型变量a,b,c,d,e,f,并对它们任意赋值。分别输出a,b的最大值,c,d的最大值和e,f的最大值

#include <stdio.h>

int main()
{
    int a, b, c, d, e, f;
    
    a = 5, b = 3, c = 6, d = 87, e = 12, f = 49;

    if (a > b)
        printf("%d\n", a);
    else if (a < b)
        printf("%d\n", b);

    if (c > d)
        printf("%d\n", c);
    else if (c < d)
        printf("%d\n", d);
    
    if (e > f)
        printf("%d\n", e);
    else if (e < f)
        printf("%d\n", f);

    return 0;
}

通过观察可以发现,代码中有大量重复的部分,如果我们定义一万个变量,并两两比较求出其中的最大值,那么if...else if...else语句就要写一万次,这显然非常累赘。在编程过程中,经常会发现,虽然数据不一样,但是对这些数据的操作却是一样的,例如,引例中求a,b中的最大值与求c,d的最大值所做的操作是一样的,唯独只有被操作的数据不同而已。所以如果程序中有大量重复的作操,但只是针对的数据不一样时,我们可以通过定义函数来解决代码重复的问题。上述引例可以通过如下代码实现对应的功能:

#include <stdio.h>

void get_max(int i, int j) // 自定义的求最大值的函数
{
    if (i > j)
       printf("%d\n", i);
   else if (i < j)
       printf("%d\n", j);
   else
       printf("Equal!\n");
}

int main()
{
    int a, b, c, d, e, f;
    
    a = 5, b = 3, c = 6, d = 87, e = 12, f = 49;

    get_max(a, b);
    get_max(c, d);
    get_max(e, f);

    return 0;
}

二、认识函数

void表示该函数没有返回值,get_max是该函数的名字,函数名后括号中的变量i和j被称为该函数的形式参数(简称形参)。

void get_max(int i, int j)
{
    if (i > j)
       printf("%d\n", i);
   else if (i < j)
       printf("%d\n", j);
}

所有的语言程序的入口都是main函数,从main函数进入则开始顺序逐行执行main函数中的代码。下面代码块中定义完变量并完成赋值后,程序执行到get_max(a, b);,此时程序便会从main函数的上方查找一个名叫get_max函数并将括号中的变量a和b的值分别传输到get_max函数名后括号中的形参i和j中,然后程序会跳转到get_max函数的内部执行,待get_max函数执行完毕后,再跳转回main函数继续执行main函数中的下一条语句。

int main()
{
    int a, b, c, d, e, f;
    
    a = 5, b = 3, c = 6, d = 87, e = 12, f = 49;

    get_max(a, b);
    get_max(c, d);
    get_max(e, f);

    return 0;
}

三、函数的作用

函数是一种工具,它是能够完成特定功能的独立代码块,它不是为某个特定的问题设计的,而是为解决大量同类型的问题设计的;虽然函数处理的数据是不同的,但是对这些数据的操作是相同的;函数的使用可以避免写大量重复的代码,减少程序员的编码量;同时函数的存在有利于整个程序的模块化,函数可以将复杂的问题剖解为一个个简单的问题;函数可以被视为一个“黑匣子”,我们只需要知道某个函数的用法即可使用该函数,但我们并不一定知道该函数是怎么实现的,例如,我们虽然经常使用的printf函数,但我们并不知道其中到底是如何实现输出功能的。同样的,当我们编写函数的时候,也可以把具体实现的过程隐藏起来,因为这可能是商业机密。

四、函数的返回值

函数不仅可以接收数据,并对接收到的数据进行处理,而且也可以将数据处理的结果返回,例如下述程序:

#include <stdio.h>

int f(void) // int表示函数的返回值是int类型的值;括号中的void表示该函数不能接收任何数据
{
    return 10; // return语句表示向主调函数返回一个值
}

int main()
{
    int i = 88;
    
    i = f(); // 调用f函数后,f函数就会返回10这个数据,所以这行代码就相当于把10赋值给变量i

    printf("%d\n", i);

    return 0;
}

思考:下述程序是否正确?

#include <stdio.h>

void g(void) // 函数名前的void表示该函数没有返回值
{
}

void h(void)
{
	return 10; // 编译时如果没有调用该函数,则不会报错,一旦调用便会报错,因为h函数的返回值为空
}

int main()
{
    int i = 88;
    
    i = g(); // 由于g函数没有返回值,所以不能将其赋值给变量i,编译时会报错

    printf("%d\n", i);

    return 0;
}

五、定义函数

六、函数的类型

函数返回值的类型也称为函数的类型,如果函数名前的返回值类型与函数执行体中的return表达式的返回的类型不同,则最终函数返回值以函数名前的返回值类型为准。

思考:下述程序输出的结果是多少?

#include <stdio.h>

int f() // 如果函数名后的括号里是空的,等同于在括号里写void
{
	return 10.5;
}

int main()
{
	double x = 6.6;

	x = f();
	
	printf("%lf\n", x);

	return 0;
}

通过程序可得,变量x输出的值为10.000000,这就说明,函数最终的返回值与函数名前的返回值类型相同,而不是以return表达式为准。所以,函数的类型取决于函数名前的返回值的类型。

七、return语句与break语句的区别

break语句的作用是终止当前循环和switch语句,而return语句与break语句有本质性的差别,return语句的作用是终止当前正在执行的函数。当被调函数的返回值为空时,则直接终止被调函数然后跳回主调函数继续顺序执行主调函数中的代码;如果被调函数的返回值不为空时,则先将返回值返回给主调函数,然后再终止被调函数并跳回主调函数继续顺序执行主调函数中的代码。

思考:以下两个程序的输出结果是否相同?如果不同,这两个程序的输出结果分别是什么?

#incldude <stdio.h>

void f()
{
	for (i = 0; i < 5; i++)
	{
		printf("AAAA\n");
		break;
	}
	printf("BBBB\n");
}

int main()
{
	f();
	
	return 0;
}
#incldude <stdio.h>

void f()
{
	for (i = 0; i < 5; i++)
	{
		printf("AAAA\n");
		return;
	}
	printf("BBBB\n");
}

int main()
{
	f();
	
	return 0;
}

八、函数的分类

根据是否有形参可以将函数分为,有参函数和无参函数;根据是否有返回值可以将函数分为有返回值函数和无返回值函数;同时,也可以将函数分为库函数和自定义函数,例如,printf函数就属于库函数,因为是系统提供给我们的,而这篇文章中的get_max函数,f函数,g函数等均属于自定义函数。

九、主函数

不管一个程序中有多少个函数,但主函数(也就是main函数)只能有一个,并且main函数是整个程序的入口,也是整个程序的出口,主函数可以调用任何其他函数,其他函数之间也可以互相调用,但是其他函数不能调用主函数。

十、函数使用举例

定义6个整型变量a,b,c,d,e,f,并对它们任意赋值。分别输出a,b的最大值,c,d的最大值和e,f的最大值

要求:自定义函数并且不能与引例中的函数执行体相同

#include <stdio.h>

int get_max(int i, int j)
{
    if (i > j)
        return i;
    else if (i < j)
        return j;
}

int main()
{
    int a, b, c, d, e, f;

    a = 5, b = 3, c = 6, d = 87, e = 12, f = 49;

    printf("%d\n", get_max(a, b));
    printf("%d\n", get_max(c, d));
    printf("%d\n", get_max(e, f));

    return 0;
}

输入三个int类型的数字,并判断这三个数字是否是素数。如果是素数输出Yes,如果不是输出No

要求:使用自定义函数实现

提示:素数(又称质数)是大于1的自然数并且素数只能被1和它本身整除

#include <stdio.h>

int is_prime(int val)
{
	int i;

	for (i = 2; i < val; i++)
		if (val % i == 0)
			break;

	if (i == val)
		return 1;
	else
		return 0;
}

int main()
{
	int val1, val2, val3, i;

	scanf("%d%d%d", &val1, &val2, &val3);

	if ( is_prime(val1) )
		printf("Yes!\n");
	else
		printf("No!\n");

	if ( is_prime(val2) )
		printf("Yes!\n");
	else
		printf("No!\n");

	if ( is_prime(val3) )
		printf("Yes!\n");
	else
		printf("No!\n");

	return 0;
}

十一、函数的声明

观察可以发现,文章中所有自定义的函数都放在了main函数之上,那我们如果将自定义的函数放在main函数的下面会出现什么情况呢?如果我们在main函数中调用了自定义函数,并且将自定义的函数放在了main函数的下方,此时整个程序就会编译报错,这是因为main函数执行到调用自定义函数的语句时,它只会向上查找对应的函数,而如果在它上面没有对应的函数,程序就会出错。

思考1:下面两个程序是否可以运行?

#include <stdio.h>

int main()
{
	f();

	return 0;
}

void f()
{	
	printf("AAAA\n");
}

那如果我们要把被调函数放在主调函数之后,我们应该怎么办呢?这需要在主调函数的上方加上函数声明即可,如下程序所示:

#include <stdio.h>

void f(); // 这是函数声明,后面的分号不可以省略

int main()
{
	f();

	return 0;
}

void f()
{	
	printf("AAAA\n");
}

思考2:下面的程序是否可以运行?如果有错误应该如何改正?

#include <stdio.h>

void g(void)
{
	f();
}

void f(void)
{
	printf("AAAA\n");
}

int main()
{
	g();

	return 0;
}

十二、函数的形参与实参

形参是指定义函数时括号中定义的变量,而实参是指在调用函数时向被调函数传输的具体的数据或变量。如下代码所示,变量i就是形参,而主函数中调用f函数时在后面的括号中写的5就是实参。需要注意的是,形参和实参的个数必须是对应的,数据类型也必须相互兼容。

#include <stdio.h>

void f(int i)
{	
	printf("%d\n", i);
}

int main()
{
	f(5);

	return 0;
}

十三、合理设计函数

在掌握了以上知识之后,我们该如何设计函数让整个程序更像是开发软件?答案很简单,如果仅需要使用一次某个功能,则不需要将该功能设计成一个函数,但如果需要多次使用该功能,则设计一个该功能对应的函数是不二选择。这段话通过以下三个程序体会:

示例:输入一个int类型的数字n,求1到n之间(包括n)所有的素数并输出。不考虑输入的值小于等于1的情况

解法1:不定义其它函数,仅在main函数中实现

#include <stdio.h>

int main()
{
	int n;
	int i, j;

	scanf("%d", &n);

	for (i = 2; i <= n; i++)
	{
		for (j = 2; j < i; j++)
			if (i % j == 0)
				break;
		
		if (j == i)
			printf("%d\n", i);
	}

	return 0;
}

这样写程序虽然实现了功能,但代码的重用性非常低,比如,我们要分别判断100个不同数字从1到它本身之间的所有素数,则需要将下面的代码块重复写100次,这样就会导致代码大部分是重复的,而且代码量会显得非常大。

for (i = 2; i <= n; i++)
{
	for (j = 2; j < i; j++)
		if (i % j == 0)
			break;
	
	if (j == i)
		printf("%d\n", i);
}

考虑到要将1到n之间所有的数字都进行判断素数这一操作,所以可以单独设计出一个函数实现判断素数这个功能,从而解决代码重复的问题。

解法2:自定义一个函数实现

#include <stdio.h>

int is_prime(int val)
{
	int i;

	for (i = 2; i < val; i++)
		if (val % i == 0)
			break;

	if (i == val)
		return 1;
	else
		return 0;
}

int main()
{
	int n;
	int i;

	scanf("%d", &n);

	for (i = 2; i <= n; i++)
		if ( is_prime(i) )
			printf("%d\n", i);

	return 0;
}

相比较第一个程序,该程序更容易让人理解,代码的可重用性也得以提高,并且多次判断时所需要写的代码也相对较少,但存在的问题与第一个程序相同,如果要分别判断100个不同数字从1到它本身之间的所有素数,则需要将下面的代码块重复写100次。

for (i = 2; i <= n; i++)
    if ( is_prime(i) )
        printf("%d\n", i);

又考虑到判断完是否是素数后,输出也是重复性操作,所以同样可以将输出这一操作通过设计函数来实现。

解法3:自定义两个函数实现

#include <stdio.h>

// 本函数的功能是判断val是否是素数
int is_prime(int val)
{
	int i;

	for (i = 2; i < val; i++)
		if (val % i == 0)
			break;

	if (i == val)
		return 1;
	else
		return 0;
}

// 本函数的功能是将1到n之间(包括n)所有的素数输出
void traverse(int n)
{
	int i;

	for (i = 2; i <= n; i++)
		if ( is_prime(i) )
			printf("%d\n", i);
}

int main()
{
	int n;
	int i;

	scanf("%d", &n);
	traverse(n);

	return 0;
}

第三个程序相较前两个程序而言,代码量更少,且可重用性更高,如果需要判断多个数字并输出的话,只需要多次调用traverse函数即可实现功能,而且整个程序更容易让人理解。

总结:一个函数的功能尽可能独立单一,不要将多个功能放在一个函数中实现,这样不仅可以避免代码的重复而且还可以增加整个程序的可重用性与可读性。

十四、变量的作用域

变量按作用域划分可以分为全局变量和局部变量。

全局变量

在所有函数外部定义的变量被称为全局变量。如下程序所示,变量k就是一个全局变量,需要注意的是,全局变量只能在定义全局变量的位置之后的函数中使用,在全局变量之上的函数不能使用。

#include <stdio.h>

int k = 10;

void f()
{
	printf("%d\n", k);
}

int main()
{
	f();
	
	return 0;
}

局部变量

在函数内部定义的变量,以及函数的形参都属于局部变量。如下程序所示,f函数中的形参i以及f函数中定义的变量j都是f函数的局部变量,main函数中定义的变量i也是main函数的局部变量。除此之外,初学时可能会有这样的困惑:f函数中定义了i变量,main函数中也定义了i变量,这样程序是否存在问题?答案是不存在问题的,因为main函数中变量i只在main函数中发挥作用,而f函数中的变量i只在f函数中发挥作用,所以它们并不会起冲突,也就意味着,所有的局部变量只能在函数的内部使用,这也正是局部变量的含义。

#include <stdio.h>

void f(int i)
{
	int j = 20;
}

int main()
{
	int i = 10;

	return 0;
}

全局变量名与局部变量名冲突的问题

#include <stdio.h>

int i = 99;

void f(int i)
{
	printf("i = %d\n", i);
}

int main()
{	
	f(8);

	return 0;
}

推测1:程序中有错误,因为全局变量名与局部变量名一样,无法分辨f函数中到底是全局变量i还是局部变量i

推测2:程序无误,如果输出结果为99,则此时的变量i是全局变量;如果输出结果为8,则此时的变量i是局部变量

结果:输出结果为8

结论:如果全局变量名与局部变量名相同,则局部变量会屏蔽全局变量的存在

十五、函数内存的分配

在使用函数之前,操作系统会给函数中所有的变量分配内存空间,但当函数被执行完毕后,其中所有变量的内存均会被释放掉,等到再次使用时,会重新给函数中的变量分配内存空间。大家可以思考一下这样做的合理性。

以上就是C语言学习之函数知识总结的详细内容,更多关于C语言 函数 的资料请关注编程网其它相关文章!

--结束END--

本文标题: C语言学习之函数知识总结

本文链接: https://www.lsjlt.com/news/153895.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言学习之函数知识总结
    目录前言一、引入二、认识函数三、函数的作用四、函数的返回值五、定义函数六、函数的类型七、return语句与break语句的区别八、函数的分类九、主函数十、函数使用举例十一、函数的声明...
    99+
    2022-11-13
  • C语言学习之指针知识总结
    目录一、地址二、指针与指针变量三、指针的作用四、初学指针时常见的错误五、通过调用函数修改主调函数中的值六、指针与一维数组七、使用函数操作一维数组八、指针变量所占字节数九、静态数组的缺...
    99+
    2022-11-13
  • python基础学习之递归函数知识总结
    目录一、递归函数使用注意点二、递归的效率问题三、递归函数引入四、递归的深度五、通过缓存解决递归限制六、递归函数使用示例一、递归函数使用注意点 递归函数一定要编写终止条件,否则将产生无...
    99+
    2022-11-12
  • Spring5学习之基础知识总结
    目录1.概述2.入门Demo3.源码1.概述 1、Spring 是轻量级的开源的 JavaEE 框架 2、 Spring 可以解决企业应用开发的复杂性 3、Spring 有两个核心部...
    99+
    2022-11-12
  • c语言中main函数用法及知识点总结
    1、main函数是C程序的入口函数,即程序的执行从main函数开始,其他函数的调动也直接或间接地在main函数中调用。 2、main函数的返回值用于解释程序的退出状态。 若返回0,则...
    99+
    2022-11-12
  • R语言函数基础知识点总结
    函数是一组组合在一起以执行特定任务的语句。 R 语言具有大量内置函数,用户可以创建自己的函数。 在R语言中,函数是一个对象,因此R语言解释器能够将控制传递给函数,以及函数完...
    99+
    2022-11-12
  • C语言学习基础知识分享
    目录写在前面为何学习C语言语言层面个人层面初识C语言什么是语言标准hellowordmainprintf数据类型byte & bitsizeof常量常量分类变量定义变量变量的...
    99+
    2023-01-28
    c语言入门自学零基础 c语言入门教程 c语言入门基础知识
  • Java基础学习之字符串知识总结
    目录一、前言二、String 类(字符串常量)2.1 String 类实例的创建2.2 String 对象的比较2.3 String对象的空值2.4 字符串拼接三、StringBui...
    99+
    2022-11-12
  • C语言之函数知识点实例分析
    这篇文章主要介绍了C语言之函数知识点实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言之函数知识点实例分析文章都会有所收获,下面我们一起来看看吧。一、引入引例:定义6个整型变量a,b,c,d,e,f,...
    99+
    2023-07-02
  • Python入门学习之类的相关知识总结
    目录前言一、类的定义和使用二、类的方法三、类的属性四、类中常用特殊方法前言 Python是面向对象的程序设计(Object Oriented Programming)。 面向对象的程...
    99+
    2022-11-12
  • Python学习之内置函数总结
    目录常用函数abs 函数 演示all 函数 演示enumerate 函数 演示input 函数 演示isinstance 函数 演示vars 函数 演示hasattr 函数 演示se...
    99+
    2022-11-13
  • C语言入门学习之fgets()函数和fputs()函数
    目录fgets()函数fputs()函数总结fgets()函数 fgets()函数和gets()函数一样,都是读取字符串,不过gets()函数通常用来从键盘读取输入的字符串,fget...
    99+
    2022-11-12
  • 自学MySql内置函数知识点总结
    字符串函数 查看字符的ascii码值ascii(str),str是空串时返回0 select ascii('a'); ...
    99+
    2022-10-18
  • Java基础学习之方法的重载知识总结
    目录一、什么是方法的重载?二、构成方法重载的条件三、重点一、什么是方法的重载? 方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法。 调用时,会根据不同的参数自动匹配...
    99+
    2022-11-12
  • Java基础学习之运算符相关知识总结
    1.算术运算符 +表示加法运算符 -表示减法运算符 *表示乘法运算符 /表示除法运算符 %表示取模/取余运算符 package com...
    99+
    2022-11-12
  • Go语言数据结构之二叉树必会知识点总结
    目录前言二叉树概念二叉树的性质创建二叉树树的遍历前序遍历(V-L-R)中序遍历(L-V-R)后序遍历(L-R-V)前言 如果你是一个开发人员,或多或少对树型结构都有一定的认识,我个人...
    99+
    2022-11-11
  • Python基础之函数嵌套知识总结
    内部/内嵌函数 1、定义:在一个函数的函数体内使用关键字def关键字定义一个新的函数,这个新的函数就叫做内部/内嵌函数。 2、注意点:内部函数的整个函数体都在外部函数的作用域内,如...
    99+
    2022-11-12
  • c语言学习之数组3
    #include <stdio.h>int main(){  char cArr[] = {'I', 'L', 'O', 'V', 'E', 'C'};  char sArr[] = "ilovec";  int i = siz...
    99+
    2023-01-31
    数组 语言
  • R语言数据类型知识点总结
    通常,在使用任何编程语言进行编程时,您需要使用各种变量来存储各种信息。 变量只是保留值的存储位置。 这意味着,当你创建一个变量,你必须在内存中保留一些空间来存储它们。 您可能想存储各...
    99+
    2022-11-11
  • R语言数据重塑知识点总结
    R 语言中的数据重塑是关于改变数据被组织成行和列的方式。 大多数时间 R 语言中的数据处理是通过将输入数据作为数据帧来完成的。 很容易从数据帧的行和列中提取数据,但是在某些情况下,我...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作