VB编程题精析:从语法肌肉记忆到算法思维训练
2026/9/19 15:56:23 网站建设 项目流程

简介:本资源是一份面向VB初学者与高校编程课程学习者的经典题库及详解PDF,聚焦基础语法巩固与算法思维训练。涵盖素数判断、字符串反转、闰年判定、数组操作、矩阵处理、排序算法、杨辉三角等33道典型编程题,每题均配标准VB代码答案与关键逻辑说明,覆盖循环控制、条件分支、函数过程调用、二维数组遍历、字符编码转换等核心知识点。资源为单文件PDF格式,共1个文件,大小1.3MB,内容精炼、排版清晰,便于离线查阅与代码复现。已有218人下载学习,适合作为课后练习、期末复习、上机考试备考及自学自测的实用参考资料,帮助读者系统掌握VB编程基本功与常见问题解决路径。

1. 这不是过时的练习册,而是 VB 语法肌肉记忆的锻造锤

很多人看到“VB 编程题及答案.pdf”第一反应是:VB 过时了为什么还要学?但真实情况恰恰相反——这份 2020 年底修订的题集,覆盖了从基础控制流到二维数组索引、从字符串切片到内存级数组重定义的完整能力图谱。它不教你如何搭 Web 框架,而是逼你在Dim a%(3, 3)ReDim Preserve a(j)之间建立条件反射;它不谈云原生,却用第 14 题“删除数组第 5 个元素”让你亲手操作内存偏移与边界收缩;它甚至在第 26 题“求两条对角线之和”里,把a(i, i)a(i, 3 - i)的下标映射关系刻进你的直觉。这不是怀旧,是训练一种底层编程通感:当你在 Python 里写arr.pop(4)或在 Java 里调用ArrayList.remove(4)时,背后那个被隐去的“元素搬移+长度重置”过程,正是 VB 这些题强制你显式写出的逻辑。适合三类人:高校《程序设计基础》课程助教(可直接拆解为课堂 demo)、转岗测试/运维需快速掌握脚本逻辑的工程师(VB 的InputBox/MsgBox/Text1 = ...是最贴近业务场景的 GUI 脚本原型),以及准备算法导论期末或 CSP-J 初赛的学生(第 9 题“被 3/5/7 除余 1 的最小 5 个数”本质是同余方程组暴力枚举,第 30 题杨辉三角是二维 DP 入门)。它不提供现代工程范式,但把“循环怎么设初值、边界怎么取、嵌套怎么缩进、变量作用域在哪失效”这些易被高级语言掩盖的细节,全摊开在For i = 0 To 3的每一行里。

2. 素数判断与闰年逻辑:从试除法到布尔代数的硬编码落地

VB 的Mod运算符和短路And/Or是这类判断题的基石。但真正区分新手与熟手的,是参数化封装意识和边界处理精度。以第 1 题“求 100 以内素数”原始代码为例,其内层循环For a = 2 To Sqr(i)存在两个关键隐患:Sqr(i)返回Double类型,而For循环变量a是整型,VB 会隐式截断导致a实际只遍历到Int(Sqr(i)),当i=100Sqr(100)=10.0截断无损,但i=97Sqr(97)≈9.848截断为 9,漏检a=10的可能性——而 97 是素数,此漏洞不影响结果,却暴露了对浮点转整型风险的忽视。更致命的是第 4 题闰年判断中If n Mod 4 = 0 And n Mod 100 <> 0 Or n Mod 400 = 0这一表达式,因 VB 中And优先级高于Or,实际等价于((n Mod 4 = 0) And (n Mod 100 <> 0)) Or (n Mod 400 = 0),逻辑正确,但若开发者误以为Or优先级更高,就会写出错误分支。这正是必须显式加括号的铁律。

2.1 封装为可复用函数:避免重复造轮子

将素数判断抽离为独立函数,不仅提升代码复用性,更强制你思考接口契约。以下为健壮版实现:

' 判断 n 是否为素数,返回 True/False Public Function IsPrime(n As Long) As Boolean If n < 2 Then IsPrime = False Exit Function End If If n = 2 Then IsPrime = True Exit Function End If If n Mod 2 = 0 Then IsPrime = False Exit Function End If ' 只需检查到 Int(Sqr(n)) + 1,防止 Sqr 浮点误差 Dim limit As Long limit = CLng(Int(Sqr(n))) + 1 Dim i As Long For i = 3 To limit Step 2 If n Mod i = 0 Then IsPrime = False Exit Function End If Next i IsPrime = True End Function

