西北农林科技大学2023级C语言期末考试题解

Readme

         本题解只提供了题目和题解代码,未提供讲解,后续会跟新B站视频详细讲解,大家可以关注等候。

        B站:沐晨汐er_

        链接:沐晨汐er_的个人空间-沐晨汐er_个人主页-哔哩哔哩视频 (bilibili.com)

        A题 WA了20多发哈哈哈哈

题目

E

题目描述

        现有n×n的棋盘,棋盘上每个格子只能放入黑白两种棋子中的一个,分别用字符'+'表示黑色棋子、'*'表示白色棋子、'0'表示未着子。
        编写Judge函数,Judge函数原型如下:
        int Judge(char **str, int n, char ch, struct solu *ps);
        其中,形参str是指向棋盘的指针,形参n表示棋盘大小(n×n),形参ch('+'、'*'分别表示黑白棋子)表示棋子颜色,形参ps是指向保存连珠方法的结构体变量。
        通过调用Judge函数,判断落子布局是否可以组成五子连珠,若可以则返回1,并将找到的第一个连珠方法保存在ps指向的结构体变量中;否则返回0。struct solu结构体的定义如下:

struct solu{
    int x;
    int y;
    char direction;
};

        其中,用x和y分别表示字符ch表示的棋子组成的第一个五子连珠的起始行号和起始列号(行号和列号均从0开始),用direction保存五子连珠的四种方向,可以在四种符号:'-','|','\','/'中取值,分别表示以x和y为起点,向右横向、向下竖向、向右下斜向、向左下斜向构成了五子连珠。
        五子连珠寻找的优先级规则为:行优先(即先判断第0行的所有位置,然后是第1行、第2行……依次类推),方向优先级判断顺序为:向右横向、向下竖向、向右下斜向、向左下斜向。

输入:

+ 20
0+0++*0+*+++000++0++
0+00+0+*0+*00*00***0
+0+0000+++*0+**+*0**
+**+0++*0*+0**0*0**0
*00*++0*0*++00*+00*0
*+*0*++*00*+0+0+**+0
+*+++0+0000+0***+**+
00*0+*0**+*0*000**++
*+**000+0+***++**+++
*00+*+*+00++0***0*0*
+*0**++0++*0+****00*
*+**+++0++++*0000+++
+*+000*0**++*+**+0**
+*0****+000*++++0*0*
+**0*+*00+000*0**+0+
0**+**+***0*+**00+*0
*+0++***0000+*+++0**
+0**+0+++*+0++**+000
**++++**00++00*++0*+
00*000+00++00+0+*+00
说明:分别用字符'+'、'*'、'0'代表黑子、白子、未着子,第一行输入"+ 20"表示在20×20的棋盘上对黑子是否能够组成五子连珠进行判断。

输出:

1 1 \
说明:该结果表明第1行,第1列,有一个由'+'组成的向右下斜向的五子连珠方案,是满足条件的第一个解

代码

// E.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct solu
{
    int x;
    int y;
    char direction;
};

int Judge(char **str, int n, char ch, struct solu *ps){
	char t = '\0';
	for (int i = 0; i < n; i++){
		for (int j = 0; j < n; j++){
			if (str[i][j] == ch){
				if (j <= n-5 && str[i][j+1]==ch && str[i][j+2]==ch &&
				str[i][j+3]==ch && str[i][j+4]==ch){
					t = '-';	
				}else if (i <= n-5 && str[i+1][j]==ch && str[i+2][j]==ch &&
				str[i+3][j]==ch && str[i+4][j]==ch){
					t = '|';	
				}else if (i <= n-5 && j <= n-5 && str[i+1][j+1]==ch && str[i+2][j+2]==ch &&
				str[i+3][j+3]==ch && str[i+4][j+4]==ch){
					t = '\\';	
				}else if (i <= n-5 && j >= 4 && str[i+1][j-1]==ch && str[i+2][j-2]==ch &&
				str[i+3][j-3]==ch && str[i+4][j-4]==ch){
					t = '/';	
				}
			}
			if (t != '\0'){
				ps->x = i;
				ps->y = j;
				ps->direction = t;
				return 1;
			}
		}
	}
	return 0;
}

