C语言:数组,综合案例:《学生成绩管理系统》

发布文章为共享知识以及个人学习笔记使用,持续不定时更新

数组

字符串基础操作

在用格式化说明符%s进行输入输出时,其输入输出项均为数组名。但在输入时,相邻两个字符串之间要用空格分隔,系统将自动在字符串后加 \0 。在输出时,遇到结束符 \0 作为输出结束标志。

对于字符串的操作,我们需要使用到一些系统提供的API函数。

字符串输入
scanf

语法:

scanf("%s",数组名);

注意:数组名对应的数组只能是char类型,从控制台输入字符串之后,默认为追加 \0

案例

#include <stdio.h>
int main(int argc,char *argv[])
{
	// 创建一个char数组,用来存储姓名
	char name[20];
	printf("请输入您的名字:\n");
	scanf("%s", name); // 用字符数组接收一个控制台输入的字符串常量
	printf("您的姓名是%s\n", name);
	return 0;
}

运行效果:

 

gets

语法

fgets(数组名,数组容量,stdin);

 

功能

从键盘录入一个字符串常量到字符数组,返回字符数组的地址(首地址,默认返回的地址,一般用12位16进制数表示)

说明

采用fgets进行字符串输入,可获取所有输入的字符串,包含\n,在实际的字符串处理时,我们可能需要手动处理\n

案例

#include <stdio.h>
int main(int argc,char *argv[])
{
    // 创建一个字符数组,用来存储姓名
	char name[20]; // 只是创建数组,必须指定容量;如果初始化,可以省略容量。
	// 计算数组容量
	int len = sizeof(name) / sizeof(name[0]);
	printf("请输入您的姓名:\n");
	fgets(name, len, stdin);
	printf("您的姓名是%s\n", name);
	return 0;
}

运行效果:

 

注意:

① 如果输入的字符串不包括空格或换行,可以使用scanf或者fgets

② 如果输入的字符串包括空格或换行,只能使用fgets

gets 危险的【C11移出】

语法:

gets(数组名);

 

功能:

从键盘录入一个字符串常量到字符数组,返回字符数组的地址(首地址,默认返回的地址,一般用12位16进制数表示)

说明:

采用gets进行字符串输入,可获取所有输入的字符串,包含 \n ,在实际的字符串处理时,我们可能需要处理 \n

案例:

#include <stdio.h>
int main(int argc,char *argv[])
{
	// 创建一个字符数组,用来存储姓名
	char name[20]; // 只是创建数组,必须指定容量;如果初始化,可以省略容量。
	// 计算数组容量
	int len = sizeof(name) / sizeof(name[0]);
	printf("请输入您的姓名:\n");
	gets(name);
	printf("您的姓名是%s\n", name);
	return 0;
}
字符串输出

printf

语法:

printf("%s",数组名);

案例:

#include <stdio.h>
int main(int argc,char *argv[])
{
	// 创建一个字符数组,用来存储姓名
	char name[20]; // 只是创建数组,必须指定容量;如果初始化,可以省略容量。
	// 计算数组容量
	int len = sizeof(name) / sizeof(name[0]);
	printf("请输入您的姓名:\n");
	fgets(name, len, stdin);
	printf("您的姓名是%s\n", name);.// %s支持字符串常量,也支持字符数组,都是以字符串形式输出
	return 0;
}

fputs

语法

 fputs(数组名,stdout);

功能

输出一个字符串

说明

字符串可以包含转义字符(以 \ 开头的字符)

案例

#include <stdio.h>
int main(int argc,char *argv[])
{
	char arr[] = "hi yifanjiao\neat!\n";
	// 第1种输出
	printf("%s", arr);
	// 第2种输出
	fputs(arr, stdout);
	return 0;
}

 

puts 危险的【C11移出】

语法:

puts(数组名称);

功能:

输出一个字符串

说明:

字符串可以包含转义字符

案例:

#include <stdio.h>
int main(int argc,char *argv[])
{
	char arr[] = "hi yifanjiao\neat!\n";
// 第1种输出
	printf("%s", arr);
// 第2种输出
	puts(arr);
    return 0;
}

