C语言学习笔记:数组与字符串及综合案例
内容提要
- 数组
- 字符串基础操作
- 字符串相关函数
- 综合案例:学生成绩管理系统v1.0
数组与字符串基础操作
在用格式化说明符%s
进行输入输出时,其输入输出项均为数组名。输入时,相邻字符串需用空格分隔,系统会自动在字符串后加\0
;输出时,遇到\0
则结束输出。字符串操作需使用系统提供的API函数。
字符串输入
scanf
- 语法:
scanf("%s", 数组名);
- 说明:数组需为
char
类型,输入后默认追加\0
。 - 注意:输入字符串不能包含空格,否则遇空格结束。
- 案例:
#include <stdio.h>
int main(int argc, char *argv[]) {
char name[20]; // 存储姓名的字符数组
printf("请输入您的名字:\n");
scanf("%s", name); // 接收输入的字符串
printf("您的姓名是%s\n", name);
return 0;
}
fgets
- 语法:
fgets(数组名, 数组容量, stdin);
- 功能:从键盘录入字符串到字符数组,返回数组首地址(12位16进制数)。
- 说明:可接收含空格或换行的字符串,需手动处理可能包含的
\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(数组名);
- 功能:从键盘录入字符串到字符数组,返回数组首地址。
- 说明:可接收含空格/换行的字符串,但存在缓冲区溢出风险,已被C11标准移除。
字符串输出
printf
- 语法:
printf("%s", 数组名);
- 说明:
%s
支持字符串常量、字符数组,均以字符串形式输出,遇\0
结束。 - 案例:同
fgets
案例中的输出部分。
fputs
- 语法:
fputs(数组名, stdout);
- 功能:输出字符串,支持包含转义字符(以
\
开头)。 - 案例:
#include <stdio.h>
int main(int argc, char *argv[]) {
char arr[] = "hi yifanjiao\neat!\n";
// 两种输出方式
printf("%s", arr);
fputs(arr, stdout);
return 0;
}
puts(危险,C11移出)
- 语法:
puts(数组名称);
- 功能:输出字符串,支持转义字符,但存在安全风险,已被C11移除。
字符串相关函数
需引入头文件#include <string.h>
。
字符串拼接(strcat)
- 语法:
strcat(字符数组, 需要拼接的字符串/字符数组/字符指针);
- 说明:
- 参数1必须是字符数组,且剩余空间需足够容纳参数2;
- 拼接时会删除除最后一个
\0
以外的所有\0
。
- 案例:
#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);
fputs(strcat(name, "你好!"), stdout); // 拼接并输出
printf("\n");
return 0;
}
字符串拷贝(strcpy)
- 语法:
strcpy(数组名, 字符串);
- 功能:类似将字符串赋值给字符数组(数组不可直接赋值,需用此函数)。
- 区别:
strcat
是追加(如"a"+“b"→"ab”),strcpy
是覆盖(如"a"+“b"→"b”)。 - 案例:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char name[50] = "hello";
printf("初始化后: %s\n", name);
strcpy(name, "my"); // 覆盖原有内容
printf("赋值后: %s\n", name);
return 0;
}
字符串比较(strcmp)
- 语法:
strcmp(字符串1, 字符串2);
- 返回值:
- 相等返回0;
- 字符串1>字符串2返回正数;
- 字符串1<字符串2返回负数。
- 说明:逐字符比较ASCII值,不可用
==
直接比较字符串。 - 案例:
#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")) {
printf("登录成功!\n");
} else {
printf("用户名或密码错误!\n");
}
return 0;
}
字符串长度(strlen)
- 语法:
strlen(字符串);
- 功能:返回字符串实际字符数(遇
\0
结束,不含\0
;无\0
则返回数组长度)。 - 案例:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char s4[] = "hello";
printf("数组长度: %lu\n字符串长度: %lu\n",
sizeof(s4)/sizeof(s4[0]), strlen(s4)); // 数组长度6,字符串长度5
return 0;
}
综合案例:学生成绩管理系统v1.0
需求
- 存储最多50名学生信息(无结构体);
- 每个学生包含:学号(字符数组)、姓名(字符数组)、3门课程成绩(一维数组);
- 功能:添加学生信息、显示所有信息、计算平均分、查找最高分科目、退出系统。
代码实现
#include <stdio.h>
#include <string.h>
/* 系统常量定义 */
#define MAX_STU 50 // 最大学生数量
#define NAME_LEN 20 // 姓名最大长度(含\0)
#define ID_LEN 8 // 学号最大长度(含\0)
#define COURSE_NUM 3 // 课程数量
/* 全局数据存储数组 */
char stu_id[MAX_STU][ID_LEN]; // 学号数组
char stu_name[MAX_STU][NAME_LEN]; // 姓名数组
int scores[MAX_STU][COURSE_NUM]; // 成绩数组
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, 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("请输入要查询的学生学号:");
scanf("%7s", target_id);
while (getchar() != '\n'); // 清空缓冲区
// 查找学生
for (int i = 0; i < stu_count; i++) {
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;
}
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("\n系统统计:共%d名学生\n\n", stu_count);
}
/**
* 获取有效成绩(0~100)
*/
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个学生 ===\n", stu_count + 1);
// 输入学号
printf("请输入学号(最多%d位数字):", ID_LEN - 1);
scanf("%7s", stu_id[stu_count]);
while (getchar() != '\n'); // 清理缓冲区
// 输入姓名
printf("请输入姓名(最多%d位字符):", NAME_LEN - 1);
fgets(stu_name[stu_count], NAME_LEN, stdin);
// 去除换行符
stu_name[stu_count][strcspn(stu_name[stu_count], "\n")] = '\0';
// 输入成绩
printf("请依次输入各科成绩:\n");
for (int i = 0; i < COURSE_NUM; i++) {
scores[stu_count][i] = get_valid_score(COURSE_NAMES[i]);
}
stu_count++;
printf("成功添加学生:%s(学号:%s)\n",
stu_name[stu_count - 1], stu_id[stu_count - 1]);
}
/**
* 显示主菜单
*/
void show_menu() {
printf("\n======== 主菜单 ========\n");
printf("1. 添加学生信息\n");
printf("2. 显示所有学生信息\n");
printf("3. 查询学生平均分\n");
printf("4. 查询最高分科目\n");
printf("5. 退出系统\n");
}
/**
* 入口函数
*/
int main(int argc, char *argv[]) {
int choice;
printf("= 学生成绩管理系统 V1.0 =\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;
}
章节作业
一维数组练习题
- 键盘录入数列,用冒泡排序从大到小排序;
- 输入年、月、日,计算该日是当年第几天;
- 录入数列,求最大数、最小数、均值;
- 判断数列是否为回文(如12321、abba);
- 存储10个整数,输入一个数,找出其下标;
- 录入10个学员成绩:
- 输出不及格成绩及下标;
- 求最高分、最低分的下标;
- 求总成绩及平均分。
二维数组练习题
- 二维数组中查找用户输入的数,返回行列位置;
- 求二维整型数组所有元素平均值、每行最大值、每列最小值;
- 计算行列相等数组的主对角线元素和;
- 计算矩阵下三角元素的和;
- 电影院某排某列有礼包(行和列的平方和为512),找出位置(20排,每排25座)。
字符数组练习题
- 读取字符串并反转输出;
- 判断字符串是否为回文。
思考题(选做)
- 求出矩阵的鞍点(行上最大且列上最大的元素)。