注意CLng(Int(Sqr(n))) + 1是关键防护。Int()向负无穷取整,Sqr()永远非负,Int()在此处安全,但+1确保上界不因浮点舍入而遗漏。Step 2跳过所有偶数,效率翻倍。n As Long支持更大范围输入,避免Integer溢出。

2.2 闰年判断的布尔代数重构

原始代码用标志位i = 1表示闰年,这是典型的过程式思维。现代写法应直接返回布尔值,并用括号明确逻辑分组:

' 判断 year 是否为闰年,返回 True/False Public Function IsLeapYear(year As Integer) As Boolean IsLeapYear = (year Mod 4 = 0 And year Mod 100 <> 0) Or (year Mod 400 = 0) End Function

提示:VB 支持将布尔表达式直接赋值给函数名,无需If...Then...Elseyear Mod 100 <> 0中的<>是 VB 唯一的不等于运算符,不可写作!=。此函数可直接用于第 33、39 题的区间素数求和中,例如For i = 1000 To 1100: If IsPrime(i) And IsLeapYear(i) Then sum = sum + i,组合逻辑清晰。

2.3 综合应用:第 33 题区间素数求和的完整流程

题目要求“编写一个过程计算并输出区间[100,1000]内所有素数的和”,且强调“判断素数使用过程来实现”。这意味着主逻辑与判断逻辑必须分离:

Private Sub Command1_Click() Dim sum As Long sum = 0 Dim i As Long For i = 100 To 1000 If IsPrime(i) Then sum = sum + i End If Next i MsgBox "100-1000 内素数之和为:" & sum End Sub

逻辑说明sum初始化为0(而非1)是累加器基本规范;For循环变量i声明为Long防止Integer在大区间溢出;IsPrime(i)调用已封装函数,主流程专注聚合逻辑。若需调试,可在If内添加Debug.Print i查看具体素数。

3. 字符串反转与数组操作:从内存拷贝到动态重定义的底层实践

VB 的字符串操作看似简单,实则暗藏内存管理玄机。第 2 题“字符串倒置”原始代码用Mid()函数直接修改字符串内容,这本质上是就地(in-place)内存覆盖,比新建字符串更省内存。而第 14 题“删除数组第 5 个元素”则涉及ReDim Preserve的核心机制:它会创建新数组、复制旧数据、释放旧内存,是 VB 中少数显式暴露内存重分配的操作。这两类题共同构成对“数据结构动态性”的双重训练。

3.1 字符串反转的三种实现与性能对比

原始代码用双指针交换Mid(),但存在i / 2的浮点除法隐患(i为奇数时i/2非整数,VB 自动取整)。更安全写法是For a = 1 To i \ 2\为整除运算符):

Private Sub Command1_Click() Dim n As String, i As Long, a As Long, b As String n = InputBox("输入字符") i = Len(n) ' 使用整除 \ 避免浮点误差 For a = 1 To i \ 2 b = Mid(n, a, 1) Mid(n, a, 1) = Mid(n, i + 1 - a, 1) Mid(n, i + 1 - a, 1) = b Next a Print n End Sub

参数说明Mid(n, a, 1)a是起始位置(从 1 开始),1是提取长度;i + 1 - a是对称位置,当a=1时对应末尾ia=2时对应i-1,以此类推。i \ 2确保循环次数为整数,如i=7时循环 3 次(位置 1↔7, 2↔6, 3↔5),中间字符4自然不动。

替代方案:构建新字符串(更直观,内存开销略高)
Private Sub Command1_Click() Dim n As String, reversed As String, i As Long n = InputBox("输入字符") reversed = "" For i = Len(n) To 1 Step -1 reversed = reversed & Mid(n, i, 1) Next i Print reversed End Sub

对比说明&连接符每次都会创建新字符串对象,时间复杂度 O(n²),而Mid()就地修改为 O(n)。对于长字符串(如 >10KB),前者可能触发频繁 GC,后者更优。但后者要求字符串可变,后者更符合函数式编程习惯。

3.2 数组删除:ReDim Preserve的精确边界控制

