首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >一种基于c++的自动阅卷机

一种基于c++的自动阅卷机
EN

Stack Overflow用户
提问于 2021-03-09 14:32:48
回答 2查看 168关注 0票数 1

我正在尝试为我正在教授的一门C++课程写一个自动评分程序。通常,自动评分器使用(输入,输出)对:提交的程序从标准输入读取并写入标准输出,评分器将其与预期输出进行比较。但我希望我的学生练习特定的C++结构(而不是用C编写程序),所以测试是用C++编写的。在一个简单的示例中,我给他们提供了一个主程序,如下所示:

代码语言:javascript
运行
复制
#include "func.hpp"
...

int main() {
    test(func(1)==2);
    test(func(2)==33);
    ...  
    /* some 100 tests, including some randomized tests */
    ...
    cout << "Grade: " << grade << endl;
}

学生必须提交文件func.hppfunc.cpp (对于更复杂的作业,需要更多的文件)。

有一个bash脚本,它用func.cpp编译main.cpp,运行程序,并从最后一行读取成绩(它在docker容器中运行,以防止无意中损坏主机)。

问题是,学生可以在func中打印“成绩: 100”并退出。

有没有一种简单的方法可以让评分器更可靠?

EN

回答 2

Stack Overflow用户

发布于 2021-03-12 10:42:40

我不想为此发疯,但如果你想让它安全,你应该把学生作业放在所谓的“洁净室”里。这是一个乏味的练习,但一旦完成,它将是非常安全的。您说您在docker容器中运行,所以我将在一个子进程中运行学生的作业,并将IO重定向(重定向到管道、文件或/dev/null,这取决于您的一些作业是否涉及控制台输出)。这样一来,一个聪明的学生可以打印他们想要的任何东西,但他们只会把它传给你,而不是打印到控制台。我不打算深入到这方面的代码-我在Stack Overflow上看到了很多我喜欢的例子,通过搜索"fork with redirected stdout“,这是一个典型的forumula,你可能知道。

在伪代码中,它看起来像这样:

代码语言:javascript
运行
复制
main() {
  <tedious setup for stdin/stdout/stderr redirection>;
  int ch = fork();
  if (ch == 0) {
    test(func(1)==2);
    test(func(2)==33);
         .
         .
    // test clearly generates "grade" so use it as an exit code as an
    // easy way to return the information you want
    exit(grade);
  } else {

    for (;;) {
      <wait on and read stdout and stderr and do whatever you want to it - it won't go to the console, so no dirty tricks.>;
      <you could analyze the student's output as part of grading, or pass it to the console with a highlight, so you know it's not your grade output>
      <wait on ch to exit, get the exit code, display it as the grade and break>;
      <generate some input if you want to have an assignment where the students read from stdin>;
      <add a time-out on waiting for the child to exit. That way evil student can't just hang or busy-loop, whether on purpose by accident.>;
      <if it seems to be hanging, you have to process id and can kill it.>;
    }
  }
}

显然,上面的内容是粗略的。当您循环管理子进程时,您必须同时使用select或类似的工具检查所有内容,但您听起来像是一个相当高级的工程师。你得到了基本的概念。如果您将学生的运行时环境放在您管理的子进程中,那么他们将无法逃脱任何惩罚。此外,它还为您提供了一个平台,可以在您认为合适的任何地方提取其代码的字符串。

票数 2
EN

Stack Overflow用户

发布于 2021-03-09 14:39:10

很简单。当您进行分析时,只需使用不同于您提供给学生的main作为参考程序。您的版本会打印您的密钥。

代码语言:javascript
运行
复制
int main() {
    test(func(1)==2);
    test(func(2)==33);
    ...  
    /* some 100 tests, including some randomized tests */
    ...

    cout << "The student doesn't know my version prints this next line" << endl;
    cout << "Secret validation code: NCC-1701" << endl;

    cout << "Grade: " << grade << endl;
}

聪明的学生如果按照您的建议执行(打印100并退出),就不会知道您的版本打印和脚本验证的秘密消息。

真实的故事。当我在教网络课的时候,有一个家庭作业要用UDP套接字实现一个“停止并等待”协议。我的代码实现了“客户端”。学生版本实现了“服务器”。一个学生没有让网络调用工作,但他足够聪明,只在print语句之间使用睡眠调用来打印预期的输出。如果我没有先停止我的客户端程序,并注意到他的程序仍在打印我们正在接收的“传入”数据行,他可能会逃脱惩罚。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66541909

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档