Search code examples
cx86-16dosturbo-c

Why is my DOS program crashing after I memset an array of 64 thousand `int`s?


I have a problem with memset and a big for loop in Turbo C.

I was programming a small Graphics library based on Mode 13h with Turbo C++ 3.00 on MS-DOS 6.22 on Virtual Box, when the code started crashing.

I know that Turbo C is really outdated, but I wanted to try the old-style coding on DOS like systems.

Here's my code:

#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);
}

What I was trying to do was basically filling the screen with the white color.

Once I started coding I noticed that memset was not setting ALL of the bytes of my heap array to 0xf.

So I decided to set them manually by coding the for loop.

I ran it and it worked like butter. As soon as I poked the byte to the screen, the program crashed, and I couldn't figure out why...

Any help?

PS: I'm pretty new to C.


Solution

  • In MS-DOS memory is organised in segments of no more than 64K.

    Your buffer of 64,000 integers is larger than that.

    If you used unsigned char (single bytes) instead of int or unsigned int (which I seem to remember are 16 bits in DOS/Turbo C++) then it would fit into a single segment and should work fine.

    ... And as you're storing bytes to be poked into video memory, you don't need the extra bit-width that integers give you.

    #include <stdlib.h>
    #include <conio.h>
    #include <stdio.h>
    #include <string.h>
    #include <dos.h>
    
    int main() {
      unsigned char *buf;
      unsigned int i;
    
      _AH = 0x0;
      _AL = 0x13;
      geninterrupt(0x10);
    
      buf = malloc(64000);
      memset(buf, 15, 64000);
    
      for (i=0; i < (unsigned int)64000; i++) {
        pokeb(0xA000, i, buf[i]); //outputting to VGA
      }
      getch();
      free(buf);
      return(0);
    }
    

    As @Jabberwocky has mentioned, if you don't plan to do anything else but poke these values directly to video RAM, you can even ignore the buffer entirely:

    int main() {
      unsigned int i;
    
      _AH = 0x0;
      _AL = 0x13;
      geninterrupt(0x10);
    
      for (i=0; i < (unsigned int)64000; i++) {
        pokeb(0xA000, i, 15); //outputting to VGA
      }
      getch();
      return(0);
    }