【咸鱼入门】终于到了C语言考试复习时间了……

        好久不见!自从上次计算机导论课结课之后,我基本(雾)就没怎么动过博客(虽然也没什么人看嘻嘻),但是毕竟到了期末复习的这个节点了,经历了一个学期的写bug,总该有一个交待。写代码之后的反思同样重要,就像王垠在博客里说的那样,写了很多代码但是不去修改,那么里面必然存在很多垃圾
        比如说期中考试对于A到z直接使用连续的,但是实际上需要分开,这里有没有更好的实现方式呢?
        我可能就写出过这种“垃圾”。所以在期末复习的时候,重新回顾一下自己写过的一些代码,看看哪里还需要改进,共勉之。
        那么我将用老师说需要掌握的题目进行复习。当然,这篇只是一个开头,找一找写博客的感觉。可能并没有什么实质性的内容, 里面的东西也很简单。毕竟很久没写了,需要熟悉熟悉……

【咸鱼入门】终于到了C语言考试复习时间了……

博文目录

  • 实验1:等腰三角形的判断
  • 实验2:输出菱形
  • 实验3:数组排序
  • 实验4:递归调用计算阶乘的和
  • 实验5:文件拼接

实验1:等腰三角形的判断

题目:

编写程序(Lab1.c),实现如下功能:从键盘上输入三个int型的整数,判断这三个数是否能构成一个等腰三角形。 提示:
(1)如果输入的三个数都大于0,才有可能构成三角形,否则,要输出告错信息:“三角形的边长必须大于0。”
(2)如果输入的三个数都满足大于0的条件,再继续判断是否满足等腰三角形的条件:三个数中有两个数相等,并且这两个数的和要大于第三个数。如果满足上述条件,输出“这三个数可以构成等腰三角形。”;否则,输出“虽然三个数都大于0,但是不能构成等腰三角形。”。

思路:就是判断。
初始代码:

#include <stdio.h>	
int main()
{
	printf("请输入三个整数:");
	int a,b,c;
	scanf("%d %d %d",&a,&b,&c);
	if(a<=0||b<=0||c<=0)
	{
		printf("三角形的边长必须大于0。");
	}
	else if((a==b&&a+b>c)||(b==c&&b+c>a)||(a==c&&a+c>b))//也可以:先找出来那两个数,实质一样的。 
	{
		printf("这三个数可以构成等腰三角形。");
	}
	else
	{
		printf("虽然三个数都大于0,但是不能构成等腰三角形。");
	}
	return 0;
}

反思:
这个程序很简单。首先读入,然后判断。怎么判断?先判断是不是大于0,如果有负数,那么程序就结束了;如果都大于0,继续判断,是否符合等腰三角形的条件,也即既可以够成三角形,又可以够成等腰三角形。

实验2:输出菱形

题目:

让用户输入任意行数,然后输出下图形状的菱形。
在这里插入图片描述

思路:其实就是找规律。可以分成上下两个部分,每个部分又可以逐行输出,逐行输出空格和星号。
要硬核一些,直接找规律。假如用户输入了N行,拆分之后上部分(N+1)/2行,下部分(N+1)/2-1行。要是偶数行数?转化为奇数!(否则会比较难看)
在上面部分,
发现i行空格数为(N+1)/2-i,星号数为2i-1,它们加起来为(N+1)/2+i-1。
在下面部分,
发现i行空格数为i-(N+1)/2,星号数为(摆几行草稿)
// 5行 n=3 加起来为N+1 2n-1=2(N+1-i)-1
// 6行 n=2
// 7行 n=1
所以,星号数为2*(N+1-i)-1,空格数为(N+1)/2+1。
好了,贴一下我的代码:

#include <stdio.h>

int main()
{
	int t;
	int l=1;
	int i;
	scanf("%d",&t);//输入行数
	int m=(t+1)/2;//中间行  整数除以整数还是整数
	int x;
	for(;l<=m;l++)//上半部分,控制行数
	{
		for(i=1;i<=m-l;i++)//输出空格
		{
			printf(" ");
		}
		for(i=1;i<=2*l-1;i++)//输出*
		{
			printf("*");
		}
		printf("\n");//每行之后换行
	}
	for(;l<=t;l++)//下半部分控制行数
	{
		x=t+1-l;//找到下面的个数和行数的关系
		for(i=1;i<=m-x;i++)//控制空格
		{
			printf(" ");
		}
		for(i=1;i<=2*x-1;i++)//*
		{
			printf("*");
		} 
		printf("\n");
	}
	return 0;
}

