函数的概念
#include <stdio.h>
/*
c语言的基本组成单位:函数
函数:将一堆可能被反复使用的代码封装在一个函数内
根据传参的不同,从而计算出特定的结果。
函数封装的原则:
1.保持功能的单一性:一个函数内尽量只完成一个功能
2.可复用性:函数支持多场景下重复使用。(前提就是保证功能的
单一性)
3.健壮性强:函数外部无论如何传参,代码都可以正常运行(不发生崩溃或者影响后续代码)
*/
/*
函数的基本概念:
1.函数的定义:有具体的实现,函数实现的过程的编写
特点:全局唯一,函数名在同一个作用域内不能冲突
2.函数的声明:只有函数名,形参,返回值,没有具体的实现
特点:声明可以声明多次,没有定义也可以声明
声明的形参可以只有类型,没有变量名
用途:主要对外展示,告诉用户函数的使用说明
3.函数的调用:使用这个函数
特点:传参的个数不能多也不能少,可以进行默认类型转换
*/
/*
函数的基本组成:
函数名:遵从标识符的命名规范:
形参:形式参数,主要用于外部传参
返回值:主要用于调用处获取函数执行的结果
函数体:{}中的内容,函数具体的实现
*/
int func(int,int); //函数的声明
int func(int a, int b); //函数的声明
int func(int a, int b); //函数的声明
int main(void)
{
//函数的调用
//函数形参的传参可以传具体的值也可以传变量
//传参:100,200:实参
//传参的实质:int a = 100.99,int b = 200;
func(100, 200);
return 0;
}
//函数的定义
int func(int a, int b) //int a,int b:形参(形式参数)
{
printf("hello world!\n");
int sum = a + b;
printf("sum = %d\n", sum);
return sum;
}
#include <stdio.h>
#define ERRORYEAR 500
#define ERRORMONTH 501
#define ERRORDAY 502
#define LEAPYEAR 1000
#define COMMONYEAR 1001
/*
函数的封装方法:
1.先写函数名,返回值和参数先不管(都写成void)
2.实现函数的功能
3.实现功能的途中,某些参数必须从外部获取,
将其定义为形参。
4.根据调用出的需求,决定返回值的类型
5.对所有设计的形参进行入参判断
*/
/*
函数的传参方式:
1.值传递:传递变量的值(一般用于不需要改变
变量的值)
2.地址传递:传递变量的地址(一般用于需要修改变量的值)
*/
void InputParm(int* year, int* month, int* day);
void Swap(int* x, int* y);
void CountDays(int year, int month, int day, int* count);
void CountDiffValue(int count1, int count2, int year1, int year2, int* DiffValue);
int JudgeLegalYear(int year);
int JudgeLeapOrCom(int year);
int JudgeLegalDay(int year, int month, int day);
int JudgeLegalMonth(int month);
int main(void)
{
int year1 = 0, month1 = 0, day1 =0;
int year2 =0, month2 =0, day2 =0;
int count1 = 0, count2 = 0;
int DiffValue = 0;
//输入参数
InputParm(&year1,&month1,&day1);
InputParm(&year2, &month2, &day2);
//将较小值赋值给year1,保证year1 < year2
//JudgeLegalYear(int year);
//JudgeLegalDay(int year, int month, int day);
//JudgeLegalMonth(int month);
if (year1 > year2)
{
Swap(&year1,&year2);
Swap(&month1, &month2);
Swap(&day1, &day2);
} // year1 <= year2
//计算这一年的第多少天
CountDays(year1, month1, day1,&count1);
CountDays(year2, month2, day2, &count2);
//计算差值
CountDiffValue(count1,count2,year1,year2,&DiffValue);
printf("差值为:%d\n", DiffValue);
return 0;
}
void InputParm(int* year, int* month, int* day)
{
printf("请输入第一个日期:(以空格隔开):\n");
scanf_s("%d %d %d", year, month, day);
}
void Swap(int* x, int* y)
{
*x = *x + *y;
*y = *x - *y;
*x = *x - *y;
}
void CountDays(int year, int month, int day, int* count)
{
int ret = JudgeLegalYear(year);
if (ret == ERRORYEAR)
{
printf("[CountDays]年份输入错误!\n");
return;
}
ret = JudgeLegalMonth(month);
if (ret == ERRORMONTH)
{
printf("[CountDays]月份输入错误!\n");
return;
}
ret = JudgeLegalDay(year,month,day);
if (ret == ERRORDAY)
{
printf("[CountDays]日期输入错误!\n");
return;
}
switch (month)
{
case 12:
*count += 30;
case 11:
*count += 31;
case 10:
*count += 30;
case 9:
*count += 31;
case 8:
*count += 31;
case 7:
*count += 30;
case 6:
*count += 31;
case 5:
*count += 30;
case 4:
*count += 31;
case 3:
*count += 28;
case 2:
*count += 31;
break;
default:
break;
}
*count += day;
if (month > 2)
{
if (LEAPYEAR == JudgeLeapOrCom(year))
{
(*count)++;
}
}
}
void CountDiffValue(int count1, int count2, int year1, int year2, int* DiffValue)
{
int ret = 0;
for (int i = year1; i < year2; i++) //2000 12 31 2001 1 1
{
ret = JudgeLeapOrCom(year1);
if (ret == LEAPYEAR)
{
*DiffValue += 366;
}
else if(ret == COMMONYEAR)
{
*DiffValue += 365;
}
}
*DiffValue += count2 - count1;
if (DiffValue < 0)
{
*DiffValue = -*DiffValue;
}
}
int JudgeLeapOrCom(int year)
{
if (year < 0)
{
return ERRORYEAR;
}
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
return LEAPYEAR;
}
else
{
return COMMONYEAR;
}
}
int JudgeLegalDay(int year,int month,int day)
{
if (day < 0 || day > 31)
{
return ERRORDAY;
}
int ret;
switch (month)
{
case 4:
case 6:
case 9:
case 11:
if (day > 30)
{
return ERRORDAY;
}
break;
case 2:
ret = JudgeLeapOrCom(year);
if (ret == COMMONYEAR && day > 28)
{
return ERRORDAY;
}
else if (day > 29)
{
return ERRORDAY;
}
default:
if (day > 31)
{
return ERRORDAY;
}
}
}
int JudgeLegalMonth(int month)
{
if (month < 0 || month > 12)
{
return ERRORMONTH;
}
}
int JudgeLegalYear(int year)
{
if (year < 0)
{
return ERRORYEAR;
}
}
#include <stdio.h>
/*
函数的调用过程:
1.根据函数名找到函数的入口地址
2.根据函数的形参和函数体分配相应的空间
3.将实参传递给形参
4.执行函数体
5.返回调用处,将return后面的值带回(返回值为void忽略)
6.释放函数调用时申请的局部变量的空间
*/
/*
函数的返回值说明:
语法层面:(编译是否能通过)
1.函数的返回值(return后面的值)和返回值类型要保持一致
用法层面:
2.根据实际需要确定返回值的类型
3.调用处可以接受这个返回值,也可以不接收这个返回值
如果返回值类型为void,则不能接收返回值
4.接收返回值时,也要遵从等号左右等价一致原则。
*/
/*
示例1-1:设计一个函数,判断指定数据是否为质数?
设计流程:
函数名、形参列表、返回值类型、函数体。
函数名:IsPrimeNum
形参列表:int n
返回值类型:int
*/
/*
函数形参的说明:
输入参数:input 通常认为是只用不改的参数
输出参数: ouput 通常认为需要通过函数修改实参的值
*/
/*
日期:
作者:
功能:判断一个数是否为质数
参数:
输入参数 :
x:需要判断的数
输出参数:无
返回值:
0:表示该数为非质数
1:表示该数为质数
*/
int IsPrimeNum(int);
int main(void)
{
int ret = IsPrimeNum(19);
if (ret == 1)
{
printf("该数为非质数!\n");
}
else if (ret == 0)
{
printf("该数为质数!\n");
}
return 0;
}
int IsPrimeNum(int x)
{
if (x < 2)
{
return 1; //非质数
}
for (int i = 2; i <= x / 2; i++)
{
if (x % i == 0)
{
return 1; //非质数
}
}
return 0; //质数
}
-------------------------------------------------------------------------------------------------------
2
#include <stdio.h>
/*
示例1-2:设计一个函数,计算出从1到n之间共有多少个质数。
*/
int CountPrimeNum(int n)
{
if (n < 2)
{
return 0;
}
int flag = 0;
int count = 0;
for (int i = 2; i <= n; i++)
{
flag = 0;
for (int j = 2; j <= i / 2; j++)
{
if (i % j == 0)
{
flag = 1;
break;
}
}
if (flag == 0)
{
count++;
}
}
return count;
}
int main(void)
{
printf("请输入一个数:\n");
int n;
scanf_s("%d",&n);
int ret = CountPrimeNum(n);
printf("1 ~ %d 之间有 %d个质数!\n",n,ret);
return 0;
}
------------------------------------------------------------------------------------------------------------------------
3
#include <stdio.h>
/*
示例2:设计一个函数,忽略正负号,计算出指定数据的位数。(比如:数据若为1234,返回4)
思路:n位数数值范围是在10的n-1次方到10的n次方之间。
在原数值的绝对值的基础上,连续进行除10运算,恰好在第n次除10后,结果为0。
*/
int CountBitNum(int num)
{
int count = 0;
while (num)
{
num /= 10;
count++;
}
return count;
}
int main(void)
{
printf("请输入一个数:\n");
int n;
scanf_s("%d", &n);
int ret = CountBitNum(n);
printf("%d 的位数为 %d\n",n,ret);
return 0;
}
-------------------------------------------------------------------------------------------------
4#include <stdio.h>
/*
示例3:设计一个函数,输出1~n之间一共出现过多少个1。
比如:n = 1时,返回1;n = 10时,返回2;n=11时,返回4;n=20时,返回12。
思路:先分解出另一个函数,通过多次调用该函数,完成最终的函数。
*/
int CountOneNum(int n)
{
if (n < 1)
{
return 0;
}
int count = 0;
int temp = 0;
//用于依次判断每个数中有几个1
for (int i = 1; i <= n; i++)
{
temp = i;
while (temp)
{
if (temp % 10 == 1)
{
count++;
}
temp /= 10;
}
}
return count;
}
int main(void)
{
printf("请输入一个数:\n");
int n;
scanf_s("%d", &n);
int ret = CountOneNum(n);
printf("1 ~ %d 之间有 %d 个1\n",n,ret);
return 0;
}
------------------------------------------------------------------------------------------------------------------
#include <stdio.h>
/*
示例4:现有5分、2分和1分硬币若干,每种至少一枚,总价值为1元。
设计一个函数,指定硬币总个数为n枚,列出所有满足条件的组合。若无解,则输出无解。
*/
void CoinPlan(int n)
{
int flag = 1;
for (int i = 1; i < 20; i++)
{
for (int j = 1; j < 50; j++)
{
int k = n - i - j;
if ((k >= 1) && (i * 5 + j * 2 + k) == 100)
{
flag = 0;
printf("5分:%d个 2分:%d个 1分:%d个\n",i,j,k);
}
}
}
if (flag == 1)
{
printf("无解!\n");
}
}
int main(void)
{
printf("请输入一个数:\n");
int n;
scanf_s("%d", &n);
CoinPlan(n);
return 0;
}
----------------------------------------------------------------------------------------------#include <stdio.h>
/*
示例5:设计一个函数,计算出指定整数的二进制形式中有多少个1。
*/
int CountOneNum(int num)
{
int count = 0;
while (num)
{
printf("num = %d\n",num);
printf("ret = %d\n", num & 1);
if ((num & 1) == 1)
{
count++;
}
num >>= 1; //num = num >>1;
}
return count;
}
int main(void)
{
printf("请输入一个数:\n");
int n;
scanf_s("%d", &n);
int ret = CountOneNum(n);
printf("%d 的二进制数有 %d 个1\n",n,ret);
return 0;
}