历年真题笔记

一、写C语言表达式

2016

在这里插入图片描述

注意是n的取值引起不同,而不是f(n) 即是n==1而不是f(n)==1 。答:f(n)= (n==1)? 2: 2nf(n-1);

2019

在这里插入图片描述

  • 第二题:注意题目是四位数的百位而不是十位。即要除以100在取模,而不是除10取模,如此得到的是十位
  • 第四题:注意fget函数参数有三个,关于文件操作函数的参数要记住。==str = fgets(str,10,fp)

2021

在这里插入图片描述

特别注意第二题题目表述,讲的是后三个条件满足两个,而不是四个条件满足两个,平均分一定要大于85

2022

在这里插入图片描述

总结:

近年更倾向于文字描述概念,注意提防文字所问细节,如几个条件满足几个,和或。与或,条件加法,还有早年的三元表达式也注意



二、写表达式的值

2022

  • 涉及两个之前从未涉及的重点问题
    在这里插入图片描述

第二题的与或的短路现象,括号括起看是否存在短路
第三题的逗号表达式优先级最低,强制转换丢失精度问题,两者都是最容易忽略的点。

拓展:

	int x=2,y=-1;
	x = (x, y = 0.5, 0.6)-y//0  0-0 两次截断
	x = (x, y = 1, 2)-x;//0   2-2
	x = (x, y = 0, 2)-y;//2   2-0

2021

在这里插入图片描述

第三题:遇到&&||先用括号括起,如题目中的可划分成( (–x&&++y) || a ) ,即a是非0整体就是0了,划分根据两者的优先级:&&>||
第四题:逗号表达式依次从左到右执行,注意double类型要填加够六个零

2020

在这里插入图片描述

注意事项同2021年

总结

  • 与或的短路问题
    先根据优先级&&>||括括号,再从左到右考虑短路问题
  • 逗号表达式
    (1) 逗号表达式的运算过程为:从左往右逐个计算表达式。
    (2) 逗号表达式作为一个整体,它的值为最后一个表达式(也即表达式n)的值。
    (3) 逗号运算符的优先级别在所有运算符中最低。
    逗号表达式并不会马上赋值,而是先计算
    例如:x=(x,2)-x先计算小括号等于2,再减去x原来的值,作差得到新值
  • float和int的类型转换的截断,浮点类型添够六个零
  • 乘除运算顺序从左到右,不能用正常的数学逻辑去改变次序!因为会int类型除法会出现截断问题,如a\b2 不能先算b2


三、流程图

2016年

在这里插入图片描述
> 内循环是2、2+2×2、2+2×2+2×3、2+…+2×i
故需要一个从0开始的累加器和一个从1开始的自增变量,注意内循环的个数是由外循环决定的,也是动态的,。

2017年

在这里插入图片描述

2021年

在这里插入图片描述

先写出局部功能,由内到外寻找变量和循环条件

请添加图片描述

2022年

在这里插入图片描述
第一题:
请添加图片描述

不用考虑变量类型的问题,不要想着用指针或者数组的方式去把问题复杂化

第二题
在这里插入图片描述

总结

  • 不用定义变量,直接命名需要赋值的赋值就行,也就不用考虑类型和拿着平时编程思维去写。如2022第一题,不用考虑是用字符串还是整形去接收。再入2022第二题,输入可以多次输入,没必要都存入数组中进行操作
  • 细节问题,箭头要画出来,判断框要有T,F,输入输出框要有文字说明,循环回指箭头要指向线而不是判断框
  • 近年的问题不再出的像分支条件那样明显,需要从用循环、判断、初始化、多个输入输出的简单角度解决问题,不要复杂化。


四、程序分析

2022年

在这里插入图片描述

题目中的哪些问题说明不止一个问题,找错要考虑全面性,采取代入不同代表性数字看执行流程

在这里插入图片描述

字符串常用方法要及时复习

在这里插入图片描述

  • 十进制转二四八十六等进制:连除法。如二进制就每次除2取余数倒着写。递归放在静态变量之前可实现逆向输出。
  • 二八六等转换成十进制:位权相加,如十进制123转八进制就是 1×82 + 2×81 + 3×80