字符串相关函数

字符串拼接

语法

strcat(字符数组,需要拼接的字符串或者字符数组或者字符指针);

解释:

① 参数1必须是字符数组;参数2可以是字符数组、可以是字符串常量、还可以是字符指

针。

② 这里的参数2被拼接到了参数1,所以参数1的剩余空间足够大,要能够容纳参数2。

引入:

#include <string.h>

案例:

  • 需求:将两个字符串拼接为一个字符串

  • 分析:

  • 代码:

    #include <stdio.h>
    // 使用字符串相关函数需要引入必要的头文件
    #include <string.h>
    int main(int argc,char *argv[])
    {
    	// 创建一个字符数组,用来接收控制台输入
    	char name[20];
    	printf("请输入您的名字:\n");
    	// 通过控制台输入字符串(支持空格)
    	fgets(name, sizeof(name) / sizeof(name[0]), stdin);
    	// 输出拼接 strcat返回拼接后的字符串
    	fputs(strcat(name, "你好!"), stdout);
    	printf("\n");
    	// char str[50];
    	// fputs(strcat(str, strcat(name, "你好!")), stdout);
        return 0;
    }

    注意:

    ① 参数1 必须是字符数组,长度必须足够大,以便于能够容纳被链接的字符串。

    ② 连接后系统将自动取消 参数1 后面的结束符 \0

    ③ 参数2 可以是字符数组名,也可以是指针,也可以是字符串常量,如:strcat(s1,"def"); strcat(s1,s2);

 

字符串拷贝

语法:

strcpy(数组名,字符串);

解释:简单来说,类似于将一个字符串赋值给一个字符数组。这个函数一般用来做赋值处理。

引入:

#include <string.h>

说明:这个函数适合给字符串赋值

char str[20] = "**培"; // 正确,字符数组的初始化,字符串初始化
char str[20] = "**培"; str = "*佳"; // 错误,不能对数组进行赋值
char str[20] = "**凡"; strcpy(str, "**林");// 正确,利用函数实现类似赋值的操作

注意: strcat和strcpy的区别:

  • strcat: 凡 + 鸿 → 鸿 (追加)

  • strcpy: 凡 + 鸿 → **鸿 (覆盖)

案例:

#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
	// 需求:对数组赋值
	char name[50] = "hello";
	printf("打印初始化后的数组:%s\n", name);
	// 对一个数组赋:
	// name = "**鸿"; // 数组一旦创建,就无法改变,所以不能对数组进行赋值
	// 通过 strcpy(字符数组,字符数组/字符常量/字符指针)实现给数组赋值
	strcpy(name, "my");// my | myllo
	printf("打印重新赋值后的数组:%s\n", name);
	return 0;
}

字符串比较

语法:

strcmp(字符串1,字符串2);

注意:这里的字符串可以是字符串常量、字符数组、字符指针。

引入

#include <string.h>

功能

如果是英文,比较两个字符串对应位置字符ASCII的大小

返回值

  • 如果字符串1 等于 字符串2,返回0

  • 如果字符串1 大于 字符串2,返回正数(>0)

  • 如果字符串1 小于 字符串2,返回负数(<0)

说明

① 执行这个函数时,自左向右逐个比较对应字符的ASCII的值,直到发现了不同字符或字符串结束符\0为止

② 对字符串不能用数值型比较符。比如: "abc" == "abc" ,这种比较是错误的。

③ 字符串1与字符串2可以是字符数组、字符指针、字符串常量

案例:

  • 需求:通过控制台输入用户名和密码,并进行校验

  • 代码:

#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
	// 用户登陆案例
	// 创建两个变量,用来存储用户名和密码
	char username[20], password[8];
	printf("---------用户登录--------\n");
	printf("请输入您的用户名:\n");
	scanf("%s",username);// 数组名本身就是一个地址(首元素的首地址)
	printf("请输入您的密码:\n");
	scanf("%s",password);
	// 校验
	if (!strcmp(username,"admin") && !strcmp(password,"123456"))
	// 相等:strcmp(..) == 0
	printf("登录成功!\n");
	else
	printf("用户名或者密码错误!\n");
	return 0;
}
  • 运行结果:

 