第 14 题数组a() = {12,6,4,89,75,63,100,20,31}删除第 5 个元素(即索引 4,值为 75),原始代码For i = 5 To j: a(i - 1) = a(i)存在严重越界风险:j = UBound(a)初始为 8,循环i=5 To 8a(i-1)=a(i)a(4)覆盖为a(5)=63a(5)覆盖为a(6)=100a(6)覆盖为a(7)=20a(7)覆盖为a(8)=31,最后j=j-1为 7,ReDim Preserve a(j)将数组截断为 8 个元素(索引 0-7),原a(8)被丢弃。但若未执行ReDima(7)仍保留旧值,逻辑错误。健壮写法必须严格配对:

Private Sub Command1_Click() Dim a As Variant a = Array(12, 6, 4, 89, 75, 63, 100, 20, 31) Dim j As Long, i As Long j = UBound(a) ' 初始上界 8 ' 打印原数组 Debug.Print "原数组: "; For i = 0 To j: Debug.Print a(i); " "; : Next i: Debug.Print ' 删除索引为 4 的元素(第5个) For i = 4 To j - 1 a(i) = a(i + 1) Next i ' 关键:重定义数组,长度减1 ReDim Preserve a(j - 1) ' 打印新数组 Debug.Print "删除后: "; For i = 0 To j - 1: Debug.Print a(i); " "; : Next i: Debug.Print End Sub

参数说明ReDim Preserve a(j - 1)j-1是新上界,因删除一个元素,长度从j+1变为j,上界即为j-1For i = 4 To j - 1确保移动a(4)a(j-1),覆盖原a(4)a(j-1),原a(j)被丢弃。Preserve保留原数据,无此关键字则数组清空。

3.3 二维数组的上/下三角输出:索引模式的数学建模

第 15 题“以上三角形式输出”和第 28 题“以下三角形式输出”本质是矩阵索引的几何约束。上三角要求j >= i(列号 ≥ 行号),下三角要求j <= i(列号 ≤ 行号)。原始代码用Tab(j * 5)控制缩进,但更通用做法是计算空格数:

' 上三角输出(4x4 数组) Private Sub UpperTriangleOutput() Dim a(3, 3) As Integer, i As Long, j As Long ' 初始化数组(示例) For i = 0 To 3 For j = 0 To 3 a(i, j) = Int(Rnd * 11 + 10) ' [10,20] Next j Next i ' 输出上三角 For i = 0 To 3 ' 每行前导空格:i 个制表符或空格 Debug.Print Space(i * 4); ' 用空格替代 Tab,更可控 For j = i To 3 Debug.Print Format(a(i, j), "00"); " "; Next j Debug.Print Next i End Sub

逻辑说明Space(i * 4)生成i*4个空格,使第i行(0-indexed)首元素左移i倍宽度,形成阶梯效果;For j = i To 3保证只输出j>=i的元素。下三角只需将内层循环改为For j = 0 To i,并移除Space()即可。

4. 矩阵处理与评分计算:从双重循环到极值追踪的工程化思维

VB 的二维数组操作是算法能力的试金石。第 16 题“输出每行最大值及下标”和第 29 题“评委打分去最高最低求平均”表面是简单循环,实则考验你对状态变量、边界初始化、多目标追踪的掌控力。原始代码常犯的错误包括:imax未初始化导致随机值参与比较、For循环范围错误、ReDim后未更新UBound。这些坑在真实项目中会导致静默错误。

4.1 矩阵行极值追踪:避免未初始化陷阱

第 16 题原始代码imax = 0后直接进入For j = 0 To 3,但若该行所有元素均小于a(i, 0)imax将保持0,输出错误下标。正确做法是将imax初始化为当前行首列索引,并用a(i, imax)作为初始比较基准:

Private Sub RowMaxWithIndex() Dim a(3, 3) As Integer, i As Long, j As Long, imax As Long, maxVal As Integer ' 初始化数组(示例) For i = 0 To 3 For j = 0 To 3 a(i, j) = Int(Rnd * 31 + 20) ' [20,50] Next j Next i ' 输出矩阵 Debug.Print "矩阵 A:" For i = 0 To 3 For j = 0 To 3 Debug.Print Format(a(i, j), "00"); " "; Next j Debug.Print Next i ' 每行找最大值及下标 Debug.Print "每行最大值及下标:" For i = 0 To 3 ' 初始化:假设第0列最大 imax = 0 maxVal = a(i, 0) ' 从第1列开始比较 For j = 1 To 3 If a(i, j) > maxVal Then maxVal = a(i, j) imax = j End If Next j Debug.Print "第" & (i + 1) & "行: 最大值=" & maxVal & ", 下标=(" & i & "," & imax & ")" Next i End Sub

