说明:
本篇记录的是自学C语言的相关过程记录,参考资料是B站郝斌老师的C语言自学教程。本人之前学过一点python,但是觉得C语言还是有必要学一下的。因为刚开始学C语言,所以本篇文章会不断更新。
因为是学习记录,所以条理可能并不是很清晰,后续感觉学的差不多的时候会重新整理一下。
P106. 函数(重点)
为什么需要函数:
- 对不同数据做相同的操作,可以减少代码量。
- 有利于程序的模块化。
- 通过C的函数与其他(C++, java, C#)等函数的学习可以理解面向过程和面向对象之间的差别。
所谓面向过程是不是就是任务分工的过程,或者说创建函数的过程?
什么叫函数:
逻辑上:能够完成特定功能的独立的代码块。
物理上:能够接收(或不接收)数据、处理(或不处理)数据并返回(或不返回)处理结果的代码块。
总结:函数是个工具,目的在于为解决大量类似问题而设计的(可以把函数当作一个黑匣子)。
如何定义函数:
格式:
函数返回值类型 函数名称 (函数的形参)
{
函数的执行体;
}
如下所示:
//如下所示,求取两个整数a和b的最大值。
void max1 (int a, int b)
{
if (a>b)
printf("%d\n", a);
else
printf("%d\n", b);
}
// 和上面不同(没有返回值),下面这个有返回值。
int max2 (int a, int b)
{
if (a>b)
return a;
else
return b;
}
// 函数第一次使用完毕,第二次使用之前,第一次调用函数所分配的内存空间会被释放(简言之,函数运行完毕,所占用的内存空间会被释放)。
函数的定义: 详细描述函数之所以能够实现某个特定功能的具体实现方法。
注意:
int f(void)
{
return 10.5; // 因为 函数返回值类型为 int,所以return返回10,而不是10.5
}
/*
注意:函数f()会返回10,因为当定义的函数返回值类型与return的返回值类型不同的时候,以定义的返回值类型为准。
*/
return
表达式的含义:
return
和break
的区别:
return
是终止函数的;
break
是终止循环的;
函数的分类:
有参函数 和 无参函数
有返回值 和 无返回值函数
库函数 和 用户自定义函数
值传递函数 和 地址传递函数
普通函数 和 主函数(main)
一个程序必须有且只有一个主函数,主函数可以调用普通函数,但是普通函数不能调用主函数;
普通函数之间可以互相调用;
主函数是程序的入口;
举例:判断一个数字是否为素数?
# include <stdio.h>
# include <stdbool.h> // 导入 bool 类型
/*
判断一个数是否为素数(只能被1和本身整除,比如2,3,5,7,11...)
所用到的知识点:
1. for 循环
2. if .. else ...
3. scanf() 注意要使用 取地址符 &
4. printf()
5. do ... while ...
6. 主函数 与 普通函数
7. break
*/
bool IsPrime(int x) // 输入任意正整数 i
{
int i; // 从2到x-1,如果其中有任意值能把 x 整除,那么就不是素数;否则是素数
for (i=2; i<x; ++i)
{
if (x%i == 0)
break;
}
if (i == x) // 如果是素数,那么i是可以加到x的(就是说i=x);否则i<x
return true;
else
return false;
}
int main(void)
{
int x; // 输入任意正整数x
char ch; // 判断是否继续执行IsPrime()
do
{
do
{
printf("输入任意大于等于2的正整数:");
scanf("%d", &x);
if (x<2)
printf("\n输入错误,请重新输入!\n");
} while (x<2);
if ( IsPrime(x) ) // 如果是素数,那么IsPrime()函数的是 true
{
printf("整数 %d 是素数。\n", x);
printf("\n");
}
else
{
printf("整数 %d 不是素数。\n", x);
printf("\n");
}
printf("是否要继续(Y/N):");
scanf(" %c", &ch);
} while ( 'y'== ch || 'Y' == ch );
return 0;
}
函数的声明:
程序由上往下执行,一般来说普通函数要放到main函数上面(或者说main函数放到最后);如果确实想把main函数放在上面而普通函数放在下面,那么需要在开头加上函数声明。如下所示:
# include <stdio.h>
void f(void); //函数声明,分号不能丢掉。
int main(void)
{
f();
return 0;
}
void f(void)
{
printf("哈哈!\n");
}
函数声明需要注意的问题:
- 告诉编译器即将可能出现的若干个字母代表的是一个函数;
- 告诉编译器即将可能出现的若干个字母所代表的函数的形参和返回值的具体情况;
- 函数声明是一个语句,末尾必须加分号;
- 对库函数的声明是通过
# include <库函数所在的文件名.h>
来实现的。
函数相关的需要注意的问题:
- 普通函数的功能尽量要单一;
- 如果该函数没有参数,那么一定要加上
void
(写的更规范);- 函数调用和函数定义的顺序(如果函数调用写在了函数声明前面,那么必须加上函数声明。注意不要忘加分号)。
函数的形参和实参:
void f(int i) // 这里的 i 就是形参 { printf("%d\n", i); } int main(void) { f(5); // 这里的 5 就是 实参 return 0; }
形参和实参需要注意的点:
- 实参和形参的个数要相同;
- 实参和形参的位置要一一对应;
- 实参和形参的数据类型要兼容;
如何在软件开发中合理地设计函数来解决实际问题:
- 函数的功能尽量独立单一(便于提高代码的可重用性);
- 注意函数的使用,提高代码的模块化和可读性;
举例:列出一定范围内所有的素数:
思路和之前判断素数的一样,只不过这个是遍历该范围内的所有数字,然后逐个判断而已。
# include <stdio.h>
# include <stdbool.h> // 导入 bool 类型
/*
输出一个范围内的所有素数;
输入:一个大于等于2的正整数;
输出:从2开始到该输入数字结束,他们之前所有的素数。
*/
// 本函数功能是判断是否为素数
bool IsPrime(int x)
{
int i;
for (i=2; i<x; ++i)
{
if (x%i == 0)
break;
}
if (i == x)
return true;
else
return false;
}
// 本函数的功能是把1-n之间的所有的素数输出到屏幕
void TraverseVal(int n)
{
int i;
for (i=2; i<=n; ++i) // 遍历 2到n之间的每一个数字
{
if ( IsPrime(i) ) // 判断这些数字是否是素数
printf("%d\n", i);
}
}
// main函数
int main(void)
{
int x; // 输入任意正整数x
printf("请输入任意大于等于2的正整数:");
scanf("%d", &x);
TraverseVal(x);
return 0;
}
常用的系统函数:
double sqrt(double x); 求平方根
int abs(int x); 求x的绝对值
double fabs(double x); 求x的绝对值
关键在于理解这种系统函数的格式:
返回值类型 函数名称(形参的数据类型 形参);
递归(暂时不学,学完数据结构再返回来看这个):
栈、递归、数据结构。