简介:C#基础练习题压缩包面向希望以动手方式巩固核心语法的初学者与进阶学习者,覆盖数据类型、控制结构、方法与参数传递、数组与集合、类与对象、接口与抽象类、异常处理、枚举与委托、文件流、LINQ、异步编程和泛型等主题,可用于课堂配套训练、自学查漏或面试前基础复盘。包内共1670个文件,以224个cs源码、164个exe程序、94个csproj项目文件及82个sln解决方案为主,并含jpg截图、resx、dll、aspx等配套内容,解压后约17.87MB,项目结构便于按知识点定位示例与对照运行结果。已有731人学习,适合通过阅读源码、修改练习、运行项目和复盘报错来理解语法细节与面向对象设计,逐步积累可复用的调试方法和实现思路。对于需要从零散语法点过渡到完整小项目练习的读者,可作为阶段性的训练素材。
1. 从“打印九九乘法表”说起:C#基础练习题到底在练什么
很多人第一次翻开 C# 教程,语法都能看懂,一关掉教程就写不出半行。问题不在天赋,在于缺一个“把知识用一次”的动作。C#基础练习题就是这一摞动作清单:变量、判断、循环、数组、字符串、方法,每个知识点配几道小题,题目短,答案能立刻在控制台里跑出结果。它不负责教你造轮子,只负责把你从“眼熟”推到“手熟”。适合刚学完一门语言语法、还没独立写过完整小程序的人,也适合丢下书本很久想重新拾起来的人,以及想练手但不知道该写点什么的学生。接下来的内容按“为什么练、怎么装环境、第一道题怎么下手、卡住了怎么排查”一路走,你跟着做就行。
2. 为什么零基础要刷题:把语法从“看过”变成“写得出”
2.1 看懂和写出来之间,隔着很多次小的卡壳
看教程像看别人游泳,动作分解得再清楚,下水还是会呛。编程也一样:if是什么意思你能背出来,但让你判断一个年份是不是闰年,手就会停在键盘上。这种“知识幻觉”在编程里特别常见,因为语法是陈述性知识,写代码是程序性知识,两者靠的记忆系统不一样,前者靠读,后者只能靠一遍遍写。
拿循环举例。下面这段代码打印 1 到 5:
// 打印 1 到 5,每行一个数字 for (int i = 1; i <= 5; i++) { Console.WriteLine(i); }int i = 1是起点,i <= 5是继续的条件,i++是每轮结束后的变化。三个地方改任何一处,结果都会变:把i改成 0 就从 0 开始,把i <= 5改成i < 5就只到 4。你现在可以立刻把i++换成i += 2试一次,看输出变成 1、3、5。新手最缺的其实就是这种“我改一个地方,看结果怎么变”的手感,而练习题提供的正是这种实验场。
所以别把刷基础题理解成应试。它是把抽象语法翻译成肌肉记忆的最短路径,一道题卡十分钟,比看十页讲解记得都牢。
2.2 一份基础练习题通常覆盖哪几块
题目看起来五花八门,摊开看其实就那么几类,每类对应一个必须掌握的能力。下面这张表可以当成检查清单,你练的时候对着看,哪一栏空着就补哪一栏。
| 知识块 | 典型题目 | 练完能干什么 |
|---|---|---|
| 变量与类型 | 温度换算、求平均分 | 知道 int、double、string 什么时候用谁 |
| 输入输出 | 猜数字、菜单选择 | 能读用户输入并做校验 |
| 条件判断 | 闰年判断、成绩等级 | 把业务规则翻译成 if |
| 循环 | 九九乘法表、素数判断、累加求和 | 会处理重复劳动 |
| 数组与集合 | 成绩统计、去重、排序 | 会存一批数据再统一处理 |
| 字符串 | 回文判断、字符统计 | 会做文本层面的处理 |
| 方法 | 把上面这些拆成函数 | 代码开始能复用,不再越写越乱 |
前四块是骨架,后三块是让代码不那么难看的肌肉。零基础容易犯的错是只挑简单的做,比如只刷循环里的累加求和,一到数组和字符串就绕开。结果就是能写二十行的小脚本,写不了五十行的完整程序。
真实情况是:数组和字符串恰恰是绝大多数小工具的核心,统计一份成绩单、校验一段输入、把一列数据排序,都得用上。入门的门槛就在这三块,早点啃下来,后面学面向对象会顺很多。
2.3 抄答案不丢人,但抄完要做三件事
零基础阶段卡题超过二十分钟,效率就开始下降了,这时候看答案是合理选择,不丢人。真正的差别在抄完之后做不做什么。第一件事,把答案盖住,从空白文件重新写一遍,写不出来的地方说明你只是“读懂了”而不是“会写”。第二件事,改一个条件,比如把求 1 到 100 的偶数和改成奇数和,看你能不能在三十秒内改对,这一步检验的是理解而不是记忆。第三件事,故意写错一次,把分号删掉、把i < n写成i <= n,看编译器报什么错、看程序在哪儿崩,报错信息看得多了,排查速度才会真的上来。
这三件事花不了几分钟,但它决定了你是“刷了五十道题”还是“会写五十种逻辑”。
3. 十分钟把环境跑起来:从装 SDK 到第一行输出
3.1 只需要三样东西:SDK、编辑器、一个空文件夹
先把必要的工具准备齐。你需要的第一样是 .NET SDK,它把编译器、运行时和命令行工具打成一个包,装完之后你的电脑就有能力编译和运行 C# 代码了。到官方站点下载 LTS(长期支持)版本即可,安装时一路下一步,装完打开一个新的终端窗口,敲下面两行验证:
# 查看当前默认使用的 SDK 版本 dotnet --version # 列出电脑上装过的所有 SDK dotnet --list-sdks第一行能打印出一个版本号,第二行能列出至少一条记录,就说明装好了。如果提示“不是内部或外部命令”,八成是装完之后没重开终端,关掉窗口重新打开再试一次。
第二样是一个能编辑代码的工具。轻量的编辑器装个 C# 扩展就够用,集成度更高的开发环境开箱即用,两者选一个,别在这个环节纠结太久,写到三百行代码之前你感受不到差别。第三样是一个专门放练习代码的空文件夹,别把题摊在桌面上,这一点在 3.3 会展开。
提示:安装过程中如果杀毒软件弹窗拦截,先允许一次再继续,装完可以恢复原设置。
3.2 第一个能跑的例子:读两个数、相加、打印
打开终端,进到你准备好的练习文件夹,执行:
# 在当前目录下创建一个名为 HelloAdd 的控制台项目 dotnet new console -o HelloAdd # 进入项目目录 cd HelloAdd # 编译并运行 dotnet run第三条命令执行完,屏幕上会打印一句Hello, World!。这就是你的第一个 C# 程序,说明整条工具链是通的。接着用编辑器打开项目里的Program.cs,把内容整体替换成下面这段:
using System; class Program { static void Main() { // 读取第一个整数 Console.Write("请输入第一个整数:"); string? first = Console.ReadLine(); // 读取第二个整数 Console.Write("请输入第二个整数:"); string? second = Console.ReadLine(); // TryParse 转换失败时返回 false,不会让程序崩掉 if (int.TryParse(first, out int a) && int.TryParse(second, out int b)) { Console.WriteLine($"{a} + {b} = {a + b}"); } else { Console.WriteLine("输入的不是整数,请重新运行再试。"); } } }保存后回到终端再执行一次dotnet run,输入两个数字试试。这段代码里有三个新手必须马上认熟的东西:Console.ReadLine()负责从键盘读一行,读回来的东西是字符串不是数字;int.TryParse负责把字符串转成整数,转换失败只是返回false,程序不会崩;$"{a} + {b} = {a + b}"是字符串插值,大括号里的表达式会先算出来再拼进句子。
为什么不用int.Parse?因为它遇到字母或者空行会直接抛异常,把整个程序打断。入门阶段先用TryParse,养成“外部输入都不可信”的习惯,这个习惯以后能救你很多次。
注意:如果你的模板生成的
Program.cs是一行Console.WriteLine("Hello, World!");这种没有class和Main的写法,说明用的是新版模板的顶级语句。直接把整份文件内容替换成上面的代码即可,两种写法都能跑。
3.3 给练习题建一个自己的目录:一题一文件
刷到第十道题的时候,如果你还在一个Program.cs里反复覆盖旧代码,很快就会乱。推荐的做法是:一个项目,一道题一个文件,另加一个入口文件负责分派。结构大概是这样:
CSharpPractice/ ├── CSharpPractice.csproj ├── Program.cs └── Exercises/ ├── Ex001_Sum.cs └── Ex002_LeapYear.cs入口文件长这样:
using System; class Program { static void Main() { while (true) { Console.WriteLine("输入题号运行对应练习(0 退出):"); string? key = Console.ReadLine(); switch (key) { case "1": Ex001_Sum.Run(); break; // 两数相加 case "2": Ex002_LeapYear.Run(); break; // 闰年判断 case "0": return; // 退出程序 default: Console.WriteLine("没有这道题。"); break; } } } }单道题的文件写成静态类,暴露一个Run方法:
using System; public static class Ex001_Sum { public static void Run() { Console.Write("第一个数:"); int a = int.Parse(Console.ReadLine() ?? "0"); // 读到 null 时给个兜底值 Console.Write("第二个数:"); int b = int.Parse(Console.ReadLine() ?? "0"); Console.WriteLine($"结果:{a + b}"); } }这样每道题都是独立的,改坏了只影响那一题,回头复习也能直接翻到原题重跑。public static是为了让入口文件能直接调用,不用创建对象,入门阶段先这么写,等学到类和对象再回头看这行会更有感觉。
4. 四类基础题的通用拆法:变量、判断、循环、集合怎么下手
4.1 变量与输入输出类:先想清楚“进来什么、出去什么”
这类题最好上手,也最容易写错,错的地方往往不在语法,在于没想清楚数据类型。拿“输入摄氏温度,输出华氏温度”来说,公式是华氏度 = 摄氏度 × 9 ÷ 5 + 32。新手常写成这样:
// 错误示范:9 / 5 两边都是整数,结果是 1 而不是 1.8 double f = c * 9 / 5 + 32;c是double的时候结果其实是对的,因为运算从左往右,c * 9先变成小数。但如果c是int,9 / 5就会先算成整数 1,结果整整差了一截。稳妥写法是把常量写清楚:
using System; Console.Write("请输入摄氏温度:"); if (double.TryParse(Console.ReadLine(), out double c)) { double f = c * 9.0 / 5.0 + 32; // 用 9.0 保证是小数除法 Console.WriteLine($"{c:F1} 摄氏度 = {f:F1} 华氏度"); } else { Console.WriteLine("请输入一个数字,比如 26.5"); }{f:F1}里的F1表示保留一位小数,不带它会打印出一长串小数点。拆这类题的固定顺序是:先定输入是什么类型,再定输出是什么类型,最后写中间的换算公式,三步行完再动手,返工率会低很多。
4.2 条件判断类:把规则一条条翻译成布尔表达式
闰年判断是条件题里的经典,规则有三条:能被 4 整除、但不能被 100 整除;或者能被 400 整除。听着绕,翻译成代码其实只有一行:
using System; Console.Write("请输入年份:"); if (int.TryParse(Console.ReadLine(), out int year)) { // 注意括号:或的左边单独成立,右边必须同时满足两个条件 bool isLeap = (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0); Console.WriteLine(isLeap ? $"{year} 年是闰年" : $"{year} 年不是闰年"); }%是取余数,year % 4 == 0就是“能被 4 整除”。这里最容易翻车的是括号:&&的优先级高于||,如果不加括号,语义会跑偏。写完拿三个值验一验:2000 年应该是闰年,1900 年应该不是,2024 年应该是。三个都对,这条规则才算真的写对了。
条件题的通用拆法是:先把题目里的“如果……就……否则……”用中文写出来,再一句句替换成if、else if、else,最后补充边界值测试。成绩等级题、票价分档题、三角形判定题,都是这个套路。
4.3 循环类:先找重复的那件事,再定三个要素
九九乘法表是练嵌套循环的好题,因为它的重复结构一眼能看出来:一共九行,第几行就打印几列。
for (int i = 1; i <= 9; i++) { for (int j = 1; j <= i; j++) // 内层只到 i,保证不重复打印 { Console.Write($"{j}x{i}={i * j}\t"); // \t 是制表符,用来对齐 } Console.WriteLine(); // 每一行结束换行 }外层控制行,内层控制列,内层的上限跟着外层走,这是嵌套循环里最常见的形态。如果写成j <= 9,你会得到一张完整的 81 项表格,虽然也对,但不是题目要的三角形。
再看素数判断,它练的是“循环里可以提前结束”:
bool isPrime = n >= 2; // 小于 2 的数一律不是素数 for (int d = 2; d * d <= n; d++) // 只试到平方根,效率高很多 { if (n % d == 0) { isPrime = false; break; // 找到一个因子就够了,不用继续 } }d * d <= n等价于d <= 根号n,因为如果一个数有大于平方根的因子,那它必然还有一个小于平方根的搭档,前面早就该发现了。这种“试到平方根就够”的优化,比死记语法有用得多。
循环题下手的顺序是:先写出重复体做什么,再定起点、终点、步长三要素,最后检查有没有可能死循环。死循环在 5.2 会专门讲。
4.4 数组与集合类:先想“数量定不定”,再选容器
数量固定的用数组,数量不定、需要边读边存的用List<int>。成绩统计这类题,用户输入几个成绩事先不知道,所以用集合更合适:
using System; using System.Collections.Generic; using System.Linq; var scores = new List<int>(); while (true) { Console.Write("输入成绩(0~100,直接回车结束):"); string? line = Console.ReadLine(); if (string.IsNullOrWhiteSpace(line)) break; // 空行就结束录入 if (int.TryParse(line, out int s) && s >= 0 && s <= 100) scores.Add(s); // 校验通过才加入 else Console.WriteLine("成绩必须是 0 到 100 的整数。"); } if (scores.Count == 0) { Console.WriteLine("没有录入任何成绩。"); return; } Console.WriteLine($"人数:{scores.Count}"); Console.WriteLine($"平均分:{scores.Average():F2}"); Console.WriteLine($"最高分:{scores.Max()}"); Console.WriteLine($"从低到高:{string.Join(", ", scores.OrderBy(x => x))}");Average()、Max()、OrderBy()来自System.Linq,加上那一行using才能用。新手容易忘掉这个引用,然后对着“找不到方法”的报错发呆。集合题的核心动作是三步:建容器、循环往里塞、循环完之后统一算。把这三步写在纸上,代码几乎是照着抄下来的。
4.5 抽方法:把一段能跑的代码变成能复用的代码
写到第四、第五题的时候你会发现,输入校验、求平均、判断素数这些逻辑开始重复出现。这时候就该学着抽方法了。以素数为例:
// 输入一个整数,返回它是不是素数 static bool IsPrime(int n) { if (n < 2) return false; // 小于 2 直接排除 for (int d = 2; d * d <= n; d++) if (n % d == 0) return false; // 找到因子立刻返回 false return true; // 全试完都没找到,才是素数 }抽方法看三件事:要传进去什么(参数int n)、要吐出来什么(返回值bool)、方法名能不能一眼看懂(IsPrime比Check强得多)。抽完之后主程序只剩一行Console.WriteLine(IsPrime(97));,读起来清爽,改起来也只改一处。
5. 新手常见问题排查:五个最容易翻车的现场
5.1 输入数字却提示“格式不正确”,或者程序直接崩了
现象:运行后输入 12,控制台抛出一段红字,说输入字符串的格式不正确。 原因:Console.ReadLine()返回的永远是字符串,int.Parse碰到空行、空格、字母都会抛异常,用户手一抖敲个回车就会触发。 解决:一律换成int.TryParse或double.TryParse,用if接住false的分支给出友好提示。也可以用Console.ReadLine() ?? "0"兜个底。养成“凡是从键盘读进来的东西都当不可信”的习惯,这个坑以后能少踩一大半。
5.2 程序卡住不动,只能强行关窗口
现象:点了运行,光标一直在闪,什么都没输出,也停不下来。 原因:循环条件永远成立,或者循环变量压根没更新。常见写法是while (i < 10)里忘了写i++,还有把i--写成i++导致方向反了。 解决:在循环体第一行临时打印一下循环变量的值,看它是没变还是越跑越远。养成写循环时先检查三要素的习惯:起点、终点、步长。复杂一点的条件,先用注释把“什么时候该退出”用中文写清楚再翻译成代码。
5.3 程序一闪就退,或者中文显示成乱码
现象:双击运行 exe,黑窗口闪一下就没;或者输出里的中文变成一堆问号。 原因:程序跑完Main就自然结束了,没有停下来的理由;中文乱码则是控制台编码和源文件编码不一致。 解决:调试阶段在Main末尾加一句Console.ReadLine();让程序等你按键。中文问题在文件开头加Console.OutputEncoding = System.Text.Encoding.UTF8;,并确认源文件本身保存为 UTF-8。这两条都是调试期的小补丁,正式程序里不需要。
5.4 数组明明有五个元素,访问第五个就报越界
现象:抛IndexOutOfRangeException,说索引超出了数组界限。 原因:C# 数组下标从 0 开始,长度是 5 的数组,合法下标是 0 到 4。写arr[5]或者循环条件写成i <= arr.Length都会越界。 解决:循环条件一律用i < arr.Length,别用<=。需要访问“最后一个元素”时写arr[arr.Length - 1]。List同理,Count是元素个数不是最大下标。这个错新手一周能犯五次,看到报错先看下标。
5.5 两个整数相除,结果总是 0 或者少一截
现象:算平均分sum / count,明明总分 350、人数 4,输出却是 87 而不是 87.5。 原因:int除以int执行的是整除,小数部分直接被丢掉,不会四舍五入。 解决:参与运算的两个数里至少有一个是浮点类型,写成(double)sum / count或者sum / 4.0。求百分比、求平均分、做汇率换算,只要涉及除法,先在心里问一句“这里会不会被截断”。
6. 练完这一轮往哪走:三条进阶路线和检验标准
基础题刷到你能不看答案写出“成绩统计”“素数筛选”“简易菜单”这三样,就可以往下走了。别急着跳去学框架,下面三个阶段按顺序过一遍,每个阶段都有能自己验证的标准。
| 阶段 | 练什么 | 什么算过关 |
|---|---|---|
| 一、方法与类 | 把之前写过的题拆成方法,再封装成一两个类 | 同一个逻辑不用复制粘贴第二次 |
| 二、集合与异常 | 用字典统计词频、用 try-catch 接住文件读不到的情况 | 程序出错时给出人话提示而不是崩掉 |
| 三、小项目 | 控制台记账、通讯录、学生成绩管理任选其一 | 数据能存到文件里,下次打开还在 |
三个阶段之外,还有一件容易被忽略的事:学会读报错。C# 的编译器其实相当啰嗦,报错信息里通常带着文件名、行号和一句人话。刚开始看到一屏红字会慌,试着只读第一条,把行号对应到代码上,多数时候改一处后面全消失。这个能力比多背十个语法点值钱。
再说一个我自己的教训。刚学的时候我特别喜欢攒题,一个下午刷十几道,每题都是跑通就关掉,觉得进度飞快。两周后回头想改一道之前做过的题,打开文件发现完全看不懂自己写的什么,变量叫a、b、temp,没有一行注释,连当时想干什么都记不起来。那次之后我给自己定了个规矩:每道题写完之后,强制在文件顶部用两句话写清楚“输入是什么、输出是什么”,变量名不许用单字母。看起来只是多了三十秒,但半个月后回看,这一行注释就是后悔药。希望帮到你。
本文还有配套的精品资源,点击获取