在这里插入图片描述

程序功能的描述:压缩存储,然后讲具体规则

在这里插入图片描述

不要掉以轻心

2021年

在这里插入图片描述

在这里插入图片描述

分析量颇大的题目,列出所有情况

在这里插入图片描述

2020年

在这里插入图片描述在这里插入图片描述

2019年

在这里插入图片描述

2018年

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2016年

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结:

  • 注意printf打印的格式,带不带中文,输出多少位小数,其他地方还还没有输出等
  • 递归与静态的结合,递归的打印才是多次执行,同时其在递归后是逆序打印。return只执行一次,除非return 递归才是返回多次,如return n+fun(n-1)计算累加
  • 推导计算类的多执行两次,容易出错
  • 描述功能可以从节约内存等计算机的角度去写
  • 别漏了for循环第一部分可初始化改变条件
  • if else判断分支只进入一个!
  • 行指针-行指针 = 间隔的步长,而不是元素个数
  • 注意for循环的三部分,定义的初始值有没有改变、终止条件包不包括等于、步长是自增1几,不要思维定式以为就是自增1。同时各个部分互相独立,会执行完一个部分在执行下一个,相当于三个独立语句,故++在前在后无影响
  • 看清楚问if判断条件的时候是问成立还是不成立时进入
  • 遇见输出结果不合理的情况要有意识检查一遍
  • 21年难度最大主要体现for循环要分析的情况很多,22年难度降下来了但功能描述是个问题
  • 很容易会的做错,做慢点,慢慢套数要多检查几遍


五、程序填空题

2022年

在这里插入图片描述

2021 年

在这里插入图片描述

2020年

在这里插入图片描述

2018年

在这里插入图片描述

总结

  • 注意看清题目要求,如正逆序打印
  • 形参是指针那么传入的必须是地址


六、编程题

2022年

1、数组各个元素组成三角形的边

  • 给定一个整型数组,编写程序,计算以其中的元素为边长可以形成多少个三角形,并输出这些三角形的边。
    例如:给定数组6 9 7 10 ,能构成的三角形的个数为4
#include<stdio.h>
int main() {
	/*
	给定一个整型数组,编写程序,计算以其中的元素为边长可以形成多少个三角形,
	并输出这些三角形的边。
	例如:给定数组6  9  7  10 ,能构成的三角形的个数为4
	*/	
	int arr[81], num, i, j, k, count = 0;;
	printf("请输入要输入的个数:");
	scanf("%d", &num);
	for (i = 0; i < num; i++) {
		printf("输入数组第%d个元素:", i + 1);
		scanf("%d", &arr[i]);
	}
	//注意此处j,k的起点 如果都是从0开始会造成数据的重复 如 6 10 9 和 10 6 9 和 9 10 6
	for (i = 0; i < num; i++) {
		for (j = i; j < num; j++) {
			for (k = j; k < num; k++) {
				if (arr[i] != arr[j] && arr[i] != arr[k] && arr[j] != arr[k]) {
					if (arr[i] + arr[j] > arr[k] && arr[i] + arr[k] > arr[j] && arr[j]+ arr[k] > arr[i]) {
						printf("%d %d %d\n", arr[i], arr[j], arr[k]);
						count++;
					}
				}
			}
		}
	}
	printf("组成三角形的个数:%d", count);
}

在这里插入图片描述

穷举要注意各自for循环的起点



2、求特殊数:丑陋数

  • 质因子只有2、3、5的数称为丑陋数,为了方便,1也被归为丑陋数(1,2,3,4,5,6,8,9,10,12,15…)。
    编写一个程序,输入一个数x,找出与x最接近的丑陋数。
