设计一个成绩管理系统,要求完成以下功能:
(1)能按学期和班级完成对学生成绩的录入和修改
(2)能按班级统计学生的成绩,求学生的总成绩和平均分
(3)能根据学生的平均成绩进行排序
(4)能查询学生成绩和不及格科目
(5)能打印学生名单
(6)能按班级输出学生成绩单
import java.util.Scanner;
class Student1 {
String num;
String name;
int cla;
int c1;
int c2;
int c3;
int c4;
int term;
float aver;
int sum;
}
public class StudentManagementSystem2 {
private static final int MAX_STUDENTS = 80;
private static Student[] stu = new Student[MAX_STUDENTS];
private static int numStudents = 0;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int choice;
do {
System.out.println("1.录入学生成绩");
System.out.println("2.修改学生成绩");
System.out.println("3.查看学生成绩");
System.out.println("4.平均分排序");
System.out.println("5.查询学生成绩");
System.out.println("6.不及格学生");
System.out.println("7.输出成绩单");
System.out.println("8.结束程序");
System.out.print("请选择操作: ");
choice = scanner.nextInt();
switch (choice) {
case 1:
numStudents = inputStudents(stu, numStudents);
break;
case 2:
modifyScores(stu, numStudents);
break;
case 3:
viewScores(stu, numStudents);
break;
case 4:
sortByAverage(stu, numStudents);
break;
case 5:
findStudent(stu, numStudents);
break;
case 6:
findFailingStudents(stu, numStudents);
break;
case 7:
printScoreSheet(stu, numStudents);
break;
case 8:
System.out.println("程序结束");
break;
default:
System.out.println("选择错误,请重新输入。");
break;
}
scanner.nextLine(); // Consume the newline character
System.out.println("按回车键继续...");
scanner.nextLine();
clearScreen();
} while (choice != 8);
}
private static int inputStudents(Student[] st, int n) {
Scanner scanner = new Scanner(System.in);
int choice;
System.out.println("按学期输入请按1,按班级输入请按2");
choice = scanner.nextInt();
scanner.nextLine();
if (choice == 1) {
System.out.print("请输入学期: ");
int term = scanner.nextInt();
scanner.nextLine();//用于读取用户在控制台输入的回车键(换行符),以等待用户按回车继续执行程序。
while (true) {
System.out.print("学生学号: ");
String num = scanner.nextLine();
// Check for duplicate student number
boolean duplicate = false;
for (int i = 0; i < n; i++) {
if (st[i].num.equals(num)) {
duplicate = true;
break;
}
}
if (duplicate) {
System.out.println("学号已存在,请重新输入学号。");
continue;
}
System.out.print("学生姓名: ");
String name = scanner.nextLine();
System.out.print("学生班级: ");
int cla = scanner.nextInt();
System.out.print("学生科目1: ");
int c1;
c1= scanner.nextInt();
while(c1<0||c1>100) {
System.out.println("成绩无效,请输入0到100之间的成绩。");
c1= scanner.nextInt();
};
System.out.print("学生科目2: ");
int c2 = scanner.nextInt();
while(c2<0||c2>100) {
System.out.println("成绩无效,请输入0到100之间的成绩。");
c2= scanner.nextInt();
};
System.out.print("学生科目3: ");
int c3 = scanner.nextInt();
while(c3<0||c3>100) {
System.out.println("成绩无效,请输入0到100之间的成绩。");
c3= scanner.nextInt();
};
System.out.print("学生科目4: ");
int c4 = scanner.nextInt();
while(c4<0||c4>100) {
System.out.println("成绩无效,请输入0到100之间的成绩。");
c4= scanner.nextInt();
};
st[n] = new Student();
st[n].num = num;
st[n].name = name;
st[n].cla = cla;
st[n].c1 = c1;
st[n].c2 = c2;
st[n].c3 = c3;
st[n].c4 = c4;
st[n].term = term;
st[n].sum = c1 + c2 + c3 + c4;
st[n].aver = st[n].sum / 4.0f;
n++;
System.out.print("是否继续输入?(1-继续,0-退出): ");
choice = scanner.nextInt();
if (choice == 0)
break;
scanner.nextLine();
}
} else if (choice == 2) {
System.out.print("请输入班级: ");
int cla = scanner.nextInt();
scanner.nextLine();
while (true) {
System.out.print("学生学号: ");
String num = scanner.nextLine();
// Check for duplicate student number
boolean duplicate = false;
for (int i = 0; i < n; i++) {
if (st[i].num.equals(num)) {
duplicate = true;
break;
}
}
if (duplicate) {
System.out.println("学号已存在,请重新输入学号。");
continue;
}
System.out.print("学生姓名: ");
String name = scanner.nextLine();
System.out.print("学生科目1: ");
int c1= scanner.nextInt();
while(c1<0||c1>100) {
System.out.println("成绩无效,请输入0到100之间的成绩。");
c1= scanner.nextInt();
};
System.out.print("学生科目2: ");
int c2 = scanner.nextInt();
while(c2<0||c2>100) {
System.out.println("成绩无效,请输入0到100之间的成绩。");
c2= scanner.nextInt();
};
System.out.print("学生科目3: ");
int c3 = scanner.nextInt();
while(c3<0||c3>100) {
System.out.println("成绩无效,请输入0到100之间的成绩。");
c3= scanner.nextInt();
};
System.out.print("学生科目4: ");
int c4 = scanner.nextInt();
while(c4<0||c4>100) {
System.out.println("成绩无效,请输入0到100之间的成绩。");
c4= scanner.nextInt();
};
st[n] = new Student();
st[n].num = num;
st[n].name = name;
st[n].cla = cla;
st[n].c1 = c1;
st[n].c2 = c2;
st[n].c3 = c3;
st[n].c4 = c4;
st[n].term = 0; // Set term to 0 for class input
st[n].sum = c1 + c2 + c3 + c4;
st[n].aver = st[n].sum / 4.0f;
n++;
System.out.print("是否继续输入?(1-继续,0-退出): ");
choice = scanner.nextInt();
if (choice == 0)
break;
scanner.nextLine();
}
} else {
System.out.println("选择错误,请重新输入。");
}
return n;
}
private static void modifyScores(Student[] st, int n) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入要修改成绩的学生学号: ");
String num = scanner.nextLine();
boolean found = false;
for (int i = 0; i < n; i++) {
if (st[i].num.equals(num)) {
System.out.println("找到学生记录:");
System.out.println("学号\t姓名\t班级\t科目1\t科目2\t科目3\t科目4\t平均分");
System.out.println(st[i].num + "\t" + st[i].name + "\t" + st[i].cla + "\t" + st[i].c1 + "\t" + st[i].c2 + "\t" + st[i].c3 + "\t" + st[i].c4 + "\t" + st[i].aver);
System.out.print("请输入要修改的科目(1-4): ");
int subject = scanner.nextInt();
if (subject < 1 || subject > 4) {
System.out.println("选择错误,请重新输入科目范围。");
return;
}
System.out.print("请输入新的成绩: ");
int score = scanner.nextInt();
while(score<0||score>100) {
System.out.println("成绩无效,请输入0到100之间的成绩。");
score= scanner.nextInt();
};
switch (subject) {
case 1:
st[i].c1 = score;
break;
case 2:
st[i].c2 = score;
break;
case 3:
st[i].c3 = score;
break;
case 4:
st[i].c4 = score;
break;
}
st[i].sum = st[i].c1 + st[i].c2 + st[i].c3 + st[i].c4;
st[i].aver = st[i].sum / 4.0f;
System.out.println("成绩修改成功。");
found = true;
break;
}
}
if (!found) {
System.out.println("未找到该学生记录。");
}
}
private static void viewScores(Student[] st, int n) {
System.out.println("学号\t姓名\t班级\t科目1\t科目2\t科目3\t科目4\t平均分");
for (int i = 0; i < n; i++) {
System.out.println(st[i].num + "\t" + st[i].name + "\t" + st[i].cla + "\t" + st[i].c1 + "\t" + st[i].c2 + "\t" + st[i].c3 + "\t" + st[i].c4 + "\t" + st[i].aver);
}
}
private static void sortByAverage(Student[] st, int n) {
// 使用冒泡排序算法对学生数组按平均分进行排序
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (st[j].aver < st[j + 1].aver) {
// 交换学生对象位置
Student temp = st[j];
st[j] = st[j + 1];
st[j + 1] = temp;
}
}
}
System.out.println("学号\t姓名\t班级\t科目1\t科目2\t科目3\t科目4\t平均分");
for (int i = 0; i < n; i++) {
System.out.println(st[i].num + "\t" + st[i].name + "\t" + st[i].cla + "\t" + st[i].c1 + "\t" + st[i].c2 + "\t" + st[i].c3 + "\t" + st[i].c4 + "\t" + st[i].aver);
}
}
private static void findStudent(Student[] st, int n) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入要查询的学生学号: ");
String num = scanner.nextLine();
boolean found = false;
for (int i = 0; i < n; i++) {
if (st[i].num.equals(num)) {
System.out.println("找到学生记录:");
System.out.println("学号\t姓名\t班级\t科目1\t科目2\t科目3\t科目4\t平均分");
System.out.println(st[i].num + "\t" + st[i].name + "\t" + st[i].cla + "\t" + st[i].c1 + "\t" + st[i].c2 + "\t" + st[i].c3 + "\t" + st[i].c4 + "\t" + st[i].aver);
found = true;
break;
}
}
if (!found) {
System.out.println("未找到该学生记录。");
}
}
private static void findFailingStudents(Student[] st, int n) {
System.out.println("不及格学生记录:");
System.out.println("学号\t姓名\t班级\t科目1\t科目2\t科目3\t科目4\t平均分");
for (int i = 0; i < n; i++) {
if (st[i].c1 < 60 || st[i].c2 < 60 || st[i].c3 < 60 || st[i].c4 < 60) {
System.out.println(st[i].num + "\t" + st[i].name + "\t" + st[i].cla + "\t" + st[i].c1 + "\t" + st[i].c2 + "\t" + st[i].c3 + "\t" + st[i].c4 + "\t" + st[i].aver);
}
}
}
private static void printScoreSheet(Student[] st, int n) {
System.out.println("学号\t姓名\t班级\t科目1\t科目2\t科目3\t科目4\t平均分");
for (int i = 0; i < n; i++) {
System.out.println(st[i].num + "\t" + st[i].name + "\t" + st[i].cla + "\t" + st[i].c1 + "\t" + st[i].c2 + "\t" + st[i].c3 + "\t" + st[i].c4 + "\t" + st[i].aver);
}
}
private static void clearScreen() {
System.out.print("");
System.out.flush();// // 刷新输出缓冲区,确保内容被立即输出到控制台
}
}
2.1 main主函数
2.1.1 功能说明
菜单,启动程序
2.1.2 代码分析
在 `main` 方法中,首先创建一个 `Scanner` 对象 `scanner` 用于接收用户输入。然后定义一个整数变量 `choice` 用于存储用户选择的操作。
在一个 `do-while` 循环中,根据用户的选择执行相应的操作。循环会一直执行,直到用户选择结束程序。
在每次循环中,先打印操作菜单,列出了用户可以选择的操作选项。然后通过 `scanner.nextInt()` 获取用户输入的选择操作的数字。
根据用户的选择,使用 `switch` 语句执行相应的操作:
- 如果选择 1,调用 `inputStudents` 方法录入学生成绩,并将更新后的学生数量赋值给 `numStudents`。
- 如果选择 2,调用 `modifyScores` 方法修改学生成绩。
- 如果选择 3,调用 `viewScores` 方法查看学生成绩。
- 如果选择 4,调用 `sortByAverage` 方法对学生数组按平均分排序。
- 如果选择 5,调用 `findStudent` 方法查询学生成绩。
- 如果选择 6,调用 `findFailingStudents` 方法查找不及格学生。
- 如果选择 7,调用 `printScoreSheet` 方法输出成绩单。
- 如果选择 8,打印程序结束的提示信息。
在每次操作执行后,使用 `scanner.nextLine()` 消耗换行符,然后打印提示信息并等待用户按回车键继续。最后,调用 `clearScreen` 方法来清除屏幕显示的内容。整个程序运行在一个循环中,直到用户选择结束程序(选择 8),程序才会退出。
该程序提供了多种操作选项,包括录入学生成绩、修改学生成绩、查看学生成绩、排序、查询和输出成绩单等功能。用户可以根据提示进行相应的操作,并通过回车键继续操作或退出程序。
2.2inputStudents函数
2.2.1功能说明
`inputStudents` 方法用于录入学生成绩信息。
2.2.2 代码分析
`inputStudents`方法的参数包括一个 `Student[]` 类型的数组 `st` 和一个表示当前学生数量的整数 `n`。方法返回更新后的学生数量。
首先,创建一个 `Scanner` 对象 `scanner` 用于接收用户输入。然后声明一个整数变量 `choice`,用于存储用户选择的录入方式。
接下来,通过打印提示信息让用户选择录入方式,输入 1 表示按学期录入,输入 2 表示按班级录入。用户的选择通过 `scanner.nextInt()` 获取,并调用 `scanner.nextLine()` 读取换行符,以等待用户按回车继续执行程序。如果用户选择的是 1(按学期录入),进入 `if` 分支。程序会要求用户输入学期信息,并通过 `scanner.nextInt()` 获取学期值,然后再次调用 `scanner.nextLine()` 读取换行符。
之后,进入一个无限循环,用于多次录入学生信息。首先,提示用户输入学生学号,并通过 `scanner.nextLine()` 获取输入值。然后,检查输入的学号是否已存在,避免学号重复。如果学号重复,打印错误信息并使用 `continue` 关键字跳过本次循环,重新输入学号。
接下来,提示用户输入学生姓名、班级以及四门科目的成绩。针对每门科目的成绩输入,先通过 `scanner.nextInt()` 获取输入值,然后进行有效性判断,如果输入的成绩不在 0 到 100 的范围内,打印错误信息并要求重新输入,直到输入有效的成绩为止。创建一个新的 `Student` 对象,将输入的学生信息赋值给该对象的相应属性。计算学生的总分和平均分,并更新到对象的属性中。
然后,将新的 `Student` 对象存储到 `st` 数组的第 `n` 个位置,增加学生数量 `n`。询问用户是否继续输入。通过 `scanner.nextInt()` 获取用户的选择,如果选择为 0,则退出循环;否则,继续下一次循环。再次使用 `scanner.nextLine()` 读取换行符。如果用户选择的是 2(按班级录入),进入 `else if` 分支。程序会要求用户输入班级信息,并通过 `scanner.nextInt()` 获取班级值,然后再次调用 `scanner.nextLine()` 读取换行符。
之后,进入一个无限循环,逻辑与前面的分支相同,只是这次不需要输入学期,而是将学期设置为 0,表示按班级录入。如果用户选择的既不是 1 也不是 2,输出错误提示信息。
最后,返回更新后的学生数量 `n`。这个方法通过循环和条件判断,根据用户选择的不同录入方式,接受用户的输入,并将输入的学生信息存储到 `Student` 对象数组中。同时,对学号的重复性进行了检查,确保每个学生的学号是唯一的。方法的设计使得可以灵活地根据用户的选择录入学生信息,满足了不同需求的录入方式。
2.3modifyScores函数
2.3.1功能说明
modifyScores 方法用于修改学生成绩。
2.3.2 代码分析
方法的参数包括一个 `Student[]` 类型的数组 `st` 和一个表示当前学生数量的整数 `n`。该方法没有返回值。首先,创建一个 `Scanner` 对象 `scanner` 用于接收用户输入。然后提示用户输入要修改成绩的学生学号,并通过 `scanner.nextLine()` 获取输入值。
接下来,使用一个布尔变量 `found` 来记录是否找到了要修改成绩的学生记录,默认为 `false`。
然后,通过一个 `for` 循环遍历学生数组 `st`,对每个学生对象进行遍历。如果找到了与输入的学号匹配的学生记录,进入 `if` 分支。在 `if` 分支中,首先打印找到的学生记录的信息,包括学号、姓名、班级、四门科目的成绩和平均分等。
然后,提示用户输入要修改的科目编号,并通过 `scanner.nextInt()` 获取输入值。如果输入值不在 1 到 4 的范围内,打印错误信息并使用 `return` 语句结束方法。
接下来,提示用户输入新的成绩,并通过 `scanner.nextInt()` 获取输入值。同样地,如果输入的成绩不在 0 到 100 的范围内,打印错误信息并要求重新输入。
然后,使用 `switch` 语句根据用户输入的科目编号,修改相应学生对象的对应科目的成绩。修改完成绩后,重新计算学生的总分和平均分,并更新到学生对象的属性中。
最后,打印提示信息表示成绩修改成功,并将 `found` 设置为 `true` 表示已找到要修改成绩的学生记录,并使用 `break` 语句跳出循环。如果没有找到匹配的学生记录,即循环结束后 `found` 仍为 `false`,打印未找到该学生记录的提示信息。
这样,通过遍历学生数组,并根据用户输入的学号查找到对应的学生记录,然后修改该学生的指定科目的成绩,最后更新总分和平均分,实现了学生成绩的修改功能。
2.4viewScores函数
2.4.1功能说明
viewScores 方法用于查看学生成绩
2.4.2 代码分析
`viewScores` 方法用于查看学生成绩。方法的参数包括一个 `Student[]` 类型的数组 `st` 和一个表示当前学生数量的整数 `n`。该方法没有返回值。
首先,在控制台打印一行表头,包含学号、姓名、班级、四门科目的成绩和平均分。
然后,通过一个 `for` 循环遍历学生数组 `st`,对每个学生对象进行遍历。在循环内部,使用 `System.out.println` 打印每个学生对象的学号、姓名、班级、四门科目的成绩和平均分。
通过该方法,可以将所有学生的学号、姓名、班级、各科成绩和平均分逐行打印出来,实现了学生成绩的查看功能。
2.5 sortByAverage函数
2.5.1功能说明
`sortByAverage` 方法用于按照学生的平均分对学生数组进行排序。
2.5.2 代码分析
方法的参数包括一个 `Student[]` 类型的数组 `st` 和一个表示当前学生数量的整数 `n`。该方法没有返回值。
使用冒泡排序算法对学生数组进行排序。外层循环控制比较的轮数,内层循环控制每轮比较的次数。通过比较相邻的学生对象的平均分大小,如果前一个学生对象的平均分小于后一个学生对象的平均分,就交换它们的位置。
在排序完成后,通过一个 `for` 循环遍历学生数组 `st`,对每个学生对象进行遍历。在循环内部,使用 `System.out.println` 打印每个学生对象的学号、姓名、班级、四门科目的成绩和平均分。
通过该方法,可以将学生数组按照平均分从高到低进行排序,并将排序后的结果逐行打印出来,实现了按平均分排序的功能。
2.6 findStudent函数
2.6.1功能说明
`findStudent ` 方法用于根据学生学号查询学生记录。
2.6.2 代码分析
方法的参数包括一个 `Student[]` 类型的数组 `st` 和一个表示当前学生数量的整数 `n`。该方法没有返回值。首先,创建一个 `Scanner` 对象 `scanner` 用于接收用户输入。然后提示用户输入要查询的学生学号,并通过 `scanner.nextLine()` 获取输入值。接下来,使用一个布尔变量 `found` 来记录是否找到了匹配的学生记录,默认为 `false`。然后,通过一个 `for` 循环遍历学生数组 `st`,对每个学生对象进行遍历。在循环内部,使用条件判断 `if (st[i].num.equals(num))` 来判断学生对象的学号是否与输入的学号匹配。
如果找到了匹配的学生记录,进入 `if` 分支。在分支内部,打印找到的学生记录的信息,包括学号、姓名、班级、四门科目的成绩和平均分等。然后将 `found` 设置为 `true` 表示已找到该学生记录,并使用 `break` 语句跳出循环。
如果没有找到匹配的学生记录,即循环结束后 `found` 仍为 `false`,打印未找到该学生记录的提示信息。
通过该方法,可以根据学生学号进行查询,打印出匹配的学生记录的详细信息,或者提示未找到该学生记录的信息。
2.7 findFailingStudents函数
2.7.1功能说明
`findFailingStudents` 方法用于找到不及格学生的记录。
2.7.2 代码分析
方法的参数包括一个 `Student[]` 类型的数组 `st` 和一个表示当前学生数量的整数 `n`。该方法没有返回值。
首先,打印标题行,包括学号、姓名、班级、四门科目的成绩和平均分。
然后,通过一个 `for` 循环遍历学生数组 `st`,对每个学生对象进行遍历。在循环内部,使用条件判断 `if (st[i].c1 < 60 || st[i].c2 < 60 || st[i].c3 < 60 || st[i].c4 < 60)` 来判断学生是否有任一科目的成绩低于 60 分(即不及格)。
如果学生有任一科目的成绩低于 60 分,进入 `if` 分支。在分支内部,使用 `System.out.println` 打印该学生的学号、姓名、班级、四门科目的成绩和平均分。
通过该方法,可以找到所有有不及格科目的学生记录,并将这些学生的学号、姓名、班级、各科成绩和平均分逐行打印出来,实现了找到不及格学生的记录的功能。
2.8 printScoreSheet函数
2.8.1功能说明
`printScoreSheet` 方法用于打印成绩单。
2.8.2 代码分析
方法的参数包括一个 `Student[]` 类型的数组 `st` 和一个表示当前学生数量的整数 `n`。该方法没有返回值。
首先,打印标题行,包括学号、姓名、班级、四门科目的成绩和平均分。
然后,通过一个 `for` 循环遍历学生数组 `st`,对每个学生对象进行遍历。在循环内部,使用 `System.out.println` 打印每个学生对象的学号、姓名、班级、四门科目的成绩和平均分。
通过该方法,可以将所有学生的学号、姓名、班级、各科成绩和平均分逐行打印出来,实现了打印成绩单的功能。
三、数据处理方案
主类包含三个成员变量:`MAX_STUDENTS`、`stu`和`numStudents`。
1. `MAX_STUDENTS`:这是一个常量整数变量,声明为 `private static final`。`private` 修饰符表示只能在类内部访问。`static` 修饰符表示它被类的所有实例共享,`final` 表示一旦赋值后其值就不能更改。在这种情况下,`MAX_STUDENTS` 设置为 80,意味着 `stu` 数组中可以存储的最大学生数是 80。
2. `stu`:这是一个 `Student` 对象数组,长度为 `MAX_STUDENTS`。假设 `Student` 类在其他地方定义。在创建数组时,所有元素都被初始化为 `null`。
3. `numStudents`:这是一个整数变量,用于跟踪当前存储在 `stu` 数组中的学生数量。它被初始化为 0,表示最初没有学生。
`Student1`类,具有以下成员变量:
1. `num`:一个字符串类型的变量,用于存储学生的学号。
2. `name`:一个字符串类型的变量,用于存储学生的姓名。
3. `cla`:一个整数类型的变量,表示学生所在的班级。
4. `c1`、`c2`、`c3`、`c4`:四个整数类型的变量,表示学生的四门课程成绩。
5. `term`:一个整数类型的变量,表示学生所在的学期。
6. `aver`:一个浮点数类型的变量,表示学生的平均分。
7. `sum`:一个整数类型的变量,表示学生的总分。
四、总结
实验心得:
在设计和实现成绩管理系统的过程中,我对面向对象编程和数据结构有了更深入的理解。通过这个实验,我掌握了以下几个重要的概念和技能:
1. 类和对象:我学会了如何定义和使用类来表示学生和成绩等相关信息,并通过创建对象来操作和管理这些数据。
2. 数据结构:我了解了如何使用合适的数据结构来组织和存储学生的成绩数据,例如使用数组或集合来存储学生对象。
3. 数据录入和修改:我学会了如何设计功能,使得用户可以根据学期和班级对学生成绩进行录入和修改。这涉及到对输入进行验证和更新相应的数据结构。
4. 统计和计算:我实现了对班级学生成绩的统计功能,包括计算总成绩和平均分。这需要遍历学生对象并累加相应的成绩数据。
5. 排序和查询:我实现了根据学生的平均成绩进行排序的功能,并能够查询学生成绩和不及格科目。这涉及到排序算法和遍历查询数据的技巧。
6. 输出和打印:我学会了按照要求输出学生名单和成绩单,可以根据班级进行输出,以便更好地组织和呈现成绩数据。
总结:
通过完成这个实验,我深入理解了面向对象编程和数据结构在实际项目中的应用。我熟悉了设计和实现一个简单的成绩管理系统所涉及的各种功能和操作,包括录入、修改、统计、排序、查询和打印。我还学会了解决一些常见的问题,如数据验证和处理异常情况。这个实验提高了我的编程能力和问题解决能力,并为我今后开发更复杂的软件系统奠定了基础。