字符串长度

语法:

strlen(字符串);

 引用:

#include <string.h>

注意:返回字符串中包含的字符的实际个数。遇到\0结束,不包含\0;如果数组中不存在\0,就以数组的实际长度作为字符串长度

案例:

需求:字符串长度案例

代码:

#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
	// 测试数据1
	char s1[] = {'h','i','\0','h','i','\0'};
	printf("数组长度:%lu\n字符串长度:%lu\n",
	sizeof(s1)/sizeof(s1[0]), strlen(s1));// 数组长度:6,字符串长度:2
	// 测试数据2
    char s2[] = "hi\0hi\0";// 使用双引号包裹的内容称之为 字符串常量,字符串常量默认会有一个结尾的\0
	printf("数组长度:%lu\n字符串长度:%lu\n",
	sizeof(s2)/sizeof(s2[0]), strlen(s2));// 数组长度:7,字符串长度:2
	// 测试数据3
	char s3[] = {'h','e','l','l','o'};// strlen()判断一个字符串的长度,优先判断是否存在\0,如果不存在,就返回数组实际长度,因编译器原因,处理机制也有所不同。
	printf("数组长度:%lu\n字符串长度:%lu\n",
	sizeof(s3)/sizeof(s3[0]), strlen(s3));// 数组长度:5,字符串长度:5,这种写法不安全,不同编译器编译结果不同
	// 测试数据4
	char s4[] = "hello";
	printf("数组长度:%lu\n字符串长度:%lu\n",
	sizeof(s4)/sizeof(s4[0]), strlen(s4));// 数组长度:6,字符串长度:5
	return 0;
}

案例

  • 需求:输入一行字符,统计其中有多少个单词,单词之间使用空格隔开。举例:I LOVE YOU

  • 分析:采用通过空格统计单词的方法。具体是:

① 用连续若干个空格算一个、一行开头的空格不计的方法决定单词数目;

② 从第一个字符开始逐个检查字符串中的每一个字符。若查到某一字符非空格,而其前面的字符是空格,则表示新单词开始,让计数变量num++。否则,当前字符非空格,前面字符也非空格,则非新单词,num不变;

③ 用变量word=0或1来表示前面字符是空格或不是空格。则:

  • 代码:

    #include <stdio.h>
    #include <ctype.h>
    int main(int argc,char *argv[])
    {
    	// 创建一个数组,用来接收控制台录入的字符串
    	char string[100];
    	// 创建2个变量,word:统计字符是否是空字符(空字符:0,非空字符:1),num:用来统计单词个数
    	int num = 0, word = 0;
    	// 创建一个变量,用来存储遍历到的字符
    	char c;
    	// 通过控制台录入字符串
    	printf("请输入一句话:\n");
    	fgets(string, sizeof(string)/sizeof(string[0]), stdin);
    	// 遍历
    	for (int i = 0; (c = string[i])!='\0'; i++)
    	{
    		if (isspace(c)) // 判断一个字符是否是空格,等价于 if (c == '')
                {
    				// 如果是空格,标记
    				word = 0;
    			}
    			else
    			{
    				// 如果上一个字符是空格,就需要统计单词
    				if (!word) // 等价于 word == 0
    				{
    					// 标记word为非空格
    					word = 1;
    					// 统计单词个数
    					num ++;
    				}
    			}
    		}
    	printf("%s\n中有%d个单词!\n", string, num);
    	return 0;
    }

    案例

    有三个字符串,要求找出其中最大者。

    分析:设计一个二维字符数组str3,即3行20列。

    ① 可把str[0]、str[1]、str[2]看作3个一维字符数组,各有20个元素;

    ② 用gets函数分别输入3个字符串到str[0]、str[1]、str[2]中 ;

    ③ 用字符串函数对str[0]、str[1]、str[2]进行比较,得到最大者

 

