【C 语言入门】系列共发布了 5 篇文章,分别为:
- 《【C 语言入门】数据类型》
- 《【C 语言入门】常量与变量》
- 《【C 语言入门】运算符》
- 《【C 语言入门】控制语句与结构化》
《【C 语言入门】总结例程》
本次通过一个小例程来回顾和整理【C 语言入门】系列的知识点,相信你掌握了这个小例程后,你将进入 C 语言的大门,迎接 C 语言编程的大千风情。下面献上例程,本例程已经上传至 GItHub。
- 链接:https://github.com/CherryXiuHuaWoo/C_Primer_Example
- 开发环境:Visual Studio 2017
C 语言入门总结例程
Example:键入5个学生的名称、语文成绩、数学成绩和英语成绩,输出各个学生的成绩等级和各科成绩的排名。源代码如下。
#include<stdlib.h>
#define STUDENT_NUM 5 // 统计总人数
#define SCORE_NUM 3 // 科目总数
/* score 为各科成绩分数.
* score[0] 为语文成绩,
* score[1] 为数学成绩,
* score[2] 为英文成绩.
* grade 为各科成绩的分数等级
* grade[0] 为语文成绩等级,
* grade[1] 为数学成绩等级,
* grade[2] 为英文成绩等级.
* name 为 student name
*/
struct student
{
int score[SCORE_NUM];
char grade[SCORE_NUM];
char name[20];
};
student s_array[STUDENT_NUM]; // 声明学生数组
void input_message(void);
void printf_grade(student *stu_pc);
void bubble_method(int *score_buf, char *stuname_buf);
/*
* Function: 键入每个学生的信息,包括:姓名、语文成绩、数学成绩和英语成绩
* Note:
* 先键入学生名称,再键入语文成绩,再键入数学成绩,最后键入英语成绩
* 信息键入需要注意空格!
*/
void input_message(void)
{
// 依据输入的信息,输出每个学生的成绩等级
for (int i = 0; i < STUDENT_NUM; i++)
{
printf("Enter the num %d student's message:\r\n", i);
scanf("%s %d %d %d", &s_array[i].name, &s_array[i].score[0], &s_array[i].score[1], &s_array[i].score[2]);
printf_grade(&s_array[i]);
}
}
/*
* Function: 将单个学生的各科的成绩结果划分等级, 输出各科的成绩等级
* Note:
* [0 , 60) 为 D
* [60, 75) 为 C
* [75, 85) 为 B
* [85, 100] 为 A
* 其余输入值会被认为是错误值,显示 E
*/
void printf_grade(student *stu_pc)
{
for (int i = 0; i < SCORE_NUM; i++)
{
if ((0 <= stu_pc->score[i]) && (60 > stu_pc->score[i]))
{
stu_pc->grade[i] = 'D';
}
else if ((60 <= stu_pc->score[i]) && (75 > stu_pc->score[i]))
{
stu_pc->grade[i] = 'C';
}
else if ((75 <= stu_pc->score[i]) && (85 > stu_pc->score[i]))
{
stu_pc->grade[i] = 'B';
}
else if ((85 <= stu_pc->score[i]) && (100 >= stu_pc->score[i]))
{
stu_pc->grade[i] = 'A';
}
else
{
stu_pc->grade[i] = 'E'; // Error
}
printf("%c ", stu_pc->grade[i]);
}
printf("\r\n");
}
/*
* Function: 使用冒泡法,对单科成绩进行排名
*/
void bubble_method(int *score_buf, char *stuname_buf)
{
int score_temp;
char *stuname_temp;
for (int i = 0; i < STUDENT_NUM - 1; i++)
{
for (int j = 0; j < STUDENT_NUM - i - 1; j++)
{
score_temp = score_buf[j];
stuname_temp = &stuname_buf[j];
if (score_buf[j] > score_buf[j + 1])
{
score_buf[j] = score_buf[j + 1];
stuname_buf[j] = stuname_buf[j + 1];
score_buf[j + 1] = score_temp;
stuname_buf[j + 1] = *stuname_temp;
}
}
}
}
/*
* Function: main
* 循环键入 5 个学生的 student name,语文、数学和英语成绩。
* 输出每个学生的各科成绩等级。
* 输出各科成绩的排名。
*/
int main(void)
{
int score_temp[STUDENT_NUM]; // 声明临时成绩数组,用于成绩排序
char *studentname_temp[STUDENT_NUM]; // 声明临时学生姓名数组,用于跟踪成绩排序结果
int i, k;
input_message();
// 输出各科成绩排名结果
for (k = 0; k < SCORE_NUM; k++)
{
// 暂存学生姓名和单科成绩
for (i = 0; i < STUDENT_NUM; i++)
{
score_temp[i] = s_array[i].score[k];
studentname_temp[i] = s_array[i].name;
}
// 采用冒泡法对各科成绩进行排序
bubble_method(&score_temp[0], studentname_temp[0]);
// 输出各科成绩信息
switch (k)
{
case 0:
printf("Chinese Ranking:\r\n");
break;
case 1:
printf("Math Ranking:\r\n");
break;
case 2:
printf("English Ranking:\r\n");
break;
default:
printf("Error\r\n");
}
for (i = STUDENT_NUM - 1; i >= 0; i--)
{
printf("Num %d is %s, score = %d\r\n", STUDENT_NUM - i, studentname_temp[i], score_temp[i]);
}
}
return 0;
}
运行结果:
例程知识点梳理
下面将重点的知识点从例程中抽离出来,逐个分析。
数据类型
基本数据类型:这里没什么好说的,重点关注它们的取值范围即可,例程中主要用到的是 int 、char 这两种基本数据类型。
派生数据类型:例程中使用了结构体、数组两种派生数据类型。其中,
- 结构体数据类型 student 包含 3 个成员,分别为 int 类型的 score 数组、char 类型的 grade 数组和 char 类型的 name 数组。
- 例程中使用结构体类型 student 创建了一个数组长度为 STUDENT_NUM 的全局数组变量 s_array。s_array 数组的每个数组元素均是 student 结构体类型,即:每个数组元素包含 3 个成员(score、grade 和 name) 。
struct student
{
int score[SCORE_NUM];
char grade[SCORE_NUM];
char name[20];
};
student s_array[STUDENT_NUM]; // 声明学生数组
那怎么给 s_array 数组的数组元素赋值呢?下面的 Example 演示了怎么给数组元素 s_array[0] 的 score 成员赋值。
Example:给数组元素 s_array[0] 的 score 成员赋值。
// score 成员具有 3 个数组元素,需要单独赋值
s_array[0].score[0] = 0;
s_array[0].score[1] = 1;
s_array[i].score[2] = 2;
指针类型:为追求更快的执行速度和效率,例程中的 printf_grade 和 bubble_method 函数都使用指针作为传参。相对于将整个数组拷贝到函数,采用指针作为传参的执行速度更快、效率更高。 下面通过 Example 分析 printf_grade 函数是怎么使用指针做传参,以及使用过程是怎么进行的。
Example:
- printf_grade 函数的传参为 student 类型的 stu_pc 指针,即传入参数是个地址。
void printf_grade(student *stu_pc)
- 引用 printf_grade 函数时,将 s_array 数组的某个元素(为 student 类型)的地址作为实参传递给 printf_grade 函数。
printf_grade(&s_array[i]);
- 通过成员运算符 -> 访问 stu_pc 指针所指的变量的成员。
if ((0 <= stu_pc->score[i]) && (60 > stu_pc->score[i]))
{
stu_pc->grade[i] = 'D';
}
空类型:例程中的 input_message、printf_grade 和 bubble_method 函数的类型均是空类型,这意味着这 3 个函数均是没有返回值。其中,input_message 的传参为 void,也就是说 input_message 是不需要传入参数。
void input_message(void);
void printf_grade(student *stu_pc);
void bubble_method(int *score_buf, char *stuname_buf);
常量与变量
常量:使用字符 STUDENT_NUM 和 SCORE_NUM 分别代替整形常量 5 和 3 。
#define STUDENT_NUM 5 // 统计总人数
#define SCORE_NUM 3 // 科目总数
控制语句与结构化
for 语句实现循环结构:例程在很多地方使用 for 语句实现循环结构。比如:input_message 函数使用 for 循环实现了循环键入学生信息的功能; printf_grade 函数使用 for 循环实现了循环打印某个学生的各科科目成绩等级;bubble_method 函数更是使用嵌套的 for 语句实现了冒泡排序法。
if 语句实现选择结构:例程中的 printf_grade 函数使用了 if-elseif-…-else 实现了将学生各科的成绩结果划分等级的功能。bubble_method 函数使用了 if 语句实现了冒泡排序中的比较换位功能。