int main()
{
    int n, i;
    char ch;
    struct solu s = {-1, -1, ' '};
    scanf("%c%d", &ch, &n);

    char *board[n];
    for(i = 0; i < n; i++)
    {
        board[i] = (char *)malloc((n+1)*sizeof(char));
        memset(board[i], 0, (n+1)*sizeof(char));
        scanf("%s", board[i]);
    }

    if (Judge(board, n, ch, &s) == 1)
        printf("%d %d %c\n", s.x, s.y, s.direction);
    else
        printf("0\n");

    for(i = 0; i < n; i++)
    {
        free(board[i]);
    }

    return 0;
}

D

题目描述

        给定一个有m个元素(m<50)的正整数整型数组nums和一个正整数k(0<k<20),现需要向nums数组中追加填充k个最小的未出现在数组nums中且互不相同的正整数,要求使填充后数组的各元素的累加和最小。请编写函数MinInsert()返回填充到nums中的k个整数之和。

        函数原型:int MinInsert(int *pnums, int m, int k);
        其中,形参pnums是指向nums整型数组的指针,形参m是数组元素的个数,形参k是要填充的正整数个数。
        函数算法请参考下面的流程图。

        注意:不能改变指定函数原型,仅需提交MinInsert()函数及其调用的自定义函数的实现代码。

        示例 1:
        输入:nums = {1,4,25,10,25}, k = 2
        输出:5
        解释:向数组中填充的两个互不相同且未出现的正整数是 2 和 3 。nums 最终元素和为 1 + 4 + 25 + 10 + 25 + 2 + 3 = 70 ,这是所有情况中的最小值。
        所以填充到数组中的两个整数之和是 2 + 3 = 5 ,所以返回 5 。

        示例 2:
        输入:nums = {5,6}, k = 6
        输出:25
        解释:向数组中填充的六个互不相同且未出现的正整数是 1 、2 、3 、4 、7 和 8 。nums 最终元素和为 5 + 6 + 1 + 2 + 3 + 4 + 7 + 8 = 36 ,这是所有情况中的最小值。
        所以填充到数组中的六个整数之和是 1 + 2 + 3 + 4 + 7 + 8 = 25 ,所以返回 25 。

        请参考下面的流程图编写代码。其中,gap是数组中的间隙。要循环判定数组的间隙大小,当间隙gap大于待填数量k时,依次填入整数;否则依次填满间隙,再调整待填数量k。最后如未达到要求的待填数量,则继续在尾部填充。

      

代码

// D.
#include <stdio.h>

int MinInsert(int *pnums, int m, int k){
	int *t = pnums;
	for (int i = 0; i < m; i++){
		for (int j = 0; j < m; j++){
			if (t[j] > t[i]){
				int x = t[i];
				t[i] = t[j];
				t[j] = x;
			}
		}		
	}
	int sum = 0, cnt = 0;
	for (int i = 0; i < m; i++){
		if (i == 0){
			int cha = t[i] - 0;
			if (cha > 1){
				for (int j = 1; j < t[i]; j++){
					sum += j;
					cnt++;
					if (cnt == k) return sum; 
				}
			}
		}else{
			int cha = t[i] - t[i-1];
			if (cha > 1){
				for (int j = t[i-1]+1; j < t[i]; j++){
					sum += j;
					cnt++;
					if (cnt == k) return sum; 
				}
			}
		}
	}
	if (cnt < k){ 
		int x = t[m-1]+1;
		while (cnt != k){
			sum += x;
			x++;
			cnt++;
		}
	}
	return sum;
}

int a[N] = {5,8,13};
void solve() {
	cout << MinInsert(a,3,15) << endl;
}

signed main() {
	int t = 1;
	while(t--) {
		solve();
	}
	return 0;
}

C

题目描述

        假定有下面的结构体:

typedef struct {
    unsigned int year;   /* 有效年份 1900~2050 年*/
    unsigned int month;
    unsigned int day;
} Date, *PDate;

        请实现下面的两个函数,其原型要求如下:
        int ToDate(char *str, PDate pd);
        int DaysCount(PDate sdate, PDate edate);
        ToDate()函数将字符串str中的合法日期存入指针变量pd指向的结构体成员中,其中字符串str的基本形式为“YYYY-MM-DD”,YYYY代表年,MM代表月,DD代表日,如str为“2023-12-30”,则ToDate()函数的功能是将2023、12、30分别存入pd->year、pd->month、pd->day中。如果str中的日期数值范围或数据格式非法,函数返回-1,正常返回0。
        DaysCount()函数计算两个日期sdate和edate之间差距是多少天,并返回计算结果。

