int Add_Int(int a , int b); //这个是函数的声明
z = Add_Int (int x , int y); //这个函数的调用是错的,不应该加int ,正确写法:z = Add_Int(x ,y);
int Add_Int(int a , int b) //这个是函数的定义,不加分号
只有函数在被调用,局部变量,形参才在栈区
int Maxint(int a, int b) // 形参
{
int c = a > b ? a : b;
return c; // 返回c的值的同时,把函数结束,把分配给函数的栈帧返回给系统但不是把c给max,而是把c的值放入到临时空间中去
}
int main()
{
int x = 0, y = 0;
int max = 0;
scanf("%d %d", &x, &x);
max = Maxint(x, y); //实参
printf("max = %d\n", max);
return 0;
}
把实参给形参是从右想左赋值,也就是先把y的值赋给b,再把x的值赋给a
举例子:要求从键盘中输入年份的整数year,通过程序判断该年是否为闰年
判断year年份是否是闰年,需要满足以下条件中的任意一个
1 该年能被4整除,同时不能被100整除
2 该年份能被400整除
函数写法:
法一:由于不是闰年就是平年,故只有两种可能,因此用bool型
bool Isleap(int year)
{
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
return true;
}
else
{
return false;
}
}
这个是双分支,改成单分支为:
bool Isleap(int year)
{
bool res = false;
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
res = true;
}
return res;
}
但是if 中本身也是bool值,故还可以简化
bool Isleap(int year)
{
return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
}
例二:输入year和month ,返回天数
上面写了平年和闰年的函数
bool IsLeap(int year)
{
return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
}
int Get_YM_Day(int year, int month)
{
int day = 0;
switch (month)
{
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
day = 31;
break;
case 4: case 6: case 9: case 11:
day = 30;
break;
case 2:
day = IsLeap(year) ? 29 : 28;
break;
}
return day;
}
int main()
{
int year, month, day;
scanf_s("%d %d", &year, &month);
day = Get_YM_Day(year, month);
printf("year : %d month :%d day : %d", year, month, day);
return 0;
}
但这种的健壮性不强,为什么呢?因为当月份输入是18时,显示为0,但实际上并没有18月,因此要对函数的合法性进行检测,怎么改呢?下面是更准确的写法
#define YEARERROR -1
#define MONTHERROR -2
bool IsLeap(int year)
{
return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
}
int Get_YM_Day(int year, int month)
{
int day = 0;
if (year < 1) return YEARERROR;
if (month < 1 || month > 12) return MONTHERROR;
switch (month)
{
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
day = 31;
break;
case 4: case 6: case 9: case 11:
day = 30;
break;
case 2:
day = IsLeap(year) ? 29 : 28;
break;
}
return day;
}
int main()
{
int year, month, day;
scanf_s("%d %d", &year, &month);
day = Get_YM_Day(year, month);
switch (day) //在这里做一个判断
{
case YEARERROR :
printf("year input error : %d\n", year);
break;
case MONTHERROR :
printf("month input error : %d\n", month);
break;
default:
printf("year : %d month :%d day : %d", year, month, day);
break;
}
return 0;
}
判断日期是否正确可以这样写:
if(day < 1 || day > Get_YM_Day(year , month)) return DAYERROR;
意思就是如果天数小于1或者天数大于上面函数输入年月后得到的天数时,就会返回天数错误
传递数值
void Swap_i(int a, int b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int x = 10, y = 20;
printf("%d %d \n", x, y);
Swap_i(x, y);
printf("%d %d\n", x, y);
return 0;
}
得到输出的结果是
因为从主函数开始执行时,给main函数分配栈帧,再调用Swap_i 函数时分配栈帧,把实参的值给形参,即把y的值给 b ,x 的值 给a 。然后把a的值给tmp ,把b的值给a 再把tmp的值给b,但实参在另一个栈帧中,并不变,即此时输出的x仍是10,y 仍是20
传递地址 (什么类型的指针就存放什么类型变量的地址)
void Swap_i(int *ap, int *bp)
{
int tmp = *ap;
*ap = *bp;
*bp = tmp;
}
int main()
{
int x = 10, y = 20;
printf("%d %d \n", x, y);
Swap_i(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
结果为
当解析*p时,系统的第一步先读取p的值,p也就是a的地址,下一步就通过这个地址去访问a
从主函数开始执行,给主函数分配栈帧,x 的值为 10 ,10的十六进制就是0a,由于是小端存储,因此为0a 00 00 00,在调用函数时,把y的地址给bp,再把x的地址给ap,当进入到函数时,把*ap也就是x本身的值给tmp,因此tmp为 0a 00 00 00 再把*bp 也就是y本身给*ap 也就是x本身,相当于把y的值给了x,接下来再把tmp的值给*bp ,即把tmp的值给了y,因此此时输出的是x = 20,y=10;
形参 实参
c语言中不允许在函数中再定义函数
函数在调用时,先把实参的值传递给形参,之后函数开始正式调用
函数调用时发生的数据的传递是单向的,只能把实参的值传递给形参,而不能把形参的值反向传递给实参
两个例题:
1 、a , b , c 三个数找出其中最大值
int Max_Int(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int a = 0, b = 0, c = 0;
int max = 0;
scanf("%d %d %d", &a, &b, &c);
max = Max_Int(Max_Int(a, b), c); //在这里调用了两次函数,简洁了许多
printf("max = %d\n", max);
return 0;
}
2 、a , b , c 三个数找出其中间值
void Swap_p(int* ap, int* bp)
{
int tmp = *ap;
*ap = *bp;
*bp = tmp;
}
int Mid_Int(int a, int b, int c)
{
if (a > b)
{
Swap_p(&a, &b);
}
if (b > c)
{
Swap_p(&b, &c);
}
if (a > b)
{
Swap_p(&a, &b);
}
return b;
}
int main()
{
int a = 0, b = 0, c = 0;
int mid = 0;
scanf("%d %d %d", &a, &b, &c);
mid = Mid_Int(a, b, c);
printf("mid = %d\n", mid);
return 0;
}