《程序设计基础(C语言)》实验指导
前言
本实验指导旨在配合《程序设计基础(C语言)》理论课程,通过一系列由浅入深的实验,帮助学生巩固课堂所学知识,培养独立分析问题、解决问题的能力,并养成良好的编程习惯,编程是一门实践性极强的学科,希望同学们能认真对待每一个实验,勤于动手,善于思考,最终掌握C语言编程的精髓。
第一部分:实验总体要求
实验目的
- 掌握语法: 熟练掌握C语言的基本语法、数据类型、运算符、表达式、控制流程(顺序、选择、循环)等。
- 理解结构: 深入理解C语言的模块化思想,熟练掌握函数的定义、调用和参数传递。
- 驾驭数据: 掌握数组、指针、结构体等复杂数据类型的使用,理解其在内存中的组织形式。
- 文件操作: 学会使用文件进行数据的持久化存储和读取。
- 培养能力: 培养逻辑思维能力、算法设计能力、程序调试能力和代码规范能力。
实验准备
- 理论学习: 每次实验前,务必认真复习相关的理论知识。
- 环境熟悉: 熟悉C语言的开发环境,如 Visual Studio (VS)、Dev-C++、Code::Blocks 或 Linux下的GCC/GDB,本指导将以VS为例进行讲解,但核心思想适用于任何环境。
- 工具掌握: 学会使用IDE的编译、运行、调试(设置断点、单步执行、查看变量)等功能。
实验步骤
- 分析问题: 仔细阅读实验题目,理解题目的具体要求和输入输出格式。
- 设计算法: 用自然语言、流程图或伪代码描述解决问题的步骤。
- 编写代码: 根据算法,使用C语言编写源程序(
.c文件),注意代码的规范性和可读性。 - 编译调试:
- 编译: 检查语法错误,根据编译器的错误提示,定位并修改错误。
- 链接: 检查函数调用、库文件链接等错误。
- 运行: 执行程序,检查逻辑错误(运行时错误)。
- 调试: 如果结果不正确,使用调试工具(如VS的“调试”窗口)设置断点,单步跟踪,观察变量值的变化,找出逻辑漏洞。
- 测试完善: 使用多组不同的测试数据(包括正常情况、边界情况和异常情况)来验证程序的正确性,并进行完善。
- 撰写报告: 实验结束后,按要求撰写实验报告。
实验报告规范
一份完整的实验报告应包含以下内容:
- 实验名称: 如“实验三:选择结构程序设计”。
- 实验目的: 简述本次实验要达成的目标。
- 实验环境: 操作系统、编译器及版本号。
- 列出本次实验完成的编程题目。
- 算法设计与描述:
- 对每个题目,给出详细的算法思路。
- 可以使用流程图或N-S图来清晰展示程序的控制流程。
- 程序代码:
- 附上经过调试、能正确运行的完整源代码。
- 代码要有必要的注释,说明关键语句的功能。
- 运行结果与分析:
- 附上程序运行的截图,要求包含输入和输出。
- 对结果进行分析,说明程序是如何工作的。
- 实验总结与心得:
- 总结本次实验中学到的知识点和技能。
- 记录在调试过程中遇到的问题及解决方法。
- 反思编程过程中的不足,提出改进方向。
第二部分:实验内容安排
C语言程序设计入门
- 目的:
- 熟悉C语言程序的基本结构(
#include,main函数)。 - 掌握C语言程序的编辑、编译、运行和调试的基本流程。
- 掌握基本输入输出函数
printf和scanf的使用。 - 理解C语言中注释的作用。
- 熟悉C语言程序的基本结构(
- Hello, World!:编写一个程序,在屏幕上输出 "Hello, World!"。
- 简单的数据输入输出:编写一个程序,要求用户输入一个整数和一个浮点数,然后在一行中输出它们的和、差、积、商(保留两位小数),格式如下:
请输入一个整数和一个浮点数,用空格隔开: 10 3.14 整数: 10, 浮点数: 3.14 和: 13.14 差: 6.86 积: 31.40 商: 3.18 - 字符的输入输出:编写一个程序,从键盘读取一个字符,然后输出其ASCII码值和下一个字符。
顺序与选择结构程序设计
- 目的:
- 熟练使用
if、if-else和if-else if-else语句实现选择结构。 - 掌握关系运算符和逻辑运算符的使用。
- 掌握
switch语句的用法。 - 学会使用
getchar()和putchar()处理单个字符。
- 熟练使用
- 判断闰年:输入一个年份,判断其是否为闰年,闰年规则:能被4整除但不能被100整除,或者能被400整除。
- 分段函数求值:编写程序,计算下面分段函数的值。 $$ f(x) = \begin{cases} x^2 - 3x + 2, & x < 1 \ \sqrt{x}, & 1 \le x < 4 \ \log_{10}(x), & x \ge 4 \end{cases} $$
- 简单计算器:实现一个简单的菜单驱动计算器,用户输入两个数字和一个运算符(, , , ),程序输出计算结果,如果运算符非法或除数为0,给出错误提示。
循环结构程序设计
- 目的:
- 熟练掌握
for、while和do-while三种循环语句。 - 理解循环嵌套的概念和应用。
- 掌握
break和continue语句在循环中的作用。 - 学会使用循环解决累加、累乘、穷举等典型问题。
- 熟练掌握
- 求阶乘和:计算
1! + 2! + 3! + ... + 10!的值。 - 素数判断与输出:输入一个正整数
n,判断它是否为素数,然后输出100到200之间的所有素数。 - 图形打印:使用嵌套循环打印以下图形。
- 求阶乘和:计算
函数
- 目的:
- 掌握函数的定义、声明和调用方法。
- 理解函数参数传递(值传递)的机制。
- 掌握函数的返回值类型和
return语句的使用。 - 理解函数的递归调用,并能解决简单的递归问题(如求阶乘、斐波那契数列)。
- 模块化计算器:将实验二中的简单计算器功能改用函数实现,分别编写
add(),subtract(),multiply(),divide()函数来执行加减乘除运算,main()函数负责显示菜单和调用这些函数。 - 最大公约数与最小公倍数:编写两个函数
gcd(a, b)和lcm(a, b),分别用辗转相除法和公式lcm(a, b) = (a * b) / gcd(a, b)来求解两个整数的最大公约数和最小公倍数。 - 递归应用:用递归函数实现斐波那契数列的计算,斐波那契数列定义为:F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2) (n>=2),输入
n,输出F(n)的值。
- 模块化计算器:将实验二中的简单计算器功能改用函数实现,分别编写
数组
- 目的:
- 掌握一维数组和二维数组的定义、初始化和引用。
- 学会使用数组进行批量数据的处理,如排序、查找、统计等。
- 理解数组作为函数参数的传递方式。
- 数组排序:从键盘输入10个整数,存入一个一维数组中,使用冒泡排序或选择排序对数组进行升序排序,并输出排序前后的数组。
- 矩阵转置:定义一个3x3的二维数组,并初始化,编写函数
transpose()将其转置(行列互换),并在主函数中打印转置前后的矩阵。 - 成绩统计:假设一个班级有30名学生,期末考试一门课程,编写程序,完成以下功能:
- 输入30名学生的成绩。
- 计算并输出平均分。
- 统计并输出最高分和最低分。
- 统计各分数段(90-100, 80-89, 70-79, 60-69, 0-59)的人数。
指针
- 目的:
- 掌握指针变量的定义、初始化和基本操作(取地址
&、解引用 )。 - 理解指针和数组的关系,能够使用指针遍历数组。
- 掌握使用指针作为函数参数,实现“传地址调用”,从而在被调函数中修改主调函数的变量。
- 了解函数指针的概念。
- 掌握指针变量的定义、初始化和基本操作(取地址
- 指针与变量:定义两个整型变量
a和b,以及两个指向整型的指针p1和p2,通过指针交换a和b的值,并在交换前后打印a和b的值。 - 指针与数组:使用指针代替数组下标来遍历并打印一个一维数组,给定数组
int arr[] = {10, 20, 30, 40, 50};,用指针p从arr开始,逐个元素输出。 - 使用指针实现字符串反转:编写一个函数
reverse_string(char *str),该函数接收一个字符串指针,将字符串原地反转,在main函数中测试该函数。
- 指针与变量:定义两个整型变量
结构体与共用体
- 目的:
- 掌握结构体类型
struct的定义和使用。 - 学会定义结构体变量、结构体数组,并访问其成员。
- 理解结构体指针和结构体作为函数参数的用法。
- 了解共用体
union的基本概念和特点。
- 掌握结构体类型
- 学生信息管理:定义一个学生结构体
Student,包含学号(字符串)、姓名(字符串)、年龄(整型)、成绩(浮点型)。- 创建一个包含5个学生信息的结构体数组。
- 编写函数
input_students()用于输入学生信息。 - 编写函数
print_students()用于打印所有学生信息。 - 编写函数
find_student_by_id(),根据学号查找并打印某个学生的信息。
- 共用体示例:定义一个共用体
Data,可以存储一个字符、一个短整型或一个浮点数,编写程序,向共用体的不同成员赋值,并观察内存中数据的变化(可以使用%p打印地址,%x打印内存内容)。
- 学生信息管理:定义一个学生结构体
文件操作
- 目的:
- 掌握文件指针
FILE*的概念。 - 学会使用
fopen(),fclose()函数打开和关闭文件。 - 熟练掌握文本文件的读写函数:
fgetc(),fputc(),fgets(),fputs(),fscanf(),fprintf()。 - 了解二进制文件的读写。
- 掌握文件指针
- 文本文件读写:将实验七中的学生信息(至少3条)保存到一个名为
students.txt的文本文件中,然后编写程序,从该文件中读取学生信息并显示在屏幕上。 - 文件复制:编写一个程序,将一个文本文件(如
source.txt完整地复制到另一个文本文件(如dest.txt)中。 - 简单数据统计:创建一个文本文件
data.txt,里面有多行数字,每行一个,编写程序,读取该文件中的所有数字,计算它们的总和、平均值,并将结果写入到另一个文件result.txt中。
- 文本文件读写:将实验七中的学生信息(至少3条)保存到一个名为
第三部分:调试技巧与常见错误
调试技巧
- 阅读错误信息: 编译器给出的错误信息是宝贵的线索,仔细阅读并理解它。
- 使用断点: 在你认为可能出错的代码行左侧单击,设置一个断点,运行程序后,执行会在断点处暂停。
- 单步执行: 使用“逐语句”(Step Over) 或“逐过程”(Step Into) 按钮,一行一行地执行代码,观察程序流程是否符合预期。
- 监视变量: 在调试过程中,打开“监视”窗口,添加你关心的变量,实时查看它们的值是如何变化的。
- 打印调试: 在代码中插入
printf语句,输出关键变量的值或程序执行到的位置,这是一种简单但非常有效的调试方法。
常见错误
- 语法错误:
- 忘记分号:C语句末尾必须有分号。
- 括号不匹配: 和 、 和 必须成对出现。
- 拼写错误:变量名、函数名拼写错误(如
prinf写成了printf)。 - 未定义变量:使用了未经定义的变量。
- 逻辑错误:
- 循环条件错误:导致死循环或循环次数不对。
- 边界条件错误:如数组访问越界(
arr[10]而不是arr[9])。 - 运算符优先级错误:如
a + b * c和(a + b) * c的结果不同。 - 值传递与地址传递混淆:想在被调函数中修改主调函数的变量,却使用了值传递。
- 链接错误:
- 函数未定义:调用了函数,但没有实现它。
- 库文件未包含:使用了标准库函数,但忘记包含对应的头文件(如
#include <math.h>)。
第四部分:编程规范与建议
- 命名规范:
- 变量名、函数名要有意义,做到“见名知意”,如用
student_count而不是sc。 - 常量名建议全部大写,如
MAX_STUDENTS。 - 遵循统一的命名风格(如驼峰命名法
myVariable或下划线命名法my_variable)。
- 变量名、函数名要有意义,做到“见名知意”,如用
- 注释规范:
- 文件头部:包含程序名称、作者、日期、功能简介。
- 函数头部:说明函数功能、参数含义、返回值。
- 关键代码行:解释复杂的算法或逻辑。
- 代码格式:
- 使用缩进(通常用空格或Tab)表示代码块层次。
- 一行只写一条语句。
- 运算符两边、逗号后面建议加空格,提高可读性。
- 学习建议:
- 多看多模仿: 阅读优秀的开源代码,学习其风格和技巧。
- 勤于思考: 写代码前先想清楚,磨刀不误砍柴工。
- 不怕犯错: 错误是学习过程中最宝贵的财富,遇到Bug,不要气馁,享受解决问题的过程。
- 善用资源: 查阅教材、官方文档、技术论坛(如Stack Overflow)。
祝大家在C语言编程的学习道路上取得成功!