#include<stdio.h>
/*
	质因子只有2、3、5的数称为丑陋数,为了方便,
	1也被归为丑陋数(1,2,3,4,5,6,8,9,10,12,15....)。
	编写一个程序,输入一个数x,找出与x最接近的丑陋数。
*/	
int flag(int i) {
	if (i == 2 || i == 3 || i == 5)
		return 1;
	//判断一个数的因数只有2,3,5
	//死循环不断连除,直至除到不能再被除后判断最后一个数是不是2,3,5
	else
	{
		int j = i;
		while (1)
		{
			if (j % 2 == 0)
				j = j / 2;
			else if (j % 3 == 0)
				j = j / 3;
			else if (j % 5 == 0)
				j = j / 5;
			else
				return 0;
			if (j == 2 || j == 3 || j == 5)
				return 1;
		}
	}
}
int main() {
	int x, close, i, j, right=0,left=0;
	printf("请输入一个数x: ");
	scanf("%d",&x);
	int num = flag(11);
	printf("%d\n", num);
	if (x <= 1) {
		close = 1;
		printf("与%d最接近的丑陋数为:%d", x, close);
	}else{
		//从x往右找
		for (i = x; i < x * 2; i++) {
			if (flag(i)) {
				right = i;
				break;
			}
		}
		//从x往左找
		for (j = x; j > 1; j--) {
			printf("b\n");
			if (flag(j)) {			
				left = j;
				break;
			}
		}
		if ((right - x) < (x - left)) {
			close = right;
			printf("与%d最接近的丑陋数为:%d", x, close);
		}
		else if((right - x) == (x - left)){
			printf("与%d最接近的丑陋数为:%d  %d", x, left, right);
		}
		else {
			close = left;
			printf("与%d最接近的丑陋数为:%d", x, close);
		}
	}
}

如何判断质因子只含2、3、5的方法是本题解题重点



3、读取后排序合输出

#include<stdlib.h>
/*
	1、输入每个学生的信息(学号、身高),保存到二进制文件
	2、再从二进制文件中读取到屏幕显示
	3、屏幕显示的要为同类合并后的结果
*/
typedef struct stu{
	int id;
	double height;
}s;

//将冒泡排序单独写一个方法  题目为从低到高
void sort(stu s[], int n) {
	int i, j;
	stu temp;
	for (i = 0; i < n - 1; i++) {
		for (j = 0; j < n - i - 1; j++) {
			if (s[j].height > s[j + 1].height) {
				temp.height = s[j].height;
				s[j].height = s[j + 1].height;
				s[j + 1].height = temp.height;
			}
		}
	}
}
int main() {
	FILE* fp1,*fp2;
	int i, j,sum;
	char ch;
	stu a[81],b[81];//一个用于存放键盘输入的信息,一个用于存放从文件读取的信息
	//创建读写指针
	if ((fp1 = fopen("D:\\123.rec", "rb")) == NULL) {
		exit(0);
		printf("文件打开失败!");
	}
	if ((fp2 = fopen("D:\\123.rec", "wb")) == NULL) {
		exit(0);
		printf("文件打开失败!");
	}

	//循环输入成绩并
	printf("是否继续输入信息?Y\N");
	scanf("%s", &ch);
	for (i = 0, sum - 0; ch == 'Y'; sum++,i++) {

		scanf("%d%f", a[i].id, a[i].height);
		//每输入一条边写出一条到二进制文件  此处的大小是类型的大小
		fwrite(&a[i], sizeof(stu), 1, fp2);

		printf("是否继续输入信息?Y\N");
		ch = getchar();
	}
	fclose(fp2);//关闭写指针

	//统计
	for (i = 0; i < sum; i++) {
		fread(&b[i], sizeof(stu), 1, fp1);
	}
	fclose(fp1);//读取到数组b完毕
	sort(b, sum);
	int count;
	printf("身高\t报表\n");
	printf("-------------");
	for (i = 0; i < sum ; i=j) {
		count = 1;
		for (j = i + 1; j < sum; j++) {
			if (b[i].height == b[j].height) {
				count++;
			}
			else {
				break;
			}
		}
		printf("%.1f\t%d", b[i].height, count);
	}
	printf("-------------");
	printf("共%d个人",sum);

}

补充:排序数组中的统计问题

#include<stdio.h>