输入:

2008-08-08
2023-12-30

输出:

5622

可以使用sscanf函数从字符串str中将年月日读取为整数,例如,sscanf(str, "%d-%d-%d", &year, &month, &day)。
另外,提供以下日期计算结果,供程序测试使用。

  • 1949年10月01日开国大典,至今(2023年12月30日)已过27118天。
  • 1950年10月25日抗美援朝,至今(2023年12月30日)已过26729天。
  • 今天是2023年12月30日,距离西北农林科技大学90周年校庆(2024年09月10日),还有255天。
  • 2023年09月11日开学,至今(2023年12月30日)已过110天。

代码

// C.
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    unsigned int year;
    unsigned int month;
    unsigned int day;
} Date, *PDate;

int is_leap(int);
int month_days(int ,int);

int ToDate(char *str, PDate pd){	
	int year,month,day;
	if ((sscanf(str, "%d-%d-%d", &year, &month, &day)) == 3){
		if (year >= 1900 && year <= 2050 && month >= 1 && month <= 12 && 
		    day >= 1 && day <= 31){
			pd->day = day;
			pd->month = month;
			pd->year = year;
			return 0;
		}
		return -1;
	}
	return -1;
}
int DaysCount(PDate sdate, PDate edate){
	int res = 0;
	
	// 开始那年 
	int flag = is_leap(sdate->year);
	res += month_days(sdate->month,flag) - sdate->day;
	for (int i = sdate->month+1; i <= 12; i++){
		res += month_days(i,flag);
	}
	
	// 后面的每一年 
	for (int i = sdate->year+1; i <= edate->year; i++){
		res += is_leap(i) ? 366 : 365;
	}
	
	// 减去多加的
	flag = is_leap(edate->year);
	res -= month_days(edate->month,flag) - edate->day;
	for (int i = edate->month+1; i<= 12; i++){
		res -= month_days(i,flag);
	} 
	return res;
}

int main()
{
    char str1[12], str2[12];
    Date sd, ed;
    fgets(str1, 12, stdin);
    fgets(str2, 12, stdin);
    if (ToDate(str1, &sd) == 0 && ToDate(str2, &ed) == 0)
        printf("%d\n", DaysCount(&sd, &ed));
    else
        printf("input data is invalid.\n");
    return 0;
}

int is_leap(int year)
{
    return ((year%4==0&&year%100!=0)||year%400==0);
}

int month_days(int month, int leap)
{
    int m_days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if(month == 2)
        return (leap == 1) ? 29 : 28;
    else
        return m_days[month];
}

B(?)

疑问

        不懂为什么排序的算法,冒泡排序(稳定性算法)过85%,选择排序1.0过92%最基础的选择排序2.0AC了有大佬可以解释一下吗??

题目描述   

        从二进制文件“stud.dic”中读取指定范围内的学生数据,并使用结构体、文件操作、函数指针等实现对各科成绩的升、降序通用化排序。程序主体框架已完成,请仔细阅读已有代码,并完成下面的两个函数:

1.通用排序
        函数原型为:void sort(stu *stud, int mode, int sub, int n);
        其中,形参sub用于指定需要排序的科目,取值为0、1或2代表的科目编号,形参mode用于指定排序模式,1表示升序,2表示降序,从而实现对形参n指定的n个学生成绩进行排序,形参stud是需要参与排序学生的数组首地址指针。

2.从二进制文件读入指定数据
        函数原型为:stu *read( FILE *fp, int m, int n);
        其中,形参fp传入的是已打开二进制文件的文件指针,形参m用于指定范围的起始位置(从0开始编号), 形参n用于指定需要读取的学生数据个数。在函数内部,用动态内存分配存储空间,读入指定的数据到分配的空间后,返回其首地址。