感觉基本上就是N/2-1的应用。

实验3:数组排序

某班有N个学生,进行了数学考试,现要求将数学成绩按由低到高的顺序排序。
具体要求:
输入成绩
输出排序前的成绩
对成绩进行排序
输出排序后的成绩

这个可以算是很简单的输入了。当然有个问题,到底是多少个学生?
针对这个题,可以开辟一个比较大的空间(当然有资源浪费),也可以先输入有多少个学生然后再开辟空间(动态数组),然后进行遍历循环,实现排序。
排序我用的冒泡排序(这什么鬼我都快忘了……)

#include <stdio.h>

void Array_Sort (int a[],int N);

int main()
{
	int N,i=0;
	printf("Please input the number of the students:");
	scanf("%d",&N);
	int a[N];
	printf("Please input the socres of each student.");
	for(;i<N;i++)
	{
		scanf("%d",(a+i));
	}
	printf("The orign data is:\n");
	for(i=0;i<N;i++)
	{
		printf("%d ",a[i]);
	}
	putchar('\n');
	Array_Sort(a,N);
	printf("The sorted data is:\n");
	for(i=0;i<N;i++)
	{
		printf("%d ",a[i]);
	}
	return 0;
}

void Array_Sort (int a[],int N)
{
	int times=0,i=0,flag=0;
	int temp;
	while((times<N-1&&(flag==0)))
	{
		flag=1;
		for(;i<N-times-1;i++)
		{
			if(a[i]>a[i+1])
			{
				flag=0;
				temp=a[i];
				a[i]=a[i+1];
				a[i+1]=temp;
			}
		}
		times++;
		i=0;
	}
}

注意里面有几个关键的地方,int a[N],直接开辟了动态数组。这在C99里是允许的。
其中,flag是用来记录是否排序完成的变量。如果这一轮没有发生任何交换,说明排序已经完成,可以不继续进行。
至于冒泡排序是怎样进行的,之前写过一篇博客,传送门:
https://blog.csdn.net/qq_43208925/article/details/83684040
了解选择排序、插入排序,可以参考:
https://blog.csdn.net/qq_43208925/article/details/84311335

实验4:递归调用计算阶乘的和

编写程序(Lab4.c),计算 1! + 2! + 3! +… + N! 。要求编写一个函数,参数设置为值参数。

这样一个题,既可以使用for循环,也可以使用递归。
递归,就是自己不断地去调用自己,所以在递归调用的时候一定要说明终止条件,以完成递归调用的中止。
所以,比如对于一个计算阶乘的函数,我们就可以写出下面的代码:

int get(int x)
{
	if(x>1)
	{
		return n*function(x-1)
	}
	else if (x==1)
	{
		return 1;
	}
}

这样,get(x)表示x的阶乘。
那么……我们还需要把它们加起来。

int add(int x)
{
	if(x!=1){
		return get(x)+add(x-1)
	}
	else if(x==1){
		return 1;
	}
	return 0;
}

也就是,通过get可以求出当前的这个数字的阶乘,然后我们需要和之前已经算好的结果去相加。之前算好的结果也可以继续使用这样的结构。
在这里应该充分体会一下递归思想。

拓展:程序的优化——高位数计算

我们知道,即使使用long long int,也只能勉强表示19位。但是使用C语言真的没有办法实现自定义的高位数计算了吗?
可以这样去想,我们直接计算1234567*3,很难一下子得到答案,但是如果让我们列竖式,那么问题就转化成了7*3=21,6*3=18,8+3=11……诸如此类。对于计算机是不是也可以做这样的竖式计算呢?理论上没问题——只要我们把竖式用代码表示出来。
怎么表示呢?我们知道一串连续的数字很像数组这个数据结构。所以,思路就是,用数组中的每一位代表竖式中的每一位。
在这里插入图片描述
虽然很难看(汗颜),但是就是这样去做的。
为了实现这样的东西,我们要做两件事:一是求出来每一个的阶乘的结果,二是将这些结果相加。

求每一个阶乘