参数说明imax = 0maxVal = a(i, 0)是成对初始化,确保比较有基准;内层For j = 1 To 3避免与自身比较;Format(a(i,j), "00")保证两位数对齐,便于阅读。此模式可直接复用于第 17、27 题的全局极值查找,只需将外层循环扩展为For i = 0 To 3: For j = 0 To 3

4.2 评委评分的鲁棒实现:排序与遍历的权衡

第 10 题和第 29 题都要求“去掉一个最高分和一个最低分后求平均”。原始代码用冒泡排序两次(先升序排找最小,再降序排找最大),效率低且易错。更优解是单次遍历追踪极值:

Private Sub JudgeScoreRobust() ' 第29题数据:a = {98,97,95,91,90,99,93,94,93,96} Dim scores(9) As Integer scores(0) = 98: scores(1) = 97: scores(2) = 95: scores(3) = 91 scores(4) = 90: scores(5) = 99: scores(6) = 93: scores(7) = 94 scores(8) = 93: scores(9) = 96 Dim minVal As Integer, maxVal As Integer, sum As Long, i As Long ' 初始化为第一个元素 minVal = scores(0) maxVal = scores(0) sum = scores(0) ' 单次遍历,同时找极值并累加 For i = 1 To 9 If scores(i) < minVal Then minVal = scores(i) If scores(i) > maxVal Then maxVal = scores(i) sum = sum + scores(i) Next i ' 减去一个最高分和一个最低分 sum = sum - minVal - maxVal ' 剩余8个分数求平均 Dim average As Double average = sum / 8 Debug.Print "原始分数: "; For i = 0 To 9: Debug.Print scores(i); " "; : Next i: Debug.Print Debug.Print "最高分:" & maxVal & ", 最低分:" & minVal Debug.Print "去掉后平均分:" & Format(average, "0.00") End Sub

逻辑说明minValmaxVal初始为scores(0)sum初始也为scores(0),然后从i=1开始遍历,避免重复计算。sum = sum - minVal - maxVal直接减去极值,无需排序。若存在多个相同极值(如两个 99 分),此方法只减去一个,符合题目“去掉一个最高分和一个最低分”的要求。时间复杂度 O(n),空间 O(1)。

4.3 矩阵对角线求和:主副对角线的坐标映射

第 26 题“求两条对角线上元素之和”原始代码sum = sum + a(i, i) + a(i, 3 - i)对 4x4 矩阵正确,但未考虑奇偶阶矩阵中心元素重复计算问题。对于 n x n 矩阵,主对角线为a(i,i),副对角线为a(i, n-1-i),当 n 为奇数时,中心元素a((n-1)/2, (n-1)/2)同时属于两条对角线,会被加两次。因此需根据矩阵阶数调整:

Private Sub DiagonalSum() Dim a(3, 3) As Integer, i As Long, j As Long, sum As Long, n As Long n = 4 ' 4x4 矩阵 ' 初始化 For i = 0 To n - 1 For j = 0 To n - 1 a(i, j) = Int(Rnd * 31 + 20) ' [20,50] Next j Next i sum = 0 ' 主对角线 a(i,i) For i = 0 To n - 1 sum = sum + a(i, i) Next i ' 副对角线 a(i, n-1-i) For i = 0 To n - 1 sum = sum + a(i, n - 1 - i) Next i ' 若 n 为奇数,中心元素被加了两次,减去一次 If n Mod 2 = 1 Then Dim center As Long center = (n - 1) \ 2 sum = sum - a(center, center) End If Debug.Print "对角线元素之和: " & sum End Sub

参数说明n = 4为矩阵阶数;n Mod 2 = 1判断奇偶;(n-1)\2计算中心索引(整除)。此代码可无缝适配任意 n x n 矩阵,只需修改n值。原始代码省略了奇偶判断,因其固定为 4x4,但工程化思维要求代码具备泛化能力。