int main() {
	//统计数学出现次数,输出数字+次数  如:数字:1,出现次数:3
	int i, j, sum = 10,count;
	int a[10] = { 1,2,3,3,4,4,6,6,6,7 };
	//下面方法成立的条件要是排序好的数组
	i=j是为了让下标跳到下一类数字中去,如i=j=4,下次从j+1=5开始统计
	for (i = 0; i < sum ; i=j) {
		count = 1;//某类数字第一次出现
		for (j = i + 1; j < sum; j++) {//j+1是跳到下一类 11122 下标从1跳到2的位置
			if (a[i] == a[j]) {
				count++;
			}
			//如果没有推出,从一开始j就会循环到最后,导致外循环的i=j让i也变得很大
			else {
				break;
			}
		}
		printf("数字:%d\t出现次数:%d\n", a[i], count);
	}
}

4、读入文件,统计和判断用户输入

#include<stdio.h>
#include<stdlib.h>
/*
	(1)读取文件信息到结构体中,统计调休信息为0的总数量sum
	(2)键盘输入到一个结构体,循环结构体数组判断其是否在其中,在就把其中信息给结构体
	不在就判断是否是周六日: 转换成距离1号多少天 (总天数-2)%7 等于6或0就是周六日
	 
*/
typedef struct holiday {
	int year,month,day;
	int flag;
};

