函数(function)可以翻译为子程序;函数就是一个完成某项特定任务的代码
库函数:
C语言规定了语法(功能,名字,参数,返回值),C语言不规定库函数,ANSIC规定了一些函数的标准,叫做标准库。标准库里的函数叫做库函数,printf,scanf都是库函数。
if,switch,for等等,数组,函数
打印:printf
输入:scanf
求字符串长度:strlen
函数的使用要包含相应的头文件
自定义函数
自定义函数更加重要,给程序员写代码提供更多的创造性
返回值类型(int double) +函数名+(形式参数)+函数体{ }
如果有参数,要交代参数的类型,名字和个数
函数的名字要根据函数功能起有意义的,void表示函数没有参数。函数体是完成计算的过程。
写一个加法函数,完成2个整型变量的加法操作
#include <stdio.h>
int main()
{
int a=0;
int b = 0;
scanf_s("%d %d", &a, &b);
int c = a + b;
printf("%d", c);
return 0;
}
调用函数
• return后边可以是⼀个数值,也可以是⼀个表达式,如果是表达式则先执⾏表达式,再返回表达式的结果。
#include <stdio.h>
int Add(int x, int y)【形式参数-形参】
{
int z = x + y;
return z;//返回计算的和
//也可以直接是 return x+y
}
int main()
{
int a = 0;
int b = 0;
scanf_s("%d %d", &a, &b);//输入
int c = Add(a, b);//计算 调用Add函数完成a+b;【实际参数-实参】
printf("%d", c);//输出
return 0;
}
在VS上面调试的时候,F10可以一步步执行代码
F11可以进入函数
函数也分为实参(真实传递)和形参
当函数调用的时候,实参传递给形参的时候,形参将会创建自己的空间来存放实参的值
形参和实参不在同一块空间;
形参的修改,不会影响实参
可以理解为:形参是实参的临时拷贝
return语句
• return后边也可以什么都没有,直接写 return; 这种写法适合函数返回类型是void(无参数//不会返回任何值)的情况。
#define CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void test()//函数的返回类型是void,这个函数不会返回任何值
{
printf("haha\n");
}
int main()
{
test();
return 0;
}
return语句执行后,函数就彻底返回,后边的代码不再执行
#define CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void test()
{
printf("haha");
int a = 0;
scanf_s("%d", &a);
if (a == -1)
return;//提前返回
printf("xixi");//a==-1就没有打印的机会
}
int main()
{
test();
return 0;
}
return返回的值和函数返回类型不⼀致,系统会自动将返回的值隐式转换为函数的返回类型。
#define CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int test()//整型
{
printf("haha");
int a = 0;
scanf_s("%d", &a);
if (a == -1)
return 3.14;
else
return -3.14;//浮点数
printf("xixi");
}
int main()
{
int r = test();
printf("%d\n", r);
return 0;
}
• 如果函数中存在if等分支的语句,则要保证每种情况下都有return返回,否则会出现编译错误。
#define CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int test()//整型
{
printf("haha");
int a = 0;
scanf_s("%d", &a);
if (a == -1)
return 4;//没有写清楚a!=-1时会有什么情况
}
int main()
{
int r = test();
printf("%d\n", r);
return 0;
}
• 函数的返回类型如果不写,编译器会默认函数的返回类型是int。
最终返回的值是不确定的。
• 函数写了返回类型,但是函数中没有使用return返回值,那么函数的返回值是未知的。
设计函数返回的时候:
1.如果函数执行的结果,需要返回给主调函数,函数要设计返回值
2.根据要返回的值,来设计返回的返回值类型
3.如果函数不需要返回值,那么写void
数组做函数参数
在使用函数解决问题的时候,可以将数组作为参数传递给函数,在函数内部对数组进⾏操作。形参和实参的名字可以相同
练习:
写⼀个函数将⼀个整型数组的内容,全部置为-1,再写⼀个函数打印数组的内容。
#include <stdio.h>
void set_arr(int arr2[10], int sz2)
//形参和实参的名字可以相同,arr2看似创建了新数组,其实并没有,是同一个数组,所以【】里面的大小可以省略
{
for (int i = 0; i < sz; i++)
{
arr2[i] = -1;//设置为-1
}
}
void printf_arr(int arr[10], int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//打印数组
}
printf("\n");
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);//元素个数
printf_arr(arr, sz);
//先把数组打印一遍(下标为10的元素)
set_arr(arr, sz);
//实参设置了两个,在形参也要设置两个,函数的形式参数要和函数的实参个数匹配,数组传参的时候本质上传递的是地址
//写一个函数把数组内容设置为-1
printf_arr(arr, sz);//打印数组的内容
return 0;
注意:
•函数的形式参数要和函数的实参个数匹配
• 函数的实参是数组,形参也是可以写成数组形式的
• 形参如果是一维数组,数组大小可以省略不写
• 形参如果是二维数组,行可以省略,但是列不能省略
• 数组传参,形参是不会创建新的数组的
• 形参操作的数组和实参的数组是同⼀个数组
嵌套调用和链式访问
练习:
写一个函数计算某年某月有多少天
int is_leap_year(int y)//调用函数
{
if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))//判断闰年
return 1;
else
return 0;
}
#include <stdio.h>//调用函数
int get_days_of_month(int y, int m)
{
int days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day = days[m];
if (is_leap_year(y) && m == 2)
day += 1;//闰年的2月要再加一天
return day;
}
int main()
{
int y = 0;
int m = 0;
scanf_s("%d %d", &y, &m);
int d = get_days_of_month(y, m);
printf("%d\n", d);打印
return 0;
}
static
static和extern都是C语言中的关键字
生命周期:创建到销毁的时间段
作用域:一个变量在哪里被使用,哪里就是他的作用域
static是静态的意思:
1.修饰局部变量(作用域:变量存在的局部范围)(出了作用域生命周期结束)
2.修饰全局变量(作用域:整个工程(项目))(整个程序的生命周期)
3.修饰函数
4.static修饰局部变量改变了变量的生命周期,生命周期改变的本质是改变了变量的存储类型,一个局部变量是存储在内存的栈区的,但是被 static 修饰后存储到了静态区。存储在静态区的变量和全局变量是一样的,生命周期就和程序的生命周期⼀样了,只有程序结束,变量才销毁,内存才回收。但是作用域不变的。
【栈区:局部变量,函数形参
静态区:全局变量,静态变量】
static修饰局部变量
因此未来一个变量出了函数后,还想保留值,等下次进入函数继续使用,就可以使用static修饰
这是static修饰全局变量
#include <stdio.h>
int gal=2024;//作用于整个程序//全局变量
void test()
{
printf("2.%d\n",gal);
}
int main()
{
printf("1.%d\n",gal);
test();
return 0;
}
把全局边量写在两个文件里面如何实现呢
创建两个源文件
extern用来声明外部符号的
打开两个源文件,长按其中一个源文件拖着悬停,接着进行编译运行
我们可以发现使用extern,就能实现在两个源文件里面运行
加上static之后代码的运行情况:
加上static之后全局变量的范围变小了,作用域变小了,生命周期没有发生改变
全局变量是默认有外部链接属性的
⼀个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使⽤。
使用建议:未来⼀个变量出了函数后,我们还想保留值,等下次进入函数继续使用,就可以使用static修饰。
static修饰函数
跟前面static修饰全局变量一样,当一个函数在整个工程都可以使用,但是被static修饰后,只能在本文件内部使用,其他文件无法正常的链接使用了。
因此一个函数只想在所在的源文件内部使用,不想被其他源文件使用,就可以使用 static 修饰