You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Turbo C编写的DOS程序在memset64000个int数组后崩溃?

解决MS-DOS 6.22下Turbo C++ 3.0 Mode 13h图形程序崩溃问题

问题场景

在VirtualBox的MS-DOS 6.22系统中,使用Turbo C++ 3.0编写Mode 13h图形程序时,出现memset无效、调用pokeb后程序崩溃的问题,目标是实现全屏白色填充。

原代码:

#include <stdlib.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>

int main(void) {
  int *buf;
  unsigned int i;

  _AH = 0x0;
  _AL = 0x13;
  geninterrupt(0x10);

  buf = malloc(sizeof(int)*64000);
  memset(buf,15,64000); //can't figure out why memset does not work properly...

  for (i=0;i< (unsigned int)64000;i++){
    buf[i] = 15; //trying to forcely set each byte to 0xf...
    pokeb(0xA000,i,buf[i]); //outputting to VGA
  }

  getch();
  free(buf);
  return(0);
}

错误原因分析

  1. 缓冲区类型不匹配
    Mode 13h的VGA显存是320×200分辨率,每个像素占1字节,总大小64000字节。你使用int* buf(int在Turbo C中为2字节),导致:

    • malloc(sizeof(int)*64000)分配了128KB内存,远超需求;
    • memset(buf,15,64000)仅能填充前64KB(32000个int),且每个int的两个字节都会被设为0x0f,不符合单像素单字节的逻辑;
    • 循环中buf[i]访问的是第i个int(对应显存的第2i和2i+1字节),逻辑完全错位。
  2. BIOS中断调用不规范
    直接给_AH、_AL赋值后调用geninterrupt并非Turbo C的标准用法,可能引发寄存器冲突,导致视频模式切换异常或程序崩溃。

  3. 未检查内存分配结果
    若malloc失败返回NULL,后续对buf的操作会直接触发崩溃。

  4. 未恢复文本模式
    程序退出后停留在图形模式,会导致DOS界面乱码,同时可能残留异常状态。

修正后的代码

方案1:使用缓冲区填充

#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <string.h>

int main(void) {
    unsigned char *buf;
    unsigned int i;
    union REGS regs;

    // 切换到Mode 13h(320×200 256色)
    regs.x.ax = 0x0013;
    int86(0x10, &regs, &regs);

    // 分配显存大小的缓冲区,检查分配结果
    buf = (unsigned char*)malloc(64000);
    if (!buf) {
        // 分配失败,恢复文本模式后退出
        regs.x.ax = 0x0003;
        int86(0x10, &regs, &regs);
        return 1;
    }

    // 用memset一次性填充所有像素为白色(颜色值15)
    memset(buf, 15, 64000);

    // 将缓冲区内容写入VGA显存
    for (i = 0; i < 64000; i++) {
        pokeb(0xA000, i, buf[i]);
    }

    // 等待按键
    getch();

    // 释放内存
    free(buf);

    // 恢复文本模式(0x03)
    regs.x.ax = 0x0003;
    int86(0x10, &regs, &regs);

    return 0;
}

方案2:直接操作显存(更高效)

不需要缓冲区,直接循环写入显存:

#include <conio.h>
#include <dos.h>

int main(void) {
    unsigned int i;
    union REGS regs;

    // 切换到Mode 13h
    regs.x.ax = 0x0013;
    int86(0x10, &regs, &regs);

    // 直接填充显存为白色
    for (i = 0; i < 64000; i++) {
        pokeb(0xA000, i, 15);
    }

    getch();

    // 恢复文本模式
    regs.x.ax = 0x0003;
    int86(0x10, &regs, &regs);

    return 0;
}

关键修复点说明

  • 将缓冲区类型改为unsigned char*,匹配Mode 13h单像素单字节的结构;
  • 使用union REGS配合int86函数规范调用BIOS中断,保证寄存器操作安全;
  • 增加malloc结果检查,避免空指针操作;
  • 程序退出前恢复文本模式,避免界面乱码;
  • 利用memset高效完成批量字节赋值,替代冗余的手动循环。

内容的提问来源于stack exchange,提问作者SlickSpore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:08:07