前言
菜鸟立个flag:希望逼迫自己把<u>C语言经典100题</u>做一遍。期望能每天在这个帖里提交一道题。
示例代码,不仅仅局限于<u> C语言经典100题</u>,还可能来自<u>明解C语言</u>的源代码
希望大家监督自己,更期待得到大佬的指点
打印日历
解法1
/*
输入起始年月和结束年月
按以下格式横排打印日历,一横排最多打印3个月
2018 / 09
日 一 二 三 四 五 六
----------------------
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
思路
1、输入起始年月和结束年月
检查结束年月是否大于起始年月
2、计算起始年月和结束年月的月份差
3、依据月份差,计算每次横向打印多少个月。依次打印9行
每个月最多需9行,3行表头,6行打印6周42天(包括空格)
打印表头某年某月、打印一周表头及分割线
依次打印每周,需传入起始年月,计算每一周的起始日
需注意第1、5、6周的打印情况
横向打印3个月后,更新起始年月、打印次数
1、宏
2、指针
3、蔡勒公式
*/
#include <stdio.h>
#include <time.h>
#define FEB 1
#define WEEK 7
#define MON 12
void get_year(int *year);
void get_mon(int *mon);
int check_valid(int syear, int smon, int eyear, int emon);
int get_mday(int *month_day, int year, int mon);
int get_wday(int year, int mon);
void put_calendar(int *month_day, int syear, int smon, int eyear, int emon);
void print_ym(int print_interval, int syear, int
smon);
void print_week_line(int print_interval);
void print_fweek(int print_interval, int syear, int smon);
void print_stfweek(int print_interval, int syear, int smon, int week);
void print_fsweek(int print_interval, int syear, int smon, int week, int *month_day);
void updtate_ym(int *mon, int *year, int interval);
int main(int argc, const char *argv[])
{
int month_day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 起始年月、结束年月
// 检测结束年月是否大于起始年月的标志
int syear, smon, eyear, emon, valid=0;
// 每月最大天数mday
// 每月的第1天是星期几wday
int mday, wday;
printf("输入开始年月:\n");
// 输入开始年月
get_year(&syear);
get_mon(&smon);
// 输入结束年月
// 检测结束年月是否大于起始年月
while (1) {
printf("输入结束年月:\n");
get_year(&eyear);
get_mon(&emon);
valid = check_valid(syear, smon, eyear, emon);
if (valid==0) {
printf("输入的结束年月小于起始年月\n");
} else {
break;
}
}
// 打印字历
put_calendar(month_day, syear, smon, eyear, emon);
return 0;
}
/*输入年*/
void get_year(int *year)
{
int res;
do {
printf("年:");
res = fscanf(stdin, "%d", year);
fflush(stdin);
} while (res==0 || *year<=0 || *year>2100);
}
/*输入月*/
void get_mon(int *mon)
{
int res;
do {
printf("月:");
res = fscanf(stdin, "%d", mon);
fflush(stdin);
} while (res==0 || *mon<=0 || *mon>12);
}
/*检测结束年月是否大于起始年月*/
int check_valid(int syear, int smon, int eyear, int emon)
{
if (syear>eyear) {
return 0;
}
if (syear==eyear && smon>emon) {
return 0;
}
return 1;
}
/*获取每月最大天数*/
int get_mday(int *month_day, int year, int mon)
{
// 判断是否闰年
if ((year%4==0 && year%100!=0) || (year%400==0)) {
*(month_day+FEB)=29;
} else {
*(month_day+FEB)=28;
}
return *(month_day+mon-1);
}
/*每月的第1天是星期几wday*/
int get_wday(int year, int mon)
{
int day=1;
if (mon==1 || mon==2) {
year--;
mon+=12;
}
return (year+year/4-year/100+year/400+(13*mon+8)/5+day)%7;
}
/*打印字历*/
void put_calendar(int *month_day, int syear, int smon, int eyear, int emon)
{
// 获取起始年月和结束年月的月份差
int period=(eyear-syear)*MON+(emon-smon)+1;
// 打印次数
int cnt=0;
// 横向排列,最多打印3个月的月历
int print_interval;
printf("\n\n%*s■□ %d年/%d月~~~~~~%d年/%d月日历 □■%*s\n\n", 15, "", syear, smon, eyear, emon, 15, "");
while (cnt<period) {
// 最后一行不足3个月
print_interval = (period-cnt>=3) ? 3 : (period-cnt);
// 打印表头某年某月
print_ym(print_interval, syear, smon);
// 打印一周表头及分割线
print_week_line(print_interval);
// 打印第1周日历
print_fweek(print_interval, syear, smon);
// 打印第2周日历
print_stfweek(print_interval, syear, smon, 1);
// 打印第3周日历
print_stfweek(print_interval, syear, smon, 2);
// 打印第4周日历
print_stfweek(print_interval, syear, smon, 3);
// 打印第5周日历
print_fsweek(print_interval, syear, smon, 4, month_day);
// 打印第6周日历
print_fsweek(print_interval, syear, smon, 5, month_day);
printf("\n");
// 横向打印完毕,统计次数
cnt+=print_interval;
// 横向打印完毕,更新下一次横向打印的年月
updtate_ym(&smon, &syear, print_interval);
}
}
/*增加多少个月后,更新年月*/
void updtate_ym(int *mon, int *year, int interval)
{
(*mon)+=interval;
if (*mon>MON) {
*mon-=MON;
(*year)++;
}
}
/*打印表头某年某月*/
void print_ym(int print_interval, int syear, int
smon)
{
int i=0;
// 横向打印表头年月,最多打印3个月
for (i=0;i<print_interval;i++) {
printf("%10d / %02d ", syear, smon);
// 横向打印一个月后,更新年月
updtate_ym(&smon, &syear, 1);
}
printf("\n");
}
/*打印一周表头及分割线*/
void print_week_line(int print_interval)
{
int i=0;
for (i=0;i<print_interval;i++) {
printf(" 日 一 二 三 四 五 六 ");
}
printf("\n");
for (i=0;i<print_interval;i++) {
printf("---------------------- ");
}
printf("\n");
}
/*打印第1周日历*/
void print_fweek(int print_interval, int syear, int smon)
{
int i;
int j;
int wday;
// 横向打印表头年月,最多打印3个月
for (i=0;i<print_interval;i++) {
// 每月的第1天是星期几wday
wday = get_wday(syear, smon);
// 打印每月第1天前面的空白
printf("%*s", 3 * wday, "");
for (j=1;j<=WEEK-wday;j++) {
printf("%3d", j);
}
printf(" ");
// 横向打印一个月后,更新年月
updtate_ym(&smon, &syear, 1);
}
printf("\n");
}
/*打印第2、3、4周日历*/
void print_stfweek(int print_interval, int syear, int smon, int week)
{
int i;
int j;
// 每2、3、4周第1天
int stfwday;
for (i=0;i<print_interval;i++) {
// 获取第2、3、周第1天
stfwday = week * WEEK-get_wday(syear, smon)+1;
for (j=stfwday;j<stfwday+WEEK;j++) {
printf("%3d", j);
}
printf(" ");
// 横向打印一个月后,更新年月
updtate_ym(&smon, &syear, 1);
}
printf("\n");
}
/*打印第5、6周日历*/
void print_fsweek(int print_interval, int syear, int smon, int week, int *month_day)
{
int i;
int j;
// 第5、6周第1天
int fswday;
// 每月最大天数mday
int mday;
for (i=0;i<print_interval;i++) {
// 获取第5、6周第1天
fswday = week * WEEK-get_wday(syear, smon)+1;
// 获取每月最大天数
mday = get_mday(month_day, syear, smon);
// 2018/9,第5周23 24 25 26 27 28 29
// 第6周30 31
mday = (fswday+6)<=mday ? (fswday+6) : mday;
// 打印第5、6周
for (j=0;fswday<=mday;fswday++) {
printf("%3d", fswday);
j++;
}
// 达到每月最大天数,空格补足
printf("%*s", 3 * (WEEK-j), "");
printf(" ");
// 横向打印一个月后,更新年月
updtate_ym(&smon, &syear, 1);
}
printf("\n");
}
解法2
/*
输入起始年月和结束年月
按以下格式横排打印日历,一横排最多打印3个月
2018 / 09
日 一 二 三 四 五 六
----------------------
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
思路
1、输入起始年月和结束年月
检查结束年月是否大于起始年月
2、计算起始年月和结束年月的月份差
3、依据月份差,计算每次横向打印多少个月。先生成日历,再打印日历
最多生成3个二维数组,用以存储横向打印的3个月
二维数组用以表示每月的日历
每个月最多需9行,3行表头,6行打印6周42天(包括空格)
每周7天需22字节,每天需3字节,最后1个字节\0
1、宏
2、指针、数组指针
3、蔡勒公式
4、三维数组
5、sprintf、strcat函数
*/
#include <stdio.h>
#include <string.h>
#define WEEK 7
#define MON 12
#define FEB 1
void get_year(int *year);
void get_mon(int *mon);
int check_valid(int syear, int smon, int eyear, int emon);
void mk_calendar(int syear, int smon, int *month_day, char (*calendar)[22]);
int get_wday(int year, int mon);
int get_mday(int *month_day, int year, int mon);
void updtate_ym(int *mon, int *year, int interval);
void print_calendar(int syear, int smon, int eyear, int emon);
int main(int argc, const char *argv[])
{
// 起始年月、结束年月
// 检测结束年月是否大于起始年月的标志
int syear, smon, eyear, emon, valid=0;
printf("输入开始年月:\n");
// 输入开始年月
get_year(&syear);
get_mon(&smon);
// 输入结束年月
// 检测结束年月是否大于起始年月
while (1) {
printf("输入结束年月:\n");
get_year(&eyear);
get_mon(&emon);
valid = check_valid(syear, smon, eyear, emon);
if (valid==0) {
printf("输入的结束年月小于起始年月\n");
} else {
break;
}
}
print_calendar(syear, smon, eyear, emon);
return 0;
}
/*输入年*/
void get_year(int *year)
{
int res;
do {
printf("年:");
res = fscanf(stdin, "%d", year);
fflush(stdin);
} while (res==0 || *year<=0 || *year>2100);
}
/*输入月*/
void get_mon(int *mon)
{
int res;
do {
printf("月:");
res = fscanf(stdin, "%d", mon);
fflush(stdin);
} while (res==0 || *mon<=0 || *mon>12);
}
/*检测结束年月是否大于起始年月*/
int check_valid(int syear, int smon, int eyear, int emon)
{
if (syear>eyear) {
return 0;
}
if (syear==eyear && smon>emon) {
return 0;
}
return 1;
}
/*每月的第1天是星期几wday*/
int get_wday(int year, int mon)
{
int day=1;
if (mon==1 || mon==2) {
year--;
mon+=12;
}
return (year+year/4-year/100+year/400+(13*mon+8)/5+day)%7;
}
/*获取每月最大天数*/
int get_mday(int *month_day, int year, int mon)
{
// 判断是否闰年
if ((year%4==0 && year%100!=0) || (year%400==0)) {
*(month_day+FEB)=29;
} else {
*(month_day+FEB)=28;
}
return *(month_day+mon-1);
}
/*生成日历*/
void mk_calendar(int year, int mon, int *month_day, char (*calendar)[22])
{
int wday=get_wday(year, mon);
int mday=get_mday(month_day, year, mon);
int i=3, j;
// 存储每天的日历,加上末尾\0,共4个字符
char tmp_day[4];
// 生成表头某年某月
sprintf(*calendar, "%10d / %02d ", year, mon);
// 生成一周表头
sprintf(*(calendar+1), " 日 一 二 三 四 五 六");
// 生成分割线
sprintf(*(calendar+2), "---------------------");
// 清除缓冲区
for (i=3; i<9;i++) {
**(calendar+i)='\0';
}
// 三维数组最多存储3个月的日历
// 9,打印每个月最多需9行,3行表头,6行打印6周42天
// 22,打印每周7天需22字节
// 打印每天需3个字节,最后1个字节\0
for (j=0,i=3;j<6*WEEK;j++) {
if (j<wday || j>=(wday+mday)) {
// 每月的第1天之前、每月最大天数
// 生成空白
sprintf(tmp_day, "%3s", "");
} else {
// 每月日期按号写入字符
sprintf(tmp_day, "%3d", j-wday+1);
}
strcat(*(calendar+i), tmp_day);
// 索引+1,等于7的倍数,表示周六,移至下一周
if ((j+1)%WEEK==0) {
i++;
}
}
}
/*打印日历*/
void print_calendar(int syear, int smon, int eyear, int emon)
{
int month_day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 计算起始年月和结束年月的月份差
int period=(eyear-syear)*MON+(emon-smon)+1;
// 三维数组最多存储3个月的日历
// 3,横向最多打印3个月
// 9,打印每个月最多需9行,3行表头,6行打印6周42天
// 22,打印每周7天需22字节
// 打印每天需3个字节,最后1个字节\0
char calendar[3][9][22];
// 计数
int cnt=0;
// 横向打印多少个月
int print_interval;
int i, j;
printf("\n\n%*s■□ %d年/%d月~~~~~~%d年/%d月日历 □■%*s\n\n", 15, "", syear, smon, eyear, emon, 15, "");
// 遍历起始年月至结束年月
// 循环判断条件不使用syear和eyear、smon和emon的比较
// 换用月份差和计数的比较,简化循环判断条件
while (cnt<period) {
// 最后一行不足3个月
print_interval = (period-cnt)>=3 ? 3 : (period-cnt);
// 生成日历
for (i=0;i<print_interval;i++) {
mk_calendar(syear, smon, month_day, *(calendar+i));
// 增加1个月份,更新年月
updtate_ym(&smon, &syear, 1);
}
// 打印日历
for (i=0;i<9;i++) {
for (j=0;j<print_interval;j++) {
printf("%s ", *(*(calendar+j)+i));
}
// 打印一行后换行
printf("\n");
}
// 横向打印月份后,换行
printf("\n\n");
// 更新计数
cnt+=print_interval;
}
}
/*增加多少个月份后,更新年月*/
void updtate_ym(int *mon, int *year, int interval)
{
(*mon)+=interval;
if (*mon>MON) {
*mon-=MON;
(*year)++;
}
}
C语言经典习题1
/*
题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
1、三位数在允许重复的情况下,有4*4*4种组合
2、筛选4*4*4种组合
剔除百十个位数字相等的组合
存入数组,并统计个数
3、格式化打印
每打印1个数字,制表符缩进
每打印5个数字,换行
打印最后一个数字,先制表符缩进,再换行
1、多重for循环
2、宏
*/
#include <stdio.h>
#define MAX_NUM 4
int main(int argc, const char *argv[])
{
// i,j,k分别存储百位、十位、个位数
int i,j,k;
// 统计次数
int cnt=0;
for (i=1;i<=MAX_NUM;i++) {
for (j=1;j<=MAX_NUM;j++) {
for (k=1;k<=MAX_NUM;k++) {
if (i!=j && i!=k && j!=k) {
printf("%d", i*100+j*10+k);
cnt++;
if (cnt%5==0) {
printf("\n");
} else {
printf("\t");
}
}
}
}
}
printf("\n总共%d种组合\n", cnt);
return 0;
}
C语言经典习题2
/*
题目:企业发放的奖金根据利润提成
利润(I)低于或等于10万元时,奖金可提10%;
利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;
20万到40万之间时,高于20万元的部分,可提成5%;
40万到60万之间时高于40万元的部分,可提成3%;
60万到100万之间时,高于60万元的部分,可提成1.5%;
高于100万元时,超过100万元的部分按1%提成
从键盘输入当月利润I,求应发放奖金总数?
1、数组
2、指针
3、逻辑运算短路效应
4、fscanf返回值检验输入是否正确、fflush函数清除缓冲区
*/
#include <stdio.h>
void get_profituser(double *profituser);
double get_sum(double profituser, int *profit, double *rate);
int main(int argc, const char *argv[])
{
int profit[7] = {0, 10, 20, 40, 60, 100, 100};
double rate[] = {0, 0.1, 0.075, 0.05, 0.03, 0.015, 0.01};
double profituser;
// 输入当月利润
get_profituser(&profituser);
// 求取奖金
printf("= %.4f (万元)\n", get_sum(profituser, profit, rate));
return 0;
}
/*输入当月利润*/
void get_profituser(double *profituser)
{
int res;
do {
printf("请输入当月利润(以万元为单位):");
res = fscanf(stdin, "%lf", profituser);
fflush(stdin);
} while (res==0 || *profituser<0);
}
/*求取奖金*/
double get_sum(double profituser, int *profit, double *rate)
{
int i;
double sum=0;
for (i=1;i<7;i++) {
// 短路效应
// 索引为6,输入利润大于100
// 利润小于或等于某个节点
// 利润减于上个节点的钱再乘以利率
if (i==6 || profituser<=profit[i]) {
sum += (profituser-profit[i-1]) * rate[i];
printf("%.3f * %.3f ", profituser-*(profit+i-1), *(rate+i));
break;
} else {
sum += ((profit[i]-profit[i-1]) * rate[i]);
printf("%d * %.3f + ", *(profit+i)-*(profit+i-1), *(rate+i));
}
}
return sum;
}
C语言经典习题3
/*
题目:一个整数,它加上100后是一个完全平方数
再加上168又是一个完全平方数,请问该数是多少?
思路
1、遍历[1, 1000]的数,逐一判断是否完全平方数
2、判断是否完全平方数,同样采取遍历
1、函数原型声明及定义
2、宏
*/
#include <stdio.h>
#define NUM 10000
int chk_square(int num);
int main(int argc, const char *argv[])
{
int num;
for (num=0;num<=NUM;num++) {
int valid=0;
if (chk_square(num+100)==1) {
valid = chk_square(num+100+168);
}
if (valid==1) {
printf("%d\n", num);
}
}
return 0;
}
/*判断是否完全平方数*/
int chk_square(int num)
{
int i;
// 以0为起点,遍历区间num的数
// 判断是否完全平方数
for (i=1;i<num;i++) {
if (num==i*i) {
return 1;
// 当遍历的数字i*i大于被检验的数字,退出循环
} else if (num<i*i) {
return 0;
}
}
}
C语言经典习题4
/*
输入某年某月某日,判断这一天是这一年的第几天?
思路
1、输入年月日
2、检查年月日是否有效
3、两种方式获取yday
mktime函数获取yday
遍历月份,加上最后一个月的天数,获取yday
1、宏
2、函数定义及原型声明
3、mktime函数
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#define LEN 20
#define FEB 1
void get_ymd(char *year, char *mon, char *day, int *month_day);
int chk_isdigit(char *ymd);
int chk_ymd(char *year, char *mon, char *day, int *month_day);
void print_msg(char *year, char *mon, char *day, int ymd_invalid);
int get_yday_mk(int year, int mon, int day);
int get_yday(int year, int mon, int day, int *month_day);
int main(int argc, const char *argv)
{
int month_day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char year[LEN];
char mon[LEN];
char day[LEN];
int yday;
// 输入年月日
get_ymd(year, mon, day, month_day);
// mktime函数获取yday
yday = get_yday_mk(atoi(year), atoi(mon), atoi(day));
printf("%s/%s/%s是这一年的第%d天\n", year, mon, day, yday);
// 遍历月份,加上最后一个月的天数,获取yday
printf("%s/%s/%s是这一年的第%d天\n", year, mon, day, get_yday(atoi(year), atoi(mon), atoi(day), month_day));
return 0;
}
/*输入年月日*/
void get_ymd(char *year, char *mon, char *day, int *month_day)
{
int ymd_invalid=0;
do {
printf("请依次输入年月日(以空格分隔):");
fscanf(stdin, "%s%s%s", year, mon, day);
fflush(stdin);
ymd_invalid = chk_ymd(year, mon, day, month_day);
print_msg(year, mon, day, ymd_invalid);
} while (ymd_invalid!=0);
}
/*检查年月日是否有效*/
int chk_ymd(char *year, char *mon, char *day, int *month_day)
{
if (chk_isdigit(year)) {
return 1;
}
if (atoi(year)<=0) {
return 2;
}
if (chk_isdigit(mon)) {
return 3;
}
if (atoi(mon)<=0 || atoi(mon)>12) {
return 4;
}
if (chk_isdigit(day)) {
return 5;
}
if (atoi(day)<=0 || atoi(day)>*(month_day+atoi(mon)-1)) {
return 6;
}
return 0;
}
/*检查年月日是否包含非数字字符*/
int chk_isdigit(char *ymd)
{
while (*ymd!='\0') {
if (isdigit(*ymd++)==0) {
return 1;
}
}
return 0;
}
/*打印年月日输入无效的信息*/
void print_msg(char *year, char *mon, char *day, int ymd_invalid)
{
switch (ymd_invalid) {
case 1:
printf("输入的年份%s含非数字字符\n", year);
break;
case 2:
printf("%输入的年份%s超出范围\n", year);
break;
case 3:
printf("输入的月份%s含非数字字符\n", mon);
break;
case 4:
printf("输入的月份%s超出范围\n", mon);
break;
case 5:
printf("输入的日期%s含非数字字符\n", day);
break;
case 6:
printf("输入的日期%s超出范围\n", day);
break;
}
}
/*mktime函数获取yday*/
int get_yday_mk(int year, int mon, int day)
{
struct tm period;
period.tm_year = year-1900;
period.tm_mon = mon-1;
period.tm_mday = day;
period.tm_hour = 0;
period.tm_min = 0;
period.tm_sec = 0;
period.tm_isdst = -1;
if (mktime(&period)==(time_t)-1) {
return -1;
}
return period.tm_yday+1;
}
/*遍历月份,加上最后一个月的天数,获取yday*/
int get_yday(int year, int mon, int day, int *month_day)
{
int i;
int yday=0;
if ((year%4==0 && year%100!=0) || (year%400==0)) {
*(month_day+FEB) = 29;
} else {
*(month_day+FEB) = 29;
}
for (i=0;i<mon-1;i++) {
yday+=*(month_day+i);
}
yday+=day;
return yday;
}