#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
	// 创建一个数组,用来存储最大的字符串
	char max[50];
	// 创建一个数组,用来存储3个用来参与比较的字符串
	char str[3][50]/* = {"apple","orange","egg"}*/;
	int i;
	// 通过循环控制台输入
	printf("请输入3个测试字符串:\n");
	for (i = 0; i < 3; i++)
	{
		fgets(str[i],50,stdin);
	}
	// 比较
	if (strcmp(str[0],str[1]) > 0) strcpy(max, str[0]);
	else strcpy(max,str[1]);
	if (strcmp(str[2],max) > 0) strcpy(max,str[2]);
	printf("\n三个字符串中最大的字符串是%s\n!", max);
	return 0;
}

综合案例:学生成绩管理系统

需求

  1. 存储最多50名学生的信息(不使用结构体)

  2. 每个学生包含:

    • 学号(字符数组)

    • 姓名(字符数组)

    • 3门课程成绩(一维数组)

  1. 实现功能菜单:

    • 添加学生信息

    • 显示所有学生信息

    • 计算学生平均分

    • 查找最高分科目

    • 退出系统

代码

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

/*系统定义常量*/
#define MAX_STU 50      //系统支持的最大学生数量
#define NAME_LEN 20     //学生姓名最大长度
#define ID_LEN 8        //学生学号最大长度
#define COURSE_NUM 3    //课程数量

/*全局数据存储数组*/
char stu_id[MAX_STU][ID_LEN];       //存储学生学号
char stu_name[MAX_STU][NAME_LEN];   //存储学生姓名
int scores[MAX_STU][COURSE_NUM];    //存储学生成绩,每个学生3门
int stu_count = 0;                  //记录当前系统中学生实际数量

/*课程名称定义*/
char COURSE_NAMES[COURSE_NUM][NAME_LEN] = {"语文", "数学", "英语"};

//查找科目最高分学生
void find_max()
{
    //检查系统中是否有学生
    if(stu_count == 0) 
    {
        printf("系统提示:当前没有学生信息\n");
        return;
    }
    
    int max_score = -1; //最高分
    int max_stu_idx = -1; //最高分学生下标
    int max_course_idx = -1; //最高分科目下标
   
    //遍历所有学生和所有科目
    for(int i = 0; i < stu_count; i++)
    {
        for(int j = 0; j < COURSE_NUM; j++)
        {
            //如果找到最高分,就替换
            if(scores[i][j] > max_score)
            { 
                max_score = scores[i][j];
                max_stu_idx = i;
                max_course_idx = j;
            }
        }
    }
    
    //输出最高分信息
    printf("系统最高分:\n");
    printf("学生:%s\n", stu_name[max_stu_idx]);
    printf("学号:%s\n", stu_id[max_stu_idx]);
    printf("科目:%s\n", COURSE_NAMES[max_course_idx]);
    printf("分数:%d\n\n", max_score);
}


//计算指定学生平均分
void calc_avg()
{
    //检查系统中是否有学生
    if(stu_count == 0)
    {
        printf("系统提示:当前没有学生信息\n");
        return;
    }
    
    //创建一个数组,存储控制台输入的学号
    char target_id[ID_LEN];
    printf("请输入要查询的学生学号:\n");
    scanf("%7s", target_id);

    //清空缓冲
    while(getchar() != '\n');

    //遍历查找学生
    for(int i = 0; i < stu_count; i++)
    {
        //比较字符串是否相等 strcmp
        if(strcmp(stu_id[i], target_id) == 0)
        {
            //计算总分
            float sum = 0;
            for(int j = 0; j < COURSE_NUM; j++) sum += scores[i][j];

            //显示平均分
            printf("学生 %s(学号 %s)的平均分:%.2f\n\n", stu_name[i], stu_id[i], sum / COURSE_NUM);
            
            //提前结束函数
            return;
        }
    }
    printf("系统提示:未找到学号为%s的学生\n\n", target_id);
}