阶乘是123456……*n,所以默认从一位开始。
需要的变量:存储阶乘结果的数组a[50](大小任意开辟),存放进位的变量carry,存放结果目前有多少位的变量digit(初始值为1),存放当前是第几位的临时变量t,进行每一次操作用来取个位和进位的变量temp,总阶数n和当前阶数i。
需要进行的循环:
外层:从1到要求的数n;内层:从第一位到第digit位。
算法:
在内层循环中,先让每一位和当前阶数相乘,然后执行进位操作。临时变量承接乘积,取个位给当前位,取更高位(除以10)给下一位。如果直到最后一位还需要继续进位,那么,总位数加1。
代码实现一下:

int mode(int x){
	//x表示到几的阶乘,即阶数。
	int digit = 1; //位数,目前是一位。
	int result[50]={1}; //结果数组,目前是1!
	int j = 1; //当前处在的位数,设置为1,当然需要持续更新
	int i = 1; //当前阶数
	int temp=0; //临时变量,用在每次阶数和某一位相乘后的进位,初值必须是0
	int carry; //用来实现进位的变量
	//外层:第几阶
	for(;i<=x;i++){
		//内层:每一位进行和当前阶数相乘
		for (;j<digit;j++)
		{
			temp=a[j-1]*i+temp;
			//temp如果发生进位,那么必须让个位数成为新的当前位
			a[j-1]=temp%10;
			//那么,要把需要进位的东西传递给下一位,进位的是除以10的东西
			carry=temp/10;
			//然后把这个carry送到temp中。如果已经是最后一位,那么执行之后的整体位数加1操作。
		}
		//实现整体位数加一
		while(carry){
			digit++;
			//有可能进两位,三位什么的,所以最高为取carry的个位,之后继续
			a[digit-1]=carry%10;
			//carry除以10,看看还用不用继续进位
			carry/=10;
		}
	}
}

这30行代码(而且好多注释)就可以实现所需要的计算出来一个阶乘。
下一件事就是把求出来的阶乘相加。(显然我定义了一个全局变量)
优化可以使用指针。之后会贴优化后的代码。
所以最重要的还是思路。

//实现高精度阶乘求和 
void array_sum(int n)
{
	int i=1,j=0,digit_a,digit_now=1,digit=1;
	int carry=0,temp;//carry means 进位 
	//执行n次,从1到n 
	for(;i<=n;i++)
	{
		array_mode(i);
		//判断刚刚计算完的阶乘的位数 
		while(1)
		{
			if(a[j]==0) break;
			j++;
		} 
		digit_a=j;
		//判断当前总位数和新数位数的关系
		if(digit<digit_a) digit=digit_a; 
		//进行加法运算 
		for(;digit_now<=digit;digit_now++)
		{
			temp=sum[digit_now-1]+a[digit_now-1]+carry;
			sum[digit_now-1]=temp%10;
			carry=temp/10;
		}
		while(carry)
		{
			digit+=1;
			sum[digit-1]=carry%10;
			carry/10;
		}
		digit_now=1; 
	} 
	//输出结果
	printf("根据高位数计算,结果是:");
	for(digit_now=digit;digit_now>0;digit_now--)
	{
		printf("%d",sum[digit_now-1]);
	} 
	putchar('\n');
}

其实思路大致都是一样的——模拟加法计算的竖式。
限于时间,先写了一点,今晚会继续完善。恳请赐教。

————————分割线————————

有了点时间,继续完善。

实验5:文件拼接

题目大意:有1.txt和2.txt两个文件,我们需要把两个文件拼接到一起,然后输出为data.dat文件。每个读入的文件都不会超过200个字符。
思路:使用一个字符数组进行存放,先存放数组1,然后后退一个位置(文件结束标记),再继续读入文件2。
代码:

#include <stdio.h>

int main(){
	FILE *fp1,*fp2;
	char file[201];
	int i=0;
	char ch;
	fp1=fopen("1.txt","r");
	while(!feof(fp1)){//濡傛灉鑳藉璇诲埌瀛楃
		ch=fgetc(fp1);
		file[i]=ch;
		i++;
	}
	i-=1;
	fp2=fopen("2.txt","r");
	while(!feof(fp2)){
		ch=fgetc(fp2);
		file[i]=ch;
		i++;
	}
	FILE *f;
	f=fopen("data.dat","w");
	int j=0;
	i-=1;
	while(j<i){
		fputc(file[j],f);
		j++;
	}
	fclose(fp1);
	fclose(fp2);
	fclose(f);
	return 0;
}

重点记住怎么读写文件。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值