//判断是否是周六日
int isweekday(int year,int month,int day) {
	int sum=0;
	int m[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
	if (year % 400 == 0 || year % 100 != 0 && year % 4 == 0) {
		m[1] += 1;
	}

	if (month >= 2) {
		for (int i = 0; i < month; i++) {
			sum += m[i];
		}
	}
	
	sum += day;
	//天数转换星期
	int flag = (sum - 2) % 7;
	if (flag == 6 || flag == 0) {
		return 1;
	}
	else {
		return 0;
	}
}

int main() {
	//(1)从文件中统计2022有多少天节假日  重点在于按格式读入
	FILE* fp;
	int i=0, j=0,count=0,sum;
	holiday a[365];
	if ((fp = fopen("D:\\holidays2022.txt", "r")) == NULL) {
		exit(0);
		printf("文件打开失败!");
	}
	//fscanf可以按固定格式读入数据 2022-1-1 0 ,同时读到尾部是EOF   %s %d的思路一开始就错了
	while (fscanf(fp, "%d-%d-%d %d", &a[i].year, &a[i].month, &a[i].day, &a[i].flag)!=EOF) {
		i++;
		sum = i;//统计文件中的日期总个数
	}

	for (i = 0; i < sum; i++) {
		if (a[i].flag == 0) {
			count++;
		}
	}
	printf("2022有%d天节假日\n", count);



	//(2)、判断用户输入是否是节假日
	holiday h;
	int flag=0;//判断是否出现过
	printf("请输入2022的一个日期(y-m-d):");
	scanf("%d-%d-%d", &h.year, &h.month, &h.day);

	for (i = 0; i < sum; i++) {
		if (h.year == a[i].year && h.month == a[i].month && h.day == a[i].day) {
			flag = 1;
			//两个flag的含义不一样,一个是判断是用户输入的日期是否在文件否出现过
			//另一个是结构体变量判断是否是放假日
			h.flag = a[i].flag;
		}
	}

	if (flag == 1) {
		if (h.flag == 1) {
			printf("该日期是节假日!\n");
		}
		else {
			printf("该日期是调休日!\n");
		}
	}
	//输入的日期没有出现在文件中,需要判断是不是周六日
	else {
		if (isweekday(h.year,h.month,h.day)) {
			printf("该日期是休息日!\n");
		}
		else {
			printf("该日期是工作日!\n");
		}
	}
	return 0;
}

补充一:txt文件的读写

#include<stdio.h>
struct stu {
	int	id;
	char sex;
	char name[81];
}s[3];
int main() {
	/*
		实现txt文件的读取和写出
		注意读取是作为判断条件不等于EOF,同时按指定格式读入存储到结构体中,要有地址符
		输出也是按指定格式输出(记得换行),多次输出需要循环
	*/
	FILE* fp1,*fp2; 
	int i = 0;
	fp1 = fopen("D:\\student.txt", "r");
	//1、从student.txt文件中读入 格式为1-Zhang m  别漏了取地址符&
	while (fscanf(fp1, "%d-%s %c", &s[i].id, &s[i].name, &s[i].sex)!=EOF) {
		i++;
	}
	fclose(fp1);
	fp2 = fopen("D:\\student02.txt", "w");
	//2、按原格式输出到student02.txt文件中  记得换行符
	for (int i = 0; i < 3; i++) {
		fprintf(fp2, "%d-%s %c\n", s[i].id, s[i].name, s[i].sex);
	}
	fclose(fp2);

	return 0;
}

txt文件读入scanf(fp, “按指定类型读入 如:%d-%d-%d %d”, 数据存储容器一般是结构体),同时是作为循环判断条件使用,不成立返回EOF
输出一般是fprintf(fp, “按指定格式输出 如%d-%d-%d %d\n”, 数据来源一般是结构体的各成员);

补充二:二进制文件的读写

#include<stdio.h>
#include<stdlib.h>
struct stu {
	int	id;
	char sex;
	char name[81];
}s[3];
int main() {
	/*
		实现二进制文件的写出和读取
		注意读取二进制文件有所不同,写出类似txt
	*/
	FILE* fp1,*fp2; 
	int i = 0;
	char str[81];

	//键盘输入转换成二进制文件,注意atoi方法
	for (i = 0; i < 3; i++) {
		printf("----第%d个学生信息-----\n", i + 1);
		printf("输入学号:");
		gets_s(str);
		s[i].id = atoi(str);
		printf("输入姓名:");
		gets_s(s[i].name);
		printf("输入姓别:");
		gets_s(str);
		s[i].sex = str[0];
	}

	fp2 = fopen("D:\\student02.rec", "wb");
	//2、按原格式输出到student02.txt文件中  记得换行符
	for (int i = 0; i < 3; i++) {
		fwrite(&s[i], sizeof(stu), 1, fp2);
	}
	fclose(fp2);

	
	//读取二进制文件
	fp1 = fopen("D:\\student02.rec", "rb");
	//1、从student.txt文件中读入 表示将指针指向的数据以数据块的方式读取存储到s数组中
	fread(&s[i], sizeof(s[i]), 1, fp1);
	while (!feof(fp1)) {//判断是否读取到文件尾部,没有读取到尾部返回0
		printf("\n学号:%d", s[i].id);
		printf("\n姓名:%s", s[i].name);
		printf("\n性别:%c", s[i].sex);
		//移动文件指针和下标指向下一个数组元素
		i++;
		fread(&s[i], sizeof(s[i]), 1, fp1);
	}
	fclose(fp1);
	
	return 0;
}

2021年

1、判断输入的年月日是否合理

#include<stdio.h>
/*
	编写程序,读入三个整数分别代表年、月、日,判断这些数能否形成合理的日期
*/	
int main() {
	int year, month, day, flag = 0; 
	int a[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
	printf("分别输入年,月,日: ");
	scanf("%d,%d,%d", &year, &month, &day);
	printf("%d年%d月%d日\n", year, month, day);
	if (year > 0) {
		//判断闰年,注意是%100不等于0
		if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
			a[1]++;
		}
		if (month >= 1 && month <= 12) {
			if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
				if (day <= 31) {
					flag = 1;
				}
			}else if (month == 2) {
				if (day<=a[1]) {
					flag = 1;
				}
			}
			else {
				if (day <= 30) {
					flag = 1;
				}
			}
		}
	}
	if (flag) {
		printf("输入的数能形成合理的日期");
	}
	else
	{
		printf("不能形成");
	}
}

嵌套if分三种情况进行讨论

方法改进

#include <stdio.h>