//显示所有学生信息
void show_all()
{
    //检查系统中是否有学生
    if(stu_count == 0)
    {
        printf("当前没有学生信息 \n");
        return; //提前结束函数,由于函数没有返回值,所以仅保留return关键字
    }
    printf("\n-----------当前学生信息------------\n");

    //表头
    printf("%-10s%-20s", "学号", "姓名");
    
    //科目
    for(int i = 0; i < COURSE_NUM; i++) printf("%-10s", COURSE_NAMES[i]); //语文 数学 英语
    printf("\n");
    
    //表格内容:学生信息
    for(int i = 0; i < stu_count; i++)
    {
        printf("%-10s%-20s", stu_id[i], stu_name[i]);  //学号 姓名

        //取出成绩
        for(int j = 0; j < COURSE_NUM; j++) printf("%-10d", scores[i][j]);
        printf("\n");
    }
    printf("系统统计共%d名学生", stu_count);
}   


//菜单显示
void show_menu()
{
    printf("\n------------菜单------------");
    printf("1.添加学生信息\n");
    printf("2.显示所有学生信息\n");
    printf("3.查询平均分\n");
    printf("4.查询最高分科目\n");
    printf("5.退出\n");
}

//获取用户输入的成绩并验证
int get_valid_score(const char* course)
{
    int score; //存储控制台输入的成绩
    
    //循环录入成绩,校验
    do
    {
        printf("请输入%s成绩(0~100)", course);
        scanf("%d", &score);

        //清理缓存
        while(getchar() != '\n');

        //验证成绩范围
        if(score < 0 || score > 100) printf("输入错误,成绩必须在0~100之间\n");
        
    } while(score < 0 || score > 100);
    return score;
}

//添加学生信息
void add_student()
{
    //检查学生添加是否已达上限
    if(stu_count >= MAX_STU)
    {
        printf("系统提示:学生数量已达上限%d人!\n", MAX_STU);
        return;  //函数提前结束,后续代码不再执行
    }
    printf("\n ----正在添加第%d个学生----", stu_count + 1);
    
    //1.输入学号
    printf("请输入学号(最多%d位):\n", ID_LEN - 1);
    scanf("%7s", stu_id[stu_count]);  //截取控制台输入字符串的前7位

    //清理缓冲区
    while(getchar() != '\n');
    
    //2.输入姓名
    printf("请输入姓名(最多%d位字符):\n", NAME_LEN - 1);
    fgets(stu_name[stu_count], NAME_LEN, stdin);
    
    //去除姓名末尾换行符
    stu_name[stu_count][strcspn(stu_name[stu_count], "\n")] = '\0';

    //3.输入成绩
    printf("请依次输入各科成绩:\n");
    for(int i = 0; i < COURSE_NUM; i++)
    {
        //循环一次就录入一门成绩,防止重复书写代码,封装在函数中
        scores[stu_count][i] = get_valid_score(COURSE_NAMES[i]);
    }
    //增加学生计数
    printf("成功添加学生:%s(学号:%s)\n", stu_name[stu_count], stu_id[stu_count]);
}

/*
 *入口函数
 * */
int main(int argc, char *argv[])
{
    int choice; //存储用户的菜单选项
    
    //设计头
    printf("-----------------------------------------\n");
    printf("|            学生成绩管理系统           |\n");
    printf("|               作者:  jpz             |\n");
    printf("-----------------------------------------\n");

    //主循环
    while(1)
    {
        //显示菜单
        show_menu();

        //获取用户输入并验证
        if(scanf("%d", &choice) != 1)
        {
            //清空输入缓冲区
            while(getchar() != '\n');
            printf("输入错误,请输入1~5的数字!\n");
            continue;   //跳过未执行代码
        }
        //根据用户选择执行对应功能
        switch(choice)
        {
            case 1:
                //添加学生信息
                add_student();
                break;
            case 2:
                //显示学生信息
                show_all();            
                break;
            case 3:
                //查询平均分
                calc_avg();
                break;
            case 4:
                //查询科目最高分的学生
                find_max();
                break;
            case 5:
                printf("感谢使用!\n");
                return 0;
            default:
                printf("输入错误,请输入1~5的数字!\n");
        } 
    }
    return 0;
}

发布文章为共享知识以及个人学习笔记使用,持续不定时更新 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值