CS106L Winter2025 Assignment1 SimpleEnroll

关于CS106L的第一个作业的个人解法

写在前面

本文取自Stanford CS106L的第一个作业,以下为笔者对本作业的思考以及对C++的一些思考。

CS106L作为C++的课程名不虚传,其特性只有自己写题时才能感知出来,一个简单的操作居然会有许多不同的方法来实现,笔者十分震惊,在这之前笔者对于C++仅是只闻其名,不闻其人。

关于此题,若你有有任何问题或更好的方法,欢迎与我联系。

点这里向我发邮件

具体思路

Part 0: Read the code and fill in the Course struct

本题一共有两个任务

  1. 整体看一下代码
  2. 补充完整结构Course

首先观察一下整体代码,并说一下整个作业需要我们完成什么。本作业需要我们通过一个csv文件,来看看在一个特定的学期当中,有哪些课被学生选了并允许达到开课的要求,而有哪些课是没有被选的,在这里我们创建一个结构体Course其中包括三个参数,title课程名称、number_of_units此课程共有几个单元以及quarter学期,值得注意的是,国外学期用的是季节+年份来表示。

在下面有一个函数parse_csv即将一个csv文件转变为一个Course数组来存放。

还有write_courses_offeredwrite_courses_not_offered,分别代表将数组中的可以开课的课程存入一个csv文件和将数组中不可以开课的课程存入另一个csv文件当中。

下一部分看看结构体Course,观察题目给我们的csv文件可以发现,titlequarter均为字符串的形式,故它们的类型均为String,对于number_of_units笔者一开始认为其应该为int类型,但之后会用到一个spilt函数,其类型属于String,即将一个字符串分成好几个不同的字符串,故这里的number_of_units也应该为String类型,

1
2
3
4
5
struct Course {
  std::string title;
  std::string number_of_units;
  std::string quarter;
};

接下来看代码中的注释,告诉我们看一下main函数,并告知我们这三个函数需要更改一下签名,观察可得,从始至终用的都是同一个结构体数组,而不是一直复制一个不断更改,故可以知道这里的数组应该是引用类型,即指向的是地址,改变一次,下一次也接着改变,故对于parse_csv函数来说需要将签名改为引用类型,而对于write_courses_offered函数来说,它存在特殊要求,最后是需要将参数数组在其原基础上做更改,所以也需要改为引用类型,对于write_courses_not_offered则没有这种要求,故不需要更改,

1
2
void write_courses_offered(std::vector<Course>& all_courses)
void write_courses_not_offered(std::vector<Course> unlisted_courses)

Part 1: parse_csv

本题需要我们完成parse_csv函数,此函数主要是读取一个csv文件的内容,并将其中的内容保存在一个Course数组中,简单思考一下,

  1. 应该要使用IO流的方法来读取外部文件的内容,需要注意的是如何打开、关闭一个文件
  2. 每一行都对应了一个Course故要一行一行的读取内容,在这里应使用getline()函数
  3. 最上面一行的内容不属于Course应忽略,有多种方式可以忽略,如ignore函数,或仅读取却不做任何操作
  4. 一行内容存放了三个不同的值,应使用split函数(应include此文件),对于此函数,其返回的是一个字符串数组,故可以使用[]表达式来取值
  5. 关于如何对一个结构体数组添加元素,有许多方法可以做到,如push_back函数或emplace_back(这也是笔者对C++很震惊的一点,一个操作居然有如此多种方法可以实现)

故可以写出代码,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
void parse_csv(std::string filename, std::vector<Course>& courses) {
  std::ifstream inputFile;
  inputFile.open(filename);
  if (inputFile.is_open()) {
    std::string line;
    std::getline(inputFile, line);
    std::vector<std::string> splitString;

    while (std::getline(inputFile, line)) {
      splitString = split(line, ',');
      Course c;
      c.title = splitString[0];
      c.number_of_units = splitString[1];
      c.quarter = splitString[2];
      courses.push_back({c});
    }
  }
  inputFile.close();
}

Part 2: write_courses_offered

本题需要将已经存在的一个Course数组进行筛选,选出quarter不为null的课程,写入一个新csv文件,并在最后将此存在的数组删除这些为null的课程,值得注意的点有,

  1. 将数组中的内容写入文件中,应使用ofstream来做,记得打开文件也要关闭文件
  2. 对于新csv文件的第一行会有一个特殊的内容需要单独写入
  3. 需要记录下来哪些是需要删除的课程,并在最后使用题目给我们的delete_elem_from_vector函数来删除

故简单写出代码,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
void write_courses_offered(std::vector<Course>& all_courses) {
  std::ofstream outfile;
  outfile.open(COURSES_OFFERED_PATH);
      std::vector<Course> course_need_to_delete;

  if (outfile.is_open()) {
    outfile << "Title,Number of Units,Quarter" << std::endl;

    for (Course c: all_courses) {
      if (c.quarter != "null") {
        outfile << c.title << ',' << c.number_of_units << ',' << c.quarter << std::endl;
        course_need_to_delete.push_back({c});
      }
    }
  }
  outfile.close();
  for (auto& c : course_need_to_delete) {
    delete_elem_from_vector(all_courses, c);
  }
}

Part 3: write_courses_not_offered

此题需要将一个已经存在的Course数组进行筛选,选出quarter为null的课程,写入一个新csv文件,但不需要删除,故大致部分与上文无二,还少了最后一个部分,不赘述,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
void write_courses_not_offered(std::vector<Course> unlisted_courses) {
  /* (STUDENT TODO) Your code goes here... */
  std::ofstream outfile;
  outfile.open(COURSES_NOT_OFFERED_PATH);
  if (outfile.is_open()) {
    outfile << "Title,Number of Units,Quarter" << std::endl;
    for (Course c : unlisted_courses) {
    outfile << c.title << ',' << c.number_of_units << ',' << c.quarter << std::endl;
    }
  }
  outfile.close();
}

常见问题

  • 不要忘了将main函数的注释给删掉,才能进行autograde评分。笔者在这里起码缠了半个小时(要疯了)

autograde

不会摄影的药师不是好程序员
使用 Hugo 构建
主题 StackJimmy 设计