int main() {
	int year, month, day,flag=0;
	int m[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	printf("请输入年,月,日:");
	scanf("%d,%d,%d", &year, &month, &day);

	if (year % 400 == 0 || year % 4 == 0 && year % 100 != 0) {
		m[2]++;
	}

	if (month <= 12 && month >= 1 && day >= 1 && day <= m[month]) {
		flag = 1;
	}

	if (flag) {
		printf("输入正常!");
	}
	else {
		printf("输入不正常!");
	}
}

用月数作为各月天数数组下标可得到对应天数,不用分类讨论

2、判断成对大中小括号

#include<stdio.h>
/*
	读入一个含有括号(包括大中小括号)的字符串,检查其中括号的用法是否正确,
	即括号必须是成对出现,而且右括号不能出现在左括号之前。
	如:"1)abc"、"\abc[[1]"、"if(a)(i++;j++:" 都是不正确的用法
*/	
int main() {
	char* p1,*p2,str[81];
	int flag = 0, right[3] = {0}, left[3] = {0};
	printf("请输入字符串:");
	gets_s(str);
	p1 = p2 = str;
	//p2尾指针,p1首指针
	while (*(p2 + 1) != '\0') {
		p2++;
	}
	//统计左括号中出现的大中小类型括号的次数,
	while (*p1!='\0') {
		//左边读取到右括号,直接推出
		if (*p1 == ')' || *p1 == ']' || *p1 == '}') {
			break;
		}
		if (*p1 == '(') {
			left[0]++;
		}
		if (*p1 == '[') {
			left[1]++;
		}
		if (*p1 == '{') {
			left[2]++;
		}
		p1++;
	}
	//统计右括号出现的总次数
	while (p2 >= str) {
		//取到左括号 如:()123() 肯定不成立
		if (*p2 == '(' || *p2 == '[' || *p2 == '{') {
			break;
		}
		if (*p2 == ')') {
			right[0]++;
		}
		if (*p2 == ']') {
			right[1]++;
		}
		if (*p2 == '}') {
			right[2]++;
		}
		p2--;
	}

	for (int i = 0; i < 3; i++) {
		if (right[i] == left[i] && right[i] != 0 && left[i] != 0) {
			flag = 1;
		}
	}
	for (int i = 0; i < 3; i++) {
		printf("right:%d   left:%d\n", right[i], left[i]);
	}
	

	if (flag == 1) {
		printf("%s中的括号用法正确", str);

	}else{
		printf("%s中的括号用法不正确", str);
	}


	/*
	*	方法一:用指针分别找出左右括号各个类型出现的次数,用数组存储,最后匹配
		方法二:while(getchar()!='\n')逐个获取所有字符,三个变量存储大中小括号出现次数
		左括号自增,右括号自减,如果匹配则是变量初始值(大小不变),发生改变则不匹配
		方法二更好
	*/
}

方法改进

#include <stdio.h>

int main() {
	char str[81],*p;	
	printf("请输入:");
	gets_s(str);
	p = str;

	int i=0, j=0, k=0,flag=1;
	while (*p!='\0') {
		//是否配对
		if (*p == '[') {
			i++;
		}
		else if (*p == '{') {
			j++;
		}
		else if (*p == '(') {
			k++;
		}

		if (*p == ']') {
			i--;
		}
		else if (*p == '}') {
			j--;
		}
		else if (*p == ')') {
			k--;
		}

		//右括号出现在左括号之前
		//会先自减,是负数
		if (i < 0 || j < 0 || k < 0) {
			flag = 0;
			break;
		}
		p++;
	}
	if (i != 0 || j != 0 || k != 0) {
		flag = 0;
	}

	if (flag) {
		printf("用法正确!");
	}
	else {
		printf("用法不正确!");
	}
}

运用两者可以抵消原理(配对),让同一个变量自增自减
不要想用数组比较具体内容,会把问题变得复杂



3、对数据分布进行统计

在这里插入图片描述

#include<stdio.h>
/*
	将所有数分布到等宽的区间,然后统计每个区间中的数的个数
	例如:输入十个整数
	2 8 5 10 35 12 9 20 50 78
*/
int main() {
	int sum=10,i,j,num,k,t;
	int a[81] = { 2,8,5,10,35,12,9,20,50,78 };
	printf("请输入整数个数:");
	//scanf("%d", &sum);
	for (i=0; i < 0; i++) {
		printf("请输入第%d个整数:", i + 1);
		scanf("%d", &num);
		a[i] = num;
	}
	printf("请输入要划分多少个区间K");
	//scanf("%d", &k);
	k = 5;//输入五个区间
	//对数据进行冒泡排序 从小到大
	for (i = 0; i < sum - 1; i++) {
		for (j = 0; j < sum - i - 1; j++) {
			if (a[j] > a[j + 1]) {
				t = a[j];
				a[j] = a[j + 1];
				a[j + 1] = t; 
			}
		}
	}
	float len;
	printf("最小:%d、最大:%d\n", a[0], a[sum - 1]);
	len = ( a[sum - 1] - a[0] ) / (float) k;
	printf("每个区间长度:%.1f\n", len);

	int sum2=0,flag=0;
	//外循环得到每个区间的起点
	for (float i = a[0]; i < a[sum - 1]; i += len) {
		//内循环比较每个元素是否在区间
			for (j = 0; j < sum; j++) {
				if (a[j] >= i && a[j] <= i + len ) {
					sum2++;
				}
			}
		printf("%.1f ~ %.1f:%d\n", i, i + len, sum2);
		sum2 = 0;
	}
	return 0;
}

有小问题首位末尾是2和78但上面输出2.0 78.0
排序找最大最小划分平均值,通过for得到每个区间,再里面便利每个元素判断是否在区间里面,注意类型的转换

方法改写

#include <stdio.h>
#define N 10

int main() {
	int a[10] = { 2,8,5,10,35,12,9,20,50,78 },i,j,k=5,n,t;

	//选择排序
	for (i = 0; i < N-1; i++) {
		n = i;
		for (j = i + 1; j < N; j++) {
			//注意此处是n和j比 i只参与值的交换
			if (a[n] > a[j]) {
				n = j;
			}
		}
		if (n != i) {
			t = a[i]; a[i] = a[n]; a[n] = t;
		}
	}

	float len = (float)(a[N - 1] - a[0]) / k;

	int count = 0;
	//划分成几个区间是不固定的,因此划分的范围也是变化的
	for (i = 1; i <= k; i++) {//获得所有区间
		for (j = 0; j < N; j++) {
			//获得每个区间的前后两端值
			if (a[j] >= a[0] + len * (i - 1) && a[j] <= a[0] + len * i) {
				count++;
			}
		}
		//实现收尾打印与中间打印的不同
		//注意打印只打印一位小数
		if (i == 1) {
			printf("%d~%.1f:%d\n", a[0], a[0] + len * i, count);

		}
		else if (i == k) {

			printf("%.1f~%d:%d\n", a[0] + len * (i - 1), a[N-1], count);
		}
		else
		{
			printf("%.1f~%.1f:%d\n", a[0] + len * (i - 1), a[0] + len * i, count);
		}
		count = 0;
	}
}
  • 先便利区间个数,再通过区间个数的关系得到具体的前后两端的区间数值是此题的重点
  • 选择排序是保存后的n和j比较,i只在交换值得时候用

4、用户点餐

#include<stdio.h>
#include<stdlib.h>
#define N 3
struct food {
	int id;
	char name[81];
	double prices;
	int flag;
	int num;
}F[N];

void order(int table, int food[N], int num[N]) {
	int i, j = 0, f = 0, n = 0;
	FILE* fp;
	fp = fopen("D:\\order.txt", "w");
	for (i = 0; i < N; i++) {
		if (food[i] == F[i].flag) {
			printf("%s菜品不再供应", F[i].name);
			j = i;//记录编号
		}
		else if (num[i] < F[i].num) {
			printf("%s菜品可供数量不足", F[i].name);
			j = i;
		}
		//讲数组转换成数字
		if (!j) {
			f = f * 10 + food[i];
			n = n * 10 + num[i];
			j = 0;
		}
	}
	//printf("转换的f和n:%d、%d", f, n);
	//保存用户点餐信息
	fprintf(fp, "%d,%d,%d", table, f, n);
}

//删除得闲打开原有文件,条件匹配之后的数据输出到新文件,删除原文件,将新文件改名
void remove() {
	int i;
	FILE* fp1, * fp2;
	food f;
	fp1 = fopen("D:\\food.rec", "rb");
	fp1 = fopen("D:\\food02.rec", "2b");

	while (fread(&f, sizeof(f), 1, fp1) == 1){//成功返回第三个参数
		if (F[i].flag != 1) {//符合条件的输出
			fwrite(&f, sizeof(f), 1, fp2);
		}
	}
	fclose(fp1);
	fclose(fp2);
	remove("food");
	rename("food2", "food");//旧的  新的
}

int main() {
	//(1) 键盘输入--》二进制文件
	FILE *fp;
	int i, j, k,t,tag=1;
	
	while ((fp = fopen("D:\\food.rec", "wb")) == NULL) {
		exit(0);
		printf("文件打开失败!");
	}
	for (i = 0; i < N; i++) {
		printf("请输入第%d个菜品信息\n", i + 1);
		F[i].id = tag++;
		printf("输入格式菜名,价格,状态,数量:");
		scanf("%s,%f,%d,%d", F[i].name, F[i].prices, F[i].flag, F[i].num);
		fwrite(&F[i], sizeof(F[i]), 1, fp);
	}
	
	int a[3] = {1,2,3};//菜品编号
	int b[3] = { 2,2,2 };//对于数量
	order(1, a, b);
	
	return 0;
}

补充:文件的增删改查

2020年

1、判断输入的两个整数是否存在重复数字

#include <stdio.h>
int main(){
	int a,b,count[10]={0}, i, flag = 0; //用数组记数是本题重点
	printf("请分别输入整数");
	scanf("%d,%d", &a, &b);
	while (a > 0) {
		count[a % 10]++;
		a = a / 10;
	}
	while (b > 0) {
		count[b % 10]++;
		b = b / 10;
	}

	for (i = 0; i < 10; i++) {
		printf("%d", count[i]);
		if (count[i] >= 2) {
			flag = 1;
			break;
		}
	}
	if (flag == 0) {
		printf("不存在");
	}
	else{
		printf("存在");
	}

	return 0;
}

计数数组要进行初始化,逐个取出数字的方法

2、两个字符串的逐个比较

#include <stdio.h>
int main(){

	char* s, * a,s1[81],a1[81],score=0;

	gets_s(s1);
	gets_s(a1);

	s = s1;
	a = a1;

	while (*a!='\0' && *s!='\0') {
		if (*a == *s) {
			score += 2;
		}
		a++;
		s++;
	}
	printf("%d", score);
	return 0;
}

字符数组考虑指针

3、左移动字符串

#include <stdio.h>
#include <string.h>
//hello
//lohel
/*
* 将字符串s左移动n次
hello
elloh
llohe
olhel
*/
char* shift(char* s, int n) {
	int i,j=0;
	char ch;
	int len = strlen(s);
	while (j < n) {
		ch = s[0];
		for (i = 0; i < len - 1; i++) {
			
			s[i] = s[i + 1];
		}
		s[len - 1] = ch;
		j++;
	}
	
	return s;
}

int main(){
	char str[81] = "hello";
	char* p = str;
	shift(p, 3);
	printf("%s", str);
}

先写出移动一次的代码
即保存首位将余下后面的往前移动一位,注意是s[i] = s[i + 1];的赋值for循环下标就到len-1

4、股票信息的输入与输出

#include <stdio.h>
#define N 50

struct GP {
	char name[81];
	int code;
	char mark;
	float up_down;
};

int main(){
	FILE* fp,*fp2;
	int i = 0,j,k;
	GP g;
	//二进制要多个b
	fp = fopen("gupiao.rec", "wb");
	fp2 = fopen("gupiao.rec", "rb");
	while (i<50) {
		scanf("%s,%d,%c,%f", g.name, g.code, g.mark, g.up_down);
		//记住方法参数
		fwrite(&g, sizeof(g), 1, fp);
		i++;
	}


	GP gg[N];
	while (i < 50) {
		fread(&gg[i], sizeof(gg[i]), 1, fp2);
		i++;
	}


	//选择排序固定套路别写错
	GP t;
	for (i = 0; i < N; i++) {
		k = i; //储存o i用来便利每个数不能变
		for (j = i + 1; j < N; j++) {//获取i之后的每个数
			if (gg[i].up_down > gg[j].up_down) {
				k = j;//找打最大数所在位置
			}
		}
		//说明有找到还要大的数,交换
		if (k != i) {
			t = gg[i];
			gg[i] = gg[k];
			gg[k] = t;
		}
	}

	fclose(fp);
	fclose(fp2);

}

二进制文件读取注意加b 和fread的参数与循环终止条件为fread一次之后 while(!feof(fp))

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值