注意:

  1. 在程序主体框架中,已给出了结构体、主函数、辅助函数类型定义以及所需要完成的函数原型。
  2. 不能改变程序主体框架和指定函数原型,仅需提交sort()和read()函数及其调用的自定义函数的实现代码。
  3. 在二进制文件中,学生信息最多为30条,且姓名中可能会有空格,如:“白 莹”,成绩中可能含有小数。

输入:

起始学生序号m,学生数量n,排序方式mode,排序科目编号sub

0 3 1 0

输出:

从第m个开始的n个学生信息,并以mode方式对科目sub排序

0th: 2009011360 卢 莹 13.27 85.45 26.72
1th: 2010036201 张 阳 87.10 54.00 63.90
2th: 2010036209 赵扶强 90.50 54.00 65.00

代码

// B.
#include <stdio.h>
#include <stdlib.h>

#define M 30

typedef struct STUDENT
{
    int studentID;
    char studentName[10];
    float score[3];
} stu, *pstu;
typedef int (*CmpFunPtr)(float, float);  /* 定义函数指针类型CmpFunPtr,该类型的指针指向的函数应该返回一个整型数据,且含有两个float型形参。 */

int compareA(float, float);    /* 降序排序比较函数 */
int compareD(float, float);    /* 升序排序比较函数 */
stu *read(FILE *fp, int m, int n);
void sort(stu *stud, int mode, int sub, int n);
void print(pstu stud, int n);
CmpFunPtr setmode(int mode);        /* 返回一个CmpFunPtr类型的函数指针 */

int main()
{
    struct STUDENT *stud;
    FILE *fp;
    int m, n, mode, sub;

    scanf("%d%d%d%d",&m, &n, &mode, &sub);
    if(m < 0 || m > M || n < 0 || n+m > M || (mode != 1 && mode != 2) || (sub != 0 && sub !=1 && sub != 2))
    {
        printf("error!\n");
        exit(0);
    }
    fp = fopen("stud.dic", "rb");
    if(fp == NULL )
        exit(0);
    stud=read(fp, m, n);
    sort(stud, mode, sub, n);
    print(stud, n);
    free(stud);
    fclose(fp);

    return 0;
}

CmpFunPtr setmode(int mode)
{
    if (mode == 1)
        return compareD;
    else
        return compareA;
}
void print(pstu stud, int n)
{
    int i;
    for(i = 0; i < n; i++)
    {
       printf("%dth: %d %s %.2f %.2f %.2f\n", i, stud[i].studentID,
              stud[i].studentName, stud[i].score[0], stud[i].score[1], stud[i].score[2]);
    }
}

int compareA(float x, float y)
{
    return x > y;
}
int compareD(float x, float y)
{
    return x < y;
}
stu *read(FILE *fp, int m, int n)
{
    stu *stud = (stu *)malloc(n * sizeof(stu));
    if (stud == NULL)
    {
        exit(1);
    }

    fseek(fp, m * sizeof(stu), SEEK_SET);
    fread(stud, sizeof(stu), n, fp);

    return stud;
}

void sort(stu *stud, int mode, int sub, int n){
	
 	// 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法。
    // 冒泡排序、插入排序、归并排序、基数排序是稳定的排序算法。
	
	
//	  //冒泡 
//    for (int i = 0; i < n; i++){
//        for (int j = 0; j < n-1; j++){
//        	if (mode == 1){  // 升序 
//	            if (stud[j].score[sub] > stud[j+1].score[sub]){
//	                stu temp = stud[j];
//	                stud[j] = stud[j+1];
//	                stud[j+1] = temp;
//	            }	        		
//			}else{ // 降序 
//	            if (stud[j].score[sub] < stud[j+1].score[sub]){
//	                stu temp = stud[j];
//	                stud[j] = stud[j+1];
//	                stud[j+1] = temp;
//	            }				
//			}
//        }
//    }
	// 选择 1.0
    for (int i = 0; i < n - 1; i++){
        for (int j = i+1; j < n; j++){
        	if (mode == 1){  // 升序 
	            if (stud[j].score[sub] < stud[i].score[sub]){ // 比该位置小就换 
			    	stu temp = stud[i];
			        stud[i] = stud[j];
			        stud[j] = temp;
	            }	        		
			}else{ // 降序 
	            if (stud[j].score[sub] > stud[i].score[sub]){
			    	stu temp = stud[i];
			        stud[i] = stud[j];
			        stud[j] = temp;
	            }				
			}
    	}
	}
//	// 选择 2.0
//    for (int i = 0; i < n - 1; i++){
//    	int idx = i;
//        for (int j = i+1; j < n; j++){
//        	if (mode == 1){  // 升序 
//	            if (stud[j].score[sub] < stud[idx].score[sub]){
//					idx = j;
//	            }	        		
//			}else{ // 降序 
//	            if (stud[j].score[sub] > stud[idx].score[sub]){
//					idx = j;
//	            }				
//			}
//    	}
//    	stu temp = stud[i];
//        stud[i] = stud[idx];
//        stud[idx] = temp;
//	}
}

A(过 90%)

疑问

        不懂,说我越界了,求大佬指点,wa了20多发。。。。。。。。

题目描述   

        “行程长度编码(Run-Length Encoding,RLE)”是一种无损压缩编码方法,其核心思想是依次记录符号序列中的每个字符(忽略大小写)及其重复出现的次数。例如用户输入字符序列(字符串)AaABBBbCBB,则其RLE编码的结果为3A4B1C2B。
        下面的代码实现对输入字符串的RLE编码,现要求在函数int rle(char *code, const char *seq);及 函数readSeq(char *seq, int n);定义中的五个空白处填充适当的表达式,完成程序功能。
        其中:rle()函数形参seq为长度在(0, 80]间(strlen(seq)>0&&strlen(seq)≤80)的全部由大小写英文字母组成的字符串指针,形参code为RLE编码后的结果字符串指针。编码正常结束函数返回0;如字符串指针seq为空或字符串长度不合法时,不进行编码函数直接返回-1;当字符串seq中出现非英文字母的其他字符时,也不进行编码函数直接返回-2。
        readSeq()从键盘读取最多n个字符到seq字符串中,以回车符或EOF字符为结束标志。

输入1:

KAAAEE

输出1:

1K3A2E

输入2:

aaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbb

输出2:

10A10B10A10B10A10B10A10B

输入3:

abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefab

输出3:

1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B

代码

// A. 
#include <stdio.h>
#include <string.h>

#define MAX_SEQ_LEN 80

int rle(char *code, const char *seq);
int readSeq(char *seq, int n);

int main()
{
	
    char seq[MAX_SEQ_LEN + 1] = { 0 };
    char code[2 * MAX_SEQ_LEN + 1];
    int r;

    readSeq(seq, MAX_SEQ_LEN);
    r = rle(code, seq);
    switch (r) {
    case 0:
        printf("%s\n", code);
        break;
    case -1:
        printf("Length is inValid.\n");
        break;
    case -2:
        printf("Has inValid character.\n");
        break;
    }
    return 0;
}

/* 以上代码禁止提交 */
int readSeq(char *seq, int n)
{
    int ch, k;
    k = 0;
    while ((ch = getchar())) {
        if (ch == '\n' || ch == EOF || k == n) break;  // if (__________(1)_________)
        seq[k++] = ch;
    }

    seq[k] = '\0';   // _____(2)______;
    return k;
}

int rle(char *code, const char *seq)
{
    int i, len = 0;
    if (strlen(seq) <= 0 || strlen(seq) > 80) return -1;  // if (________(3)_______)
    const char *p = seq; // p = seq; 
//    char *ptr = code;
    
    // while (*p != '\0' && strlen(code) < strlen(seq)*2-1)   
    while (*p) {   // while (____(4)____)
        char token = *p;
        i = 1;
        token &= 0xDF;
        if (token > 'Z' || token < 'A')
            return -2;
        while ((*(++p) == token || *(p) == token+32) && *p != '\0'){ // while (___(5)___)
            i++;
        }
//		while (1){
//			p++;
//			if (*p == '\0') break;
//        	if (*p != token && *p != token+32) break;
//			i++; 
//		}
        len = sprintf(code, "%d%c", i, token);
		code += len;
    }
    *code = '\0';
//    code = ptr;
    return 0;
}

// aaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbb
// abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefab

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王业强

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值