5. 杨辉三角与字符串排序:从递推关系到稳定排序的算法内功

第 30 题“输出 n 行杨辉三角”和第 20 题“字符串按递减次序排列”是算法思维的分水岭。前者考察你能否将数学递推式C(n,k) = C(n-1,k-1) + C(n-1,k)转化为二维数组的填充逻辑;后者则检验你对排序稳定性、比较函数、以及 VB 字符串比较规则(ASCII 序)的理解。原始代码用冒泡排序,但未处理字符串长度相同时的字典序,也未考虑空字符串等边界。

5.1 杨辉三角的动态规划实现:二维数组的逐层填充

杨辉三角第i行(0-indexed)有i+1个元素,每个元素triangle(i,j) = triangle(i-1,j-1) + triangle(i-1,j),边界triangle(i,0) = triangle(i,i) = 1。关键在于数组声明和填充顺序:

Private Sub PascalTriangle(n As Long) ' 声明 n 行的三角形,第 i 行有 i+1 列 Dim triangle() As Long ReDim triangle(n - 1, n - 1) ' 最大行需要 n 列,但只用前 i+1 列 ' 填充 Dim i As Long, j As Long For i = 0 To n - 1 ' 每行首尾为 1 triangle(i, 0) = 1 triangle(i, i) = 1 ' 中间元素:上一行相邻两数之和 For j = 1 To i - 1 triangle(i, j) = triangle(i - 1, j - 1) + triangle(i - 1, j) Next j Next i ' 输出(居中对齐) Debug.Print "杨辉三角 " & n & " 行:" For i = 0 To n - 1 ' 左侧空格:(n-i-1)*2 个空格 Debug.Print Space((n - i - 1) * 2); For j = 0 To i Debug.Print Format(triangle(i, j), "00"); " "; Next j Debug.Print Next i End Sub

逻辑说明ReDim triangle(n-1, n-1)声明足够大的二维数组;外层For i逐行填充;内层For j = 1 To i-1填充中间元素,j-1j确保不越界;Space((n-i-1)*2)实现居中,使第i行比第i+1行少 2 个空格。调用PascalTriangle 5即可输出 5 行标准杨辉三角。

5.2 字符串递减排序:冒泡排序的稳定实现与优化

第 20 题原始代码If a(j) < a(j + 1) Then t = a(j): a(j) = a(j+1): a(j+1) = t是标准冒泡,但未处理a(j)a(j+1)为空字符串的情况(VB 中空字符串""在比较时小于任何非空字符串)。更健壮版本应加入空值检查,并利用 VB 内置StrComp函数进行大小写敏感比较:

Private Sub StringSortDescending() Dim n As Long, i As Long, j As Long, t As String n = 5 ' 输入字符串个数 Dim a() As String ReDim a(1 To n) ' 输入字符串 For i = 1 To n a(i) = InputBox("请输入第 " & i & " 个字符串") Next i ' 冒泡排序(递减) For i = 1 To n For j = 1 To n - i ' 使用 StrComp 比较,-1 表示 a(j) < a(j+1),即递减序 If StrComp(a(j), a(j + 1), vbBinaryCompare) < 0 Then t = a(j) a(j) = a(j + 1) a(j + 1) = t End If Next j Next i ' 输出 Debug.Print "递减排序结果:" For i = 1 To n Debug.Print a(i) Next i End Sub

参数说明StrComp(string1, string2, compare)返回-1string1<string2)、0(相等)、1string1>string2);vbBinaryCompare表示二进制比较(区分大小写,ASCII 序);< 0a(j) < a(j+1),满足递减条件。此写法比直接a(j) < a(j+1)更明确,且可轻松切换为vbTextCompare实现不区分大小写排序。

5.3 进阶技巧:用Collection对象实现高效字符串排序

对于大量字符串,冒泡排序 O(n²) 效率低。VB 的Collection对象虽无内置排序,但可结合Key属性模拟索引。不过更实用的是利用Scripting.Dictionary(需引用 Microsoft Scripting Runtime)的Keys属性,但本题集聚焦原生 VB,故推荐一个轻量技巧:预计算字符串长度并用Select Case分组,再对每组内部排序,减少比较次数。但针对本题 5 个字符串,冒泡已足够,重点在于理解比较逻辑的精确性。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询