C Game Programming For Dummies 2
C Game Programming For Dummies 2
Other Information
Source Code Files
On-line Book Ordering
Related Web Pages 1. If you're looking for the Lessons promised in Chapter
11 (stuff on linked lists), see Chapter 17 below.
The Rules
You are granted the right to print one (1) copy of each
Lesson for your personal use. You cannot duplicate or
mass reproduce the Lesson(s) or distribute any
material from this Web site in any way. This material is
copyrighted. I'm giving you the right to make one copy
because you own C for Dummies and have, in a sense,
already paid me. If you do not own a copy of C for
Dummies, then buy one!
More to come!
Linux Supplement!
Bonus Lessons!
Bonus C For Dummies Lesson 13.1Lesson 13.1 – Does Anyone Have the Time?
the book. This stinks because getting the time or knowing the time or even
TIMER.H
The time functions in C are defined in the TIMER.H header file for the
most part and — stand back! — they're UNIX time functions. Yech! You would
no. (Compiler and operating system specific time functions are available,
however.)
TIMER.H contains many functions, but the one I want to show you is time.
You might guess that time displays the current time. But no. Or that it
displays perhaps the date and time. But no. No! No! No!
The time function returns the number of seconds that have elapsed since
time_t *timepointer;
Even so, the number of seconds that have passed since you were 12 (or
maybe not even yet born!) is useless. I mean, can you imagine all the math
required to divvy that up into years, months, dates, hours and seconds?
Egads!
converts the time_t value into handy and veryprintable string. Time for a
program!
Name: TODAY.C
#include <stdio.h>
#include <time.h>
int main()
time_t now;
time(&now);
return 0;
The time_t now; statement creates the time_t pointer variable, into which
the time function, time(&now) to create and store the current time — I
The killer is the ctime function inside the printf statement. That's what
converts the number of seconds into a string you can read on the display.
Well, unless you just want to display the time. Or maybe you just want to
display the date. If so, you have to look elsewhere for your time or date
functions. Alas.
Now the rest of the programs in this lesson require use of the DOS.H
header file, which accesses special DOS routines to display the date and
time. If you're using Microsoft Visual C++ versions 4.0 or later, you
The DOS.H header defines two functions, getdate and gettime, which fill
Nifty.
getdate requires you to create a date structure, into which it puts values
as follows:
struct date
};
gettime had you set up a time structure into which it places values in
this manner:
struct time
};
together:
Name: NOW.C
#include <stdio.h>
#include <dos.h>
int main()
getdate(&date);
gettime(&time);
date.da_mon,
date.da_day,
date.da_year,
time.ti_hour,
time.ti_min);
return 0;
Type in the above program, or just relent and shift-click here to download
What you see on your screen will, of course, reflect the current date and
time (according to the computer, at least). A few things to point out:
These two statements create the date and time structures into which
getdate and gettime place the current date and time values. I used the
names date and time for the variables, which could be confusing to some,
formatting string. Also, see the %02d placeholder? That ensures that the
I split the variables in the printf statement onto separate lines so you
can better see them. Those are merely the date and time structure values,
I want you to modify the NOW.C program. I would like it to display the
time in a 12-hour format, from 12:00 a.m. on through 12:00 p.m. (noon),
and then starting with 1:00 p.m. for one o'clock in the afternoon on up to
11:00 at night. So all you're doing is applying some logic and programming
way to do it, though there are better and worse ways! When you're done, or
if you're stuck, you can click here to see my solution, which is only one
Bonus C For Dummies Lesson 13.3Lesson 13.3 – Say Hello to Mr. Bit
Well, I do. He was the Little Man with the Stupid Hat who taught me how
The Little Man with the Stupid Hat (LMSH) had ten fingers – just like you
do, boys and girls! Easy enough. But the point behind LMSH was to get
everyone to understand the "10s position" and "100s position" and so on,
That's 3 hundreds, 7 tens and 9 ones, which translates into the number
379. Remember how that works? Of course you do. (And if you don't, then at
least you're nodding your head.) Well now I'd like to introduce you to
Binary Man:
Poor Binary Man has only one finger. So he can only count to one. Well,
one and zero. LMSH can use zero fingers to show a zero, and Binary Man can
do so too. Not only that, Binary Man can count to larger numbers just as
LMSH can: you just need more than one of him. Thus:
Because Binary Man has one finger, he counts by twos and not by tens. So
the first place is the 1's, but the second place is the 2's, then 4's,
8's, 16's, 32's and on up, each time double the amount of the previous
Binary Man.
And it's weird primarily because it's not the way we count. We count in
fingers. They have only themselves, so they count by twos. "Base two," is
That's not ten at all. It's the symbol "1" and "0," which people using
anything up there; just symbols. In fact, not all humans use "10" to mean
first (and even if it were, it's not one thousand ten of anything). The
number in binary, however, is the value 10. Here's Binary Man again:
So, just like you learned when you were young, you have 1 in the 8s place
and 1 in the 2s place. Add 8 and 2 and you get . . what? Anyone? Anyone .
..?
Of course, you get ten. That's how binary represents numbers. yes, it's
1 x 64
0 x 32
1 x 16
0x8
1x4
1x2
0x1
Now isn't this a pain? Sure it is. But you shouldn't worry about it since
it's the computer that figures things in binary. With your programming
skills, you can display that value as decimal or even hexadecimal. So the
table like this one handy, so they can easly convert between hex and
binary.
Remember that binary is base 2. Computers are obsessed with base 2.
The printf function lacks a method for displaying binary values. (You
can display Hex and decimal just fine.) But don't panic! There's a
Bit Twiddling
C has a few operators that let you manipulate integer values at the bit
| Boolean OR operation
Okay. You've seen them. I'll save the details for the next lesson. But I
can't let you down here without giving you at least one program. The
a string representing a binary value. It actually uses the & and <<
operators shown above, so you'll have to wait to find out exactly how it
works.
Name: BINBIN.C
#include <stdio.h>
#include <stdlib.h>
void main()
char value[8];
int v;
gets(value);
v = atoi(value);
for(index=0;index<16;index++)
bin[index] = '1';
else
bin[index] = '0';
bin[16] = 0x00;
return(bin);
Type in your favorite number, such as 12345 (no commas). Press the Enter
hexadecimal and in binary. If you add up the binary digits, you'll get the
proper decimal value (which you can verify using Windows' Calculator
will be offered in the next lesson. For now, if you like, feel free to use
Try running the program a few more times with some additional numbers.
Try some negative numbers (-1 through -32000) to see what happens. (I'll
Try entering some "holy" computer numbers: 255, 16384, 1024, 4096,
32767, etc.
binString does in the program. Even so, some comiplers may have a "bin"
Note how the binary and hexadecimal values relate. See how hex is a
Windows may have it all, but DOS could always print in colored text. The
only PC that can’t print in colored text was the old monochrome system.
Since then, and since the color displays have gotten better and better,
The bad news is that there are no native C language routines or functions
for writing colored text on the screen. (Well, they have ‘em in Borland
C++, which I’ll get into later.) The good news is that, thanks to the
versatility of the C language, you can write your own routines. This
Volume I.
The bad news is that writing colored text to the screen requires that you
understand the color codes used by the PC. Even so, the good news is that
it’s not that hard and there’s a table shown later in this Lesson that
Enough news!
The putchar and printf functions in STDIO.H are actually shortcuts to the
secret, inner BIOS routines in the PC’s guts. They use Interrupt 0x10 (the
This function has the following parameters, which are sent to the BIOS in
Character code ? AL
Text color ? BL
Character count ? CX
The Character code is the ASCII value of the character you’re displaying,
which is just like the character you’d specify in a putchar function call.
The Display page is usually zero. (The PC has several text display pages,
though I’ve rarely seen any program use anything other than page 0. (If
you wanted to, you could write a program to display text to different
display pages and then "flip" the pages to rapidly display information –
The text color tells the BIOS which foreground and background colors to
set for the text, whether the text is blinking and whether or not the
Finally, the rarely used Character count value tells the BIOS how many
characters to write to the screen. Normally you write only one, but you
could write up to 65,000 characters providing you send the proper value to
Always use display page zero. That’s the one your PC is probably using
To move the cursor, use the locate function introduced in Lesson 5-3.
You’ll also need to use another function to read the cursor so that
And those color numbers should be unsigned char types. Anything else and
Feeling blue?
When Mr. Norton introduced his Norton Utilities version 2, he added a tool
that changed the color of the DOS prompt and all text displayed at the DOS
prompt. I have no idea how he did that, but you might get a hint of what’s
Name: BLUE.C
#include <stdio.h>
#include <dos.h>
unsigned char x;
while(*text)
dcolor(*text,BLUE);
text++;
putchar('\n');
int x,y;
int86(VIDEO,®s,®s);
regs.x.cx = 1; //count
int86(VIDEO,®s,®s);
y++;
regs.h.bh=0x00; //"page"
regs.h.dh=x; //row
regs.h.dl=y; //column
int86(VIDEO,®s,®s);
Carefully type the above source code into your editor. Actually, since
this is on a Web page, you can copy and paste the source code into your
Am I blue?
The background color is blue and the text is bright white. I’ll explain
some cases you may need to specify _REGS instead of REGS in the dcolor
The cursor position must be read before the character is displayed. (You
Knowing that a character is a byte, you may think that the screen’s
"memory" can hold 2000 bytes. But that’s not so. The screen is actually
4048 bytes big. That’s because each character on the screen has a
companion byte – an attribute byte that tells the monitor which color to
The character and attribute bytes go hand in hand. Normally you never mess
with the attribute bytes. You merely tell your program to display
characters and it does so, placing them on the screen one after the other
also set the attribute byte and thereby control the foreground and
The PC produces color text using three colors: Red, Green and Blue. If
you’ve been around long enough, you may remember the old RGB monitors.
That’s Red, Green and Blue all over again; the three primary colors used
to create just about any other color you see on your screen.
In the attribute byte, there are three bits for the foreground color: one
bit for Red, another for Green and another for Blue. Here’s how that looks
RGB
The byte above is shown with eight bits, 7 through 0 reading left to
right. Bit 0 is the Blue bit; bit 1 is the Green bit and bit 2 is the Red
bit.
Using binary math you haven’t yet been properly introduced to (which is
The numbers shown above (0000-0001) are binary; not decimal. This is base
2 counting stuff; so 100 is not "one hundred," is the binary number 100,
which is four. (This all makes total sense after I get off my butt and
Instead of quibbling about binary here, change the BLUE.C program. Change
line 5 to read:
This sets the attribute to 0x01, which is the Blue bit for blue text.
Save to disk! Compile and run! You should see the text as blue with a
black background.
Now go back to the source code and change the same line to the values 0x02
and then 0x04. Compile and run after making each change. You’ll see Green
text and then Red text when you run each of the programs.
Musical interlude . . .
If you’ve been using a PC since the dark days, then you might recall that
there are actually seven colors you can make text on the screen. In
addition to Red, Green and Blue, there is Cyan, Magenta, Brown and Gray.
Black simply means that none of the colors are used. The PC really does
display the text, but since it’s black-on-black, you can’t see it. (A
Rather than have you re-edit the BLUE.C source code to try all of the
First, remove the #define BLUE statement. Then edit the main function to
read as follows:
void main()
char *t;
printf("%2X - ",fc);
while(*t)
dcolor(*t,fc);
t++;
putchar('\n');
Save the changed file to disk as CLRTEXT.C and compile and run. You’ll see
1 – Sample text
2 – Sample text
3 – Sample text
4 – Sample text
5 – Sample text
6 – Sample text
7 – Sample text
The number and hyphen part of the output (displayed by printf) is not
display routine. That text shows up as gray on white (like number 7).
The %2X part of the printf statement displays the color number as a
hexadecimal value on the screen. This comes in handy later when you’re
The pointer needs to be reset to allow the while loop to scan the same
string of text for each iteration of the for loop. This is advanced
The fourth bit in the character attribute byte is for intensity. It’s not
a color. Instead, the intensity byte tells the display whether or not to
IRGB
The colors you’ve seen so far as dim, actually. To see the whole 16 course
meal in both dim and bright modes, modify the CLRTEXT.C source code so
for(fc=0x00;fc<0x10;fc++)
Basically, change the first value to 0x00 and then the 0x08 into an 0x10.
That tells the program to cycle through all 16 color combinations, from
screen.
Color code 0x0F is all white: 0000-1111 in binary. Looking at the above
binary table, you see that the Intensity, Red, Green and Blue bits are
The for loop cycles color codes from 0x00 through 0x0F. The code 0x10,
specified in the for loop, isn’t used as a text color value since that’s
what tells the loop when to stop. (Review your for loop info if this
confuses you.)
8 different colors for the text background. Yup, these are the same 8
colors used for the foreground text, codes 0 through 7 (see above). There
is no "intensity" bit for the background color attribute, just Red, Green
and Blue bits. And they live in the attribute byte thusly:
RGBIRGB
So for, say, a red background you would switch on the Red background bit:
(since none of the Red, Green or Blue foreground bits are set). So this is
where things get a bit tricky because you must set both foreground and
that you can easily specify foreground and background colors without
0 = Black 4 = Red
1 = Blue 5 = Magenta
2 = Green 6 = Brown
3 = Cyan 7 = Gray
The hexadecimal digits above work for both foreground and background
colors. So if you want Blue text on a Red background, you would use: 0x41
with 4 as the Red background color and 1 as the Blue foreground color.
(The table at the end of this Lesson contains more detail, but the above
Modify CLRTEXT.C so that the main function now looks like this:
void main()
for(bc=0x00;bc<0x80;bc+=0x10)
for(fc=0x00;fc<0x10;fc++)
printf("%2X",fc+bc);
while(*t)
dcolor(*t,fc+bc);
t++;
putchar('\n');
all the foreground and background colors one at a time, displaying each
along with its hexadecimal values.
You’ll see a grid displayed, detailing all the colors possible for the
PC’s screen.
colors.
All the colors with the same foreground and background values (0x11,
0x22, 0x33 and so on) show up as solid on the screen. Better not use
those.
The foreground and background values are added in the program to get the
final text attribute (fc+bc in the program). This works since the text
Eventually.
The PC’s text screen normally uses the 0x07 attribute for all
characters. That is, 0 for black background and 7 for a gray foreground.
There are eight bits in a byte (on the PC at least), so there is one more
bit left to explain in the PC’s text attribute byte: the blinking blinking
BLRGBIRGB
When you set the blinking attribute on, the foreground text blinks. Very
annoying. To see this in action, change the source code for CRLTEXT. You
only need to change on line. Modify the call to the dcolor function so
dcolor(*t,fc+bc|0x80);
You’re adding the pipe character (Shift+\) and then 0x80 to the math
function that sets the color attribute. This is a logical binary operation
that sets the 7th bit in the byte without affecting the other bits. So
You should see the same grid appear on the screen, but with all blinking
foreground text.
Now there is an off-chance you may see the grid displayed with bright
then the video driver may be set to prevent blinking text. If so, press
Alt+Enter to switch to the full screen mode. Then type the following DOS
command:
mode 80
This switches to the regular text screen. Now run the CLRTEXT.C program
Table. Simply combine the foreground and background hex values to get the
00Black00Black
10Blue01Blue
20Green02Green
30Cyan03Cyan
40Red04Red
50Magenta05Magenta
60Brown06Brown
70Gray07Gray
E0Brown (blinking)0EYellow
The dcolor function used throughout this lesson presents a handy way to
display one text character in color on the screen. A nice companion
specific color. That would be the dscolor function, which is shown below
in the final, final rendition of the CLRTEXT.C program, which you can
Name: CLRTEXT.C
#include <stdio.h>
#include <dos.h>
void main()
char *t;
for(bc=0x00;bc<0x80;bc+=0x10)
{
for(fc=0x00;fc<0x10;fc++)
printf("%2X",fc+bc);
dscolor(text,fc+bc);
putchar('\n');
while(*string)
dcolor(*string,color);
string++;
int x,y;
/* First, read the cursor */
int86(VIDEO,®s,®s);
regs.x.cx = 1; //count
int86(VIDEO,®s,®s);
y++;
regs.h.bh=0x00; //"page"
regs.h.dh=x; //row
regs.h.dl=y; //column
int86(VIDEO,®s,®s);
If you get into this color stuff, you may consider creating your own set
specify the proper keyword above and separate it by the | (pipe), which is
the logical OR. So to have bright white text on a blue background, you
That’s FG_Gray (foreground text color gray) OR Bright (for high intensity)
OR BG_Blue (background text color blue). Again, there will be more of this
The Borland C compiler has a whole slew of color text commands, plus
anywhere since very few people bother with DOS programs any more.
Two different commands are used to set the text and background color. Text
textcolor(color)
And background color is set with the textbackground function:
textbackground(color)
earlier in this Lesson for various colors to display on the screen. Or you
can use the color macros predefined in the CONIO.H header file:
BLACK DARKGRAY
BLUE LIGHTBLUE
GREEN LIGHTGREEN
CYAN LIGHTCYAN
RED LIGHTRED
MAGENTA LIGHTMAGENTA
BROWN YELLOW
LIGHTGRAY WHITE
The colors you set are then used by any subsequent calls to the cputs or
cprintf functions. Both of those functions work just like the regular C
counterparts, puts and printf, though the output is in the color specified
You must specify the CONIO.H header file in your source code for these
functions to work.
least not right away. And if you do get it, then you'll never understand
beyond the scope of the books and this Web page. But I've gotten some
questions and I feel it's a neat trick. So I thought I'd toss it up here
Brace yourself
...
Recursion is the art of calling a function within that same function. Now
the guy who thought this up had to be totally nuts. Or a genius. Because,
honestly, why would you call a function from within a function? Let me
Name: RECURSE.C
#include <stdio.h>
void repeat(void)
{
puts("Recursion can drive you mad!");
repeat();
void main()
repeat();
The above program, RECURSE.C, is stupid. I admit it. But it shows you
recursion on the very basic level (albeit stupid recursion). The function
repeat is called from within itself. Anyone who's reading this and who's
Download the source code for RECURSE.C by Shift+clicking here, or you can
type the thing in yourself. By the way, notice that I wrote it "upside
Compile. Yes it will compile. Remember that C compiles stupid things all
the time.
Run.
Press Ctrl+C to stop it. (And please so stop it before you computer
crashes, which it will do if you let the program run too long.)
The program calls the repeat function, which displays the string
But the repeat function then calls itself again, which displays the same
string.
The reason your computer crashes if the program runs too long is that
you run out of stack space, the infamous "Stack Overflow" error message
that drives DOS users nuts. This is explained in the next section.
Now, obviously, recursion is a useful tool. The program RECURSE.C does not
But the program doesn't work because there is no exit from the repeat
stack storage space. Calling the function over and over without ever
the stack's address. Values are pushed onto the stack and can then be
Every time you call a function in C, the stack pointer holds the return
In the figure above, the intro function is being called. The memory
address where that function was called, 0x820 in the figure, is saved
(pushed) onto the stack for storage. The stack pointer then moves down to
What happens with the RECURSE.C program is that the return address keeps
getting pushed onto the stack. The stack keeps moving to a lower address
in memory until the stack eventually destroys other data. The computer
crashes.
To see how this works you can use the _SP macro in Turbo C++/Borland C++
(sorry Microsoft users!). Modify the RECURSE.C program by sticking the
printf("%04X - ",_SP);
Name: RECURSE.C
#include <stdio.h>
void repeat(void)
printf("%04X - ",_SP);
repeat();
void main()
repeat();
Compile and run. This time you'll see the stack pointer's address
Press Ctrl+C to stop so you can get a better view. That four-digit hex
number gets smaller and smaller as the stack keeps pushing down into low
A Way Out
When I first read about recursion I thought, "There blows the stack!" As
from within itself ran the risk of pushing the stack out the back of the
function in the RECURSE.C program. This time, the repeat function has a
way out, but notice how recursion is still used to call the same routine
#include <stdio.h>
void repeat(int x)
if(x)
printf("%04X - ",_SP);
x--;
repeat(x);
void main()
repeat(5);
Download this source code by Shift+clicking here, or you can just modify
the existing source for RECURSE.C in your editor. Remember to save the
file as X5.C.
Note how the repeat function has been re-typed. It now requires an integer
as input. Also, an if test is used, which is the key to making the
recursion work.
No need to press Ctrl+C to stop it this time. You should see something
The repeat function worked through only five times, which is the value
First, the repeat function requires an integer value. That value tells the
if(x)
Any positive value for x causes the loop to repeat. If x is zero, then the
printf("%04X - ",_SP);
repeat(x);
The stack pointer address is printed, along with the catchy phrase. But
then x is decremented. The repeat function is called again, but this time
with a new, smaller value for x. Then the whole thing happens all over.
execute and the repeat function merely returns. At that point, the return
addresses start popping off the stack: Pop! Pop! Pop! Pop! The repeat
function just keeps returning to itself until eventually the big knot
main.
Amen!
Now you can sit and stare and try to figure it out.
Borland Compiler People: Before you ruminate, you can add one more line of
code to the program to visually inspect the popping off of the return
printf("%04X - ",_SP);
x--;
repeat(x);
The last statement is executed as the repeat function returns (when the
recursion starts unwinding). Now, when x equals zero, and the repeat
function returns, you'll see the return addresses as they're popped off
the stack.
Cute.
There was a great article on recursion in the recent Dr. Dobb's Journal,
though most of it was above my head. But that, and a flurry of recent
letters from readers, got me on the subject. I'll show you a really nifty
example of recursion in the next lesson, but before then I thought I'd
I've been messing a lot recently with strings and arrays and needed some
just wouldn't settle for that. No, I wanted to count the number of
Name: CCC.C
#include <stdio.h>
int count = 1;
if(*s++)
count += string_count(s);
else
count--;
return(count);
void main()
x = string_count(string);
copy.
is 25 characters long
Now this one will probably baffle you. You can see how the count variable
called?
Yes, it does. But who cares! The string_count function does not count the
length of the string each time it's called. No, it counts the number of
You see, string_count returns an integer value that is added to the count
For example, for every character in the string, the function is called and
if(*s++)
count += string_count(s);
The if statement checks to see if the NULL (end of string) character has
because the string_count function hasn't yet returned from itself. (Think
return. Only then is the count variable added to itself. The value of
The else part of the if test decrements the value of count, which happens
only once to account for the NULL at the end of the string. (Otherwise the
So, to wrap it all up, the string_count function uses recursion to call
itself once for every character in the string. Then, it counts the number
of returns, incrementing the value each time to get the size of the
string.
Bonus C For Dummies Lesson 15-1Lesson 15-1 — What Files Lurk on Disk
Programmers do not live by simple file access alone. No, there must be
How can I change directories? How can I find out which disk or directory a
file is using? They can all be answered when you unwrap the mystery of
directory access in C.
Of course, there really is not directory access in C. It's all a myth! The
using. (Can you tell where this is leading?) For DOS, the library is
DIR.H, which means these programs compile well in Borland C++ and DJGPP,
but not at all in Microsoft Visual C++ 4.2 or later, or in Linux. Sorry.
There are two companion functions used to find files on disk, both of
The findfirst function is used first. It sets DOS up to look for files
DIR *.*
DIR *.C
DIR HELLO.EXE
*.*, *.C and HELLO.EXE are all patterns findfirst would use.
Next findfirst uses a special file block structure, also defined in the
DIR.H header. This structure is filled with information about the files
found: the file's name, size in bytes, date and time, attributes and other
Finally, findfirst is passed the attributes of files to find. That way you
can search for archive, read-only or even directory files. Searching for
directory files, by the way, is the method by which you can scour the
The following program shows you how findfirst can be set up to locate the
Name: D.C
#include <stdio.h>
#include <dir.h>
if( findfirst("*.*",&fblock,NORMAL) != 0 )
return 1;
return 0;
Hunt and peck this source code, or just click here to download. Compile
it. Run.
The findfirst function ventures out to disk and locates the first file it
finds, which above was D.EXE (the program file itself). That file rang in
The first struct statement defines the file block structure used by the
struct ffblk
directory entry. And this is old DOS stuff too, since the creation
The structure is declared in D.C using struct ffblk fblock. Then the
findfirst("*.*",&fblock,NORMAL);
The first argument is the pattern to match. In this case, it's *.*
is the address of the file block, where information about the found file
is placed by findfirst. Then comes the attribute to match, which is
occurred and the program bails out. Otherwise, the information stored in
You find one, you can find them all! After the initial findfirst function,
structure), yields you all the files in the directory. Well, eventually.
Name: DR.C
#include <stdio.h>
#include <dir.h>
int main()
if( findfirst("*.*",&fblock,NORMAL) != 0 )
return 1;
printf("%s\t%d\n",fblock.ff_name,fblock.ff_fsize);
while( findnext(&fblock) == 0)
printf("%s\t%d\n",fblock.ff_name,fblock.ff_fsize);
return 0;
Enter this program into your editor, or shift-click here to download it.
You can also create the program by simply modifying D.C as shown above.
Essentially there is just one extra line and the modified printf statement
is used twice.
Compile and run.
D.EXE 31792
D.C 605
D.OBJ 732
DR.C 643
DR.EXE 31770
DR.OBJ 737
You see filenames and file sizes. Interesting. A few more moves and you
Nothing much changes between DR.C and D.C. The printf statement is
modified to display only the filename and size. And it's used twice.
The second time printf is used is inside a while loop. The loop uses the
findnext(&fblock)
Using the findnext function with the same file block used by a previous
findfirst function yields the next matching file from the directory.
That's it! The file block structure is refilled with information about the
new file. And as long as the value returned is not zero, the while loop
The while loop ends when the last file from the directory has been read.
You can change the wildcard specification to locate specific files, but
you cannot (usually) specify a full pathname. In C you need to use the
need to create a linked list using structures similar to the file block,
but with the linked list pointer added. (See Chapter 17.)
Changing the file attribute locates only files of that specific type.
For example, before Windows came along I wrote a DOS utility to locate
hidden files in a directory, which was basically the same routine shown
Bonus C For Dummies Lesson 16-1Lesson 16.1 – Welcome to the Lower Level
English-like words used for file access for example — and it has the
twiddle bits and tweak memory with pointers and all that. But C also has
another leg up because most C compilers allow you to embed the one of the
lowest form of computer languages possible right there into your source
Both Borland C++ and Microsoft C++ have the built-in assembly language
feature. Even so, your compiler may implement it differently from the
way documented here. Check your Help file for the details.
If you're using DJGPP, then you'll need to use the ATT nottaion, not the
Intel Assembly notation shown here. Click here for more information.
(Sorry!)
Need I mention that this information here is specific to a PC. You can
different.
language program placed inside a C program. Normally the whole dang doodle
program wouldn't be assembly, only a small part would. But this is one of
Name: HELLOW.C
void main()
Type the above program into your editor, or Shift+click on this link to
download it.
Hello, Weirdo!
display. What you did was to use in-line assembly language — a second
All the lines starting with _asm are assembly language directives.
Some versions of Microsoft C++ may require you to use two underlines
before asm.
Borland C++ may require the presence of the TASM assembler to compile
this program.
The microprocessor speaks only one language. It's called machine language.
Like the name says, it's a language spoken primarily by machines, not by
basic) programming.
B4 09
placed into the AH register is 9. From this you can deduct the following:
The truth is, no one writes programs in machine language. Instead, they
mov ah,09h
The "mov ah" is assembly code for "put the following value into the
value 9 hexadecimal, what you would write a 0x09 in C. This is much easier
than remembering B409. But to the computer, it's the same deal.
does C. In C you have functions already defined for you. In assembly, you
have to create them all using the grunts and snorts of machine language.
other high-level language stuff. Then use assembly language for the stuff
For this Lesson and the rest of this Chapter, I'll use in-line assembly
merely to show you some tricks. In real life you'll probably use it only
when you have some clumsy chunk of code you want to run veryfast.
More good news: Since in-line assembly works the same in both Borland
and Microsoft C, I can show you some common routines between the two. No
Most of this stuff is basic 8086 Assembly language, which still works on
today's monster 32-bit Pentium systems. In fact, I would say very little
assembly coding is done in the full 32-bit mode. (Mostly because your C
compiler creates the 32-bit code for you much more efficiently.)
The following jewel comes from Volume I of C for Dummies, back when this
whole BIOS and DOS call stuff was alien. Hopefully this will make it even
more alien!
Name: DOSVER2.C
#include <stdio.h>
void main()
char major,minor;
Type the above source code into your editor, or Shift+click this link to
DOSVER.C program (which you can download if you Shift+Click here). Gone
are the DOS.H header file, REGS declarations and the int86() function.
The results you see on the screen may vary, depending on which version of
DOS or Windows you're using. For most versions of Windows 95 you'll see
This is all done using Assembly language right inside the C source code.
And you'll notice how easily the variables are echanged between the two
The major and minor variables are declared as chars here instead of
(8-bits). If the variables were integers, then the 8-bit values would
This program may crash with some later versions of Microsoft C++ on
Windows 95. There is a way to compile the program, but you must convince
the Developer Studio how to create DOS programs. (If you know how to do
The next lesson covers the microprocessor itself, its registers and how
Bonus C For Dummies Lesson 17-1Lesson 17-1 – The Birth of Linked Lists
limitations.
At first glance that seems perfectly fine. In fact, if you set out to
build a database program, you could just expand upon the rudiments of the
BDAYS.C program: just change the size of the array to match the maximum
possible input you could imagine. No one would ever suspect a thing! But
you would be wasting memory. And you could potentially run out of memory,
for example, when the Osmond family started using your birthday database
program.
which is why it's not covered in the book. (Well, that and I was running
Just like most advanced concepts, someone smarter than you and I has
already worked out the details for doing linked lists. You merely copy
the way that superbrain at MIT developed linked lists in the '70s, just
like everyone else does. This isn't called cheating. No, it's "using an
algorithm."
There is no requirement that you make a linked list when working with
structures. Arrays are just fine most of the time. In fact, linked lists
Before moving on, you must understand structures through Lesson 11-5 in
the book. Further, a good grasp of pointers and the malloc() function is
structure.
The pointer contains the address of the next structure in the list.
It all works like following clues to get to a hidden treasure; one map
takes you to another map, which takes you to another map and so on. In a
linked list, each structure contains an extra item: a pointer (of the
structure's type) which contains the address of the next structure in the
list.
Each structure contains the address (pointer) of the next structure in the
list. The first structure contains "George Washington" and then the
address of the next structure in the list. This keeps going down to the
last item in the list, which contains 000 or the NULL pointer.
The problem with other C books that try to teach linked lists is that they
give you the whole friggin' linked list program at once. I'll be
different. Below is the silly source code for PREZEZ1.C, which starts to
Name: PREZEZ1.C
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
void main()
struct pres {
char name[25];
strcpy(president->name,"George Washington");
printf("president->name = %s\n",president->name);
copy.
The structure was created and George Washington was stored in its string
variable. Then the address of the next structure for which malloc() has
displayed). This sample holds the rudiments for all linked lists, but it's
Of course, the value you see on your screen may or may not be 3672 for
This should make sense to you: the next variable requires a pointer
value -- an address. To get that address, you simply use the malloc()
equal to the size of the pres structure. (This was all explained in
Chapter 11.)
The PREZEZ1.C program makes room for another structure, but it doesn't do
anything with that room. This doesn't displease the C gods any; it's just
that the program takes only half a step and never completes the process,
Second, that variable should be used to hold the value returned from the
The value returned from the malloc() function -- the address of the new
needed:
president->next = new;
Now the program still runs the same, but the new variable holds a value
strcpy(new->name,"John Adams");
That fills in the name part of the new structure, but to fill in the
Oops! That changes the value of the new variable. Which means you can't
new->next = new;
Ugh! Looks like another structure pointer variable is needed. You must
keep the value of the current structure's address but also have a variable
list
The new variable holds the value of the second structure in the list.
But . . .
You cannot use the new variable to hold the address of the third
structure in the list unless you first save that address in yet another
pointer variable.
No, the solution does not involve an array of pointer variables, though
What you need to work all the structures and their addresses are only
One pointer variable holds the address of the first item in the list,
*first
One pointer variable holds the address of the current item in the list,
*current
One pointer variable is used to hold the address of the next item in the
list, *new
Of course there are problems with this, but don't rush ahead of yourself.
You still need to fix up the PREZEZ.C program so that you can add another
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
void main()
struct pres {
char name[25];
};
strcpy(first->name,"George Washington");
current = new;
strcpy(current->name,"John Adams");
current->next = new;
printf("first->name = %s\n",first->name);
printf("current->name = %s\n",current->name);
Type the above source code into your editor, or Shift+click here to
download the PREZEZ2.C file. Some things have changed: The old president
variable has been replaced by the first variable, and the new and current
There are some limitations: For example, a loop would be better suited to
add new items to the list. Also, there must be some way to tell when
you've reached the end of the list. These issues will be addressed in the
next lesson.
Bonus C For Dummies Lesson 17-2Lesson 17-2 – The Adolescence of Linked Lists
I think I could rattle off about a dozen reasons why so many people find
books present you with a Linked List Program that's all complete. There's
nothing to really learn since you don't ever discover the painful process
-- the journey. You're merely presented with the reward and implored to
understand it. This is why linked lists come in second only to pointers on
From Lesson 17.1 you've seen a vague attempt at creating a linked list
ahead and create a structure with pointers (this was covered in Lesson
11.5):
Fill the space for the new structure using the -> thing.
In fact, aside from using malloc() and the -> thing, structure-pointers
are no different than structures themselves. You just create them on the
With a linked list, you not only create the structures, but you store the
address of each structure in the list; the current structure holds the
address of the next structure in the list. That way you can find things;
So far, the PREZEZ2.C program has it almost right. The bottom line is that
you don't need a whole basket full of structure pointer variables to make
a linked list. You need only three: first, current and new. Working those
into a loop is the problem. (And then there's the problem of starting and
your PC is a linked list describing all the disk drives in your system.
The operating system creates it when it boots: the BIOS tells the
operating system how many drives are physically present and the operating
system creates a linked list describing each drive. If any other drives
are added during the boot process (CD-ROMs, removable drives, network
drives), they're added to the linked list. When the thing is done, the
I've set up the PREZEZ.C series of programs to use static data -- strings
strcpy(first->name,"George Washington");
and
strcpy(current->name,"John Adams");
lists but also because writing an input routine from the keyboard would
make the program bigger. (That type of linked list program is coming, by
the way.) So the first problem to tackle with spiffing up the PREZEZ.C
program is to handle inputting the strings into the list. And the best way
President Of The United States. (Kind of James Bondish, huh?) It shows how
to display an array of strings using a while loop. A null string ends the
Name: POTUS.C
#include <stdio.h>
void main()
char *presidents[] = {
"George Washington",
"John Adams",
"Thomas Jefferson",
"James Madison",
"James Monroe",
""
};
int index = 0;
while(*presidents[index])
{
printf("%s\n",presidents[index]);
index++;
copy.
Compile and Run -- you know the drill. When you run it, you should see the
following:
George Washington
John Adams
Thomas Jefferson
James Madison
James Monroe
The array of Presidents works like any string array: It's an array of
pointers, but in this case the pointers contain the address of a set of
strings in memory. (Don't let that "array of pointers" thing get to you;
The last item in the array is a NULL string. This is similar to making the
last item in a list of integers zero; it marks the end of a long list. The
array isn't even defined with a number in the brackets. That way you can
A while loop ticks through each string in the list, displaying each string
and incrementing the index variable. Only when the NULL string is
And that, ladies and gentlemen, is exactly how you will fill the names in
If you dare to look at it, Lesson 10.10 covers the thorny ground of
arrays of pointers.
To create the linked list you need a loop, a loop with a single if test in
it to be sure you handle the first structure in the linked list properly.
similarly to the way the POTUS.C program displayed the presidents' names.
Name: PREZEZ3.C
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
void main()
struct pres {
char name[25];
};
char *presidents[] = {
"George Washington",
"John Adams",
"Thomas Jefferson",
"James Madison",
"James Monroe",
""
};
int index = 0;
current = first;
while(*presidents[index])
strcpy(current->name,presidents[index]);
current->next = new;
current = new;
index++;
*/
printf("first->name = %s\n",first->name);
Type in the above source code or Shift+click here to download a copy. The
the list:
I limited output because displaying the structures opens a whole new can
How it Works
Here are the details -- the blow-by-blow, though I lack rights to use that
icon here:
The program starts by creating the first structure in the linked list.
That address marks the start of the linked list, so the *first variable
must never change:
current = first;
After the *first variable is created, it's stored in the *current variable
for use inside the loop. At this point, the first structure can be filled
The guts of the program consists of a while loop, identical to the one in
POTUS.C:
while(*presidents[index])
The loop continues to spin as long as there are strings in the presidents
array. The index variable is incremented at the end of the loop to keep
index++;
Inside the loop, two things happen: The string is saved in the structure
strcpy(current->name,presidents[index]);
current->next = new;
This works the same as for the PREZEZ2.C program, however in this program
you've eliminated the extra pointer variables and replaced them with
*current and *new. The *current pointer references the current structure
and *new is used only to get the address of the next structure in the
list.
filled-in:
current = new;
This means that the next time the loop spins, it will be filling in the
next structure in the list. After that, the index variable is incremented
The PREZEZ3.C program isn't without its problems. Before that, note what
works:
The program creates a linked list, with each structure containing the
the rest of the program to locate that structure and then all the other
The program doesn't display all the items in the list. No biggie; the
next program in this Lesson shows you how. (I just didn't want the thing
The program works only in one fell swoop: it creates the linked list all
at once. If you wanted to write a program that added items to the linked
list one at a time, this code wouldn't cut it. (More on that in the next
lesson).
Okay. Minor gripes, but legit. The first item in the gripe list is most
important. How would you display all the items in the linked list? It's
Think about it! Go back and look at the source code. I'll wait here.
Do-be-do-be-do Dee-do-be-do-be . . .
Right. You need some kind of loop. A for loop would work, but you'd be
cheating; you already know how many linked lists there are so you could
current = first;
current = current->next;
Use the *current pointer to stomp through the linked list. Initialize it
to the start of the list, as shown above with current = first;. Then,
because you know there are only five structures in the list, re-use the
index variable in a for loop to march through the list only five times.
Inside the loop, use printf to display each structure's data. Then the
*current pointer is reset to the address of the next structure using the
current = current->next; statement. Nifty. Tidy. And it works.
You can Shift+click here to download the PREZEZ4.C program, which contains
the above for loop to display the structures. Go ahead, even though you
Compile the code and run the program. Output looks like this:
If you're from the school of "If it works, it's done," then you can stop
Right: it still needs a loop. But why not a while loop? After all, a while
loop was used to create the structures. Likewise, a while loop can be used
to display them. The drawback to that approach is that a while loop needs
is yet another problem with the PREZEZ.C series of programs: how can you
Now you could create a *last pointer. But that's overkill. (If you thought
of that, then you're using your brain too much. This is C programming, not
Pascal!) Think instead of how the first while loop works. How does it know
when to stop?
NULL...
Right. To end the linked list, you need a NULL pointer. The final
taught in Sunday School: The last structure in the list, logically, has
Here's another look at that linked list illustration to drive the point
home:
Look at the last structure in the list. What does it end with? 000? Isn't
Now two things must be done: The loop that creates the linked list must
cap it off with a NULL pointer in the last structure. After that, the loop
that displays the list uses the same NULL to determine when the list is
done. You could ruminate on this for a time if you like, or just peek
ahead to the following source code, the last of the PREZEZ.C series.
Name: PREZEZ5.C
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
void main()
struct pres {
char name[25];
};
char *presidents[] = {
"George Washington",
"John Adams",
"Thomas Jefferson",
"James Madison",
"James Monroe",
""
};
int index = 0;
current = first;
while(1)
strcpy(current->name,presidents[index]);
index++;
if(!*presidents[index])
break;
else
{
new = (struct pres *)malloc(sizeof(struct pres));
current->next = new;
current = new;
current = first;
index = 1;
while(current)
printf("%s\n",current->name);
current = current->next;
Compile and Run. The output will be the same as for PREZEZ4.C (above) but
because an if-else structure is used inside the loop to determine when the
last item from the array has been read. (There are other ways to do this
as well.)
Inside the loop, the structure is filled in two steps. First, the
president's name is fetched from the array and stuffed into the structure:
strcpy(current->name,presidents[index]);
This works the same for all the structures, whether they're the first,
middle or last.
index++;
You need to determine whether or not this is the last structure and the
if(!*presidents[index])
This is a peek ahead. The value of the string there isn't used now; it
will be used the next time the loop repeats (if it repeats). Otherwise, if
tests to see whether anything is there at all. If not (which is the ! part
of the test), then the next pointer in the structure is assigned a NULL
break;
saved, the current pointer is reset to that address so that the loop can
current = new;
To display the results a simpler construction can be used. After all, the
next pointer in each structure variable holds an address for every item in
the list but the last one. In that case, it holds the NULL value. And all
Before the loop starts, the current pointer is initialized to the address
of the first item in the list, and the index variable is set to one (for
counting purposes):
current = first;
index = 1;
After that, the loop can spin until the value of the next pointer is zero
while(current)
printf("%s\n",current->name);
current = current->next;
Only the name part of each structure is displayed with a printf. In fact,
Then, the current variable is set equal to the address of the next
structure in the linked list:
current = current->next;
When the last item in the list is encountered, the current variable will
be set equal to NULL. That's the condition the while loop interprets as
The program may not be utterly elegant, and it's certainly not the only
way to accomplish the task, but it works and is flexible: You can add
the rest of the presidents' names to the array and the sucker will still
The next lesson shows a different way to add and display elements in a
programs.
Bonus C For Dummies Lesson 17-3Lesson 17-3 – The Dawn of the Database
Linked lists are really all about databases. The structure itself is like
can't see how it could get any more obnoxiously obvious. And if that's all
true, then the linked list is really just another term for a database. So
starting with this Lesson and continuing for a few more Lessons, you're
It seems like the last few times I've gotten questions from readers about
linked lists it had to do with banking programs. You know the type: They
lose track of you and your money – unless you owe them money, in which
The following program is BANK1.C, which should tell you immediately that
it's only the first in what will probably be several more BANK programs.
This program creates a linked list one record at a time. Unlike the
previous linked list examples, this one take a giant step into the area of
databases.
Name: BANK1.C
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
void addNewAccount(void);
struct account {
int number;
char lastname[15];
char firstname[15];
float balance;
struct account *next;
};
int anum = 0;
void main()
char ch;
do
printf("\tYour choice:");
ch = toupper(getch());
switch(ch)
{
case 'A':
addNewAccount();
break;
case 'Q':
puts("Quit\n");
default:
break;
while(ch != 'Q');
void addNewAccount(void)
char buffer[64];
*/
if(first==(struct account *)NULL)
*/
else
current = current->next;
current = new; //and make the current record the new one
current->number = anum;
gets(current->lastname);
gets(current->firstname);
current->balance = atof(gets(buffer));
*/
Your choice:
There are only two options at this stage. Type A to add a new record.
Fill in the last name, first name and a bogus account value. After that,
function will be added in the second half of this lesson. Before then,
You can press A again to add another record. In, fact you can keep
The program already specifies the account number for you, starting with
structure and the three linked-list pointers: first, current and next.
Please review Lessons 17-1 and 17-2 on linked lists if the concept is
new to you.
general.
The key to the program is a small snippet of code that's used to find the
new structure (or actually perform just about any operation on the linked
list) you need to know which structure is the last. Here's the simple
current = current->next;
structure.
list. If that address is NULL, it means you've found the last structure in
current = current->next
adjusts the current pointer to contain the address of the next structure
This while loop elegantly stomps through every structure in the list.
After it's done, the value of the current pointer is the address of the
last structure in the list (the one with NULL as the value of
Working the whole BANK1.C program from the top down: The main function
merely displays a menu and calls other functions to do the actual work.
Nothing there should surprise you, other than the do-while loop instead of
a while(TRUE) loop (which I normally use). Again, this is just Yet Another
The addNewAccount function is where the fun starts. And the fun starts
Now, normally there should be some code there comparing new to NULL just
should never happen. (In a "real" program you must do that.) (I know I'm
bad for not checking. A later lesson actually does the checking. Promise!)
After creating the new structure, you need to check to see if it's the
All the structure pointers were initialized to NULL in the main function,
so if first is still a NULL pointer, then you're adding the first record
address of this, the first structure, is then stored in the first pointer
Otherwise, if there are already structures in the list, you need to spin
up to the last structure and add the new structure to the end. That
else
{
current = first; //make the first record the current one
current = current->next;
current = new; //and make the current record the new one
structure in the list. Then your friendly while loop is used to spin
through all the structures until the last one is found (the one with NULL
After the while loop spins, the record current points at is the last
record in the list. First, the current->new value is changed from NULL to
the address of the new structure. Then the new structure is made the
anum++;
current->number = anum;
The value of the global variable anum (account number) is incremented and
assigned to the new account. The extra spaces in the printf string line up
the colon with the next several prompts. And the %5i makes the integer
display to 5 digits.
The next few questions and answers are pretty easy to figure out
It's pointless to create data and shove it into memory without any chance
snap.
In fact, it's so easy, I would like you to try it on your own. So don't
peek ahead! Sit down and write a routine called listAll and stick it on
the end of your BANK1.C source code file. Then modify the main function so
that pressing the L key displays all the files in the list.
Do it now!
Compile? Run?
Did it work?
If not, keep in mind you can use the NULL byte at the end of the list as a
How about this. Run the program again, and press L to list all the records
before you entered any records.
Did it crash?
Okay. Give up? The following is my code for the listAll function. This
void listAll(void)
else
current=first;
do
current->number,\
current->lastname,\
current->firstname,\
current->balance);
First, an if test is done to ensure that there are records to list. If the
value of the first pointer is still NULL, then the linked list is empty.
The main bulk of the structure listing routine is a do-while loop. This is
one of the smoothest ways to do things without skipping over the first or
last item in the linked list. The loop is driven by the following:
the linked list. But the != stops it when the result of that operation is
the NULL pointer. This is one way to read in the last structure in the
last structure. When that happens, the do-while loop stops cold.
Inside the loop, a printf statement formats the output. This lines up
routine's output:
Don't worry about modifying your program to look like mine. Instead, just
Compile and run BANK2.C if you like. Compare it with your own source code.
Remember, it's not the best way to do things, just another way.
The next lesson continues this series with examples of deleting records
Bonus C For Dummies Lesson 17-4Lesson 17-4 – Decimating the Linked List
Most of us take the word "decimate" to mean "destroy," which is true but
not the original meaning of the word. When the Roman army decimated a foe,
they just killed every tenth guy. Ten = dec, which is where decimate came
from.
won't be destroying the list entirely. Instead, you'll just be killing off
If you have a database that's just a series of 3x5 cards, then removing
old entries is cinchy: pull out the dead card. No one would know!
Now suppose your database is a series of structures in an array. How can
you delete structure account[7]? If you just zero out the entries, then
you have a blank record in the database. No, you'd probably have to copy
all the structures account[8] and above down a notch. Yeah, that might
work . . .
But arrays are boring. The truth is pointers are much easier to work with.
The malloc function can really put the new structure it allocates anywhere
in memory. All you get back is the address in a pointer variable. Even so,
To delete a record, you merely remove its pointer: Take the pointer in the
The pointer in the second structure now points to the fourth structure.
The third structure is out of the list. (And, realistically, in memory the
Yes, it's true, the deleted structure is not removed from memory.
Well, you could use the free function to remove the structure from
merely "skipped over" on disk. This is how UNDELETE programs work; they
find the remains of the dead file and then put it back into the list.
The fact that pointers connect these structures will be used in a later
To delete a structure from the BANK.C program you need to know three
things:
So, basically, you take the address stored in the previous structure's
*next pointer and store the address of the next structure in there.
this works). Only one new variable is needed: a pointer to hold the
all:
void deleteAccount(void)
char ch;
else
current=first;
do
current->number,\
current->lastname,\
current->firstname,\
current->balance);
ch = toupper(getch());
if(ch=='Y')
puts("Yes!");
if(current==first)
first=current->next;
break;
else
{
previous->next = current->next;
break;
else
puts("No!");
previous=current;
Copy and paste the above code into your BANK2.C program. Remember to
prototype! Remember to add a Delete item to the menu! Save your source
BANK3.C
Enter about three or four different records, then try the new Delete
command. Delete a record in the middle, then list 'em all. Then try
deleting the first and last records to make sure that works.
So How Does It Work?
tricks. First, only two variables are required: ch to hold the Y or N key
the program.
The entire function works off of a do-while loop exactly the same as the
ch = toupper(getch());
If the user press Y, then another if-else structure is used to delete the
record.
First, a test is made to see if the current record is the first record:
if(current==first)
first=current->next;
break;
If the current record is the first record, then all you need to do is
change the value stored in the first pointer (the address of the first
structure in memory). Just change the value to the address of the next
structure in memory and you're done. The new starting address is stored in
If the current structure is not the first structure, then the following
else
previous->next = current->next;
break;
else
puts("No!");
previous=current;
If the user types N to not delete a record, then the address of the
current structure is stored in the previous variable. This works since the
only time that wouldn't happen is when the first record is deleted – and
If it's still fuzzy as to why this function works, review it again and
Remember that pointers are addresses. In this program, they hold the
each structure is what makes this a linked list – and what allows you to
stuff around.
Yes, technically you should use the free function to remove the
structure from memory. I will show you how that's done in a later
lesson. (It's okay at this point because the structures are small and
you're typing them all in; I don't expect you to type in more than 32K
of data, okay?)
I've been bad. Bad author! Bad! I've done a lot of explaining how malloc
works, here on the Web and in the Books, but I left out one little,
The need to free memory shall become painfully apparent to you as your
programs grow. All that mallocing stuff gobbles up tons of memory, never
giving it back. Especially for the tiny programs you write in these
lessons, 64K of memory is about all you have. Lose it and it's gone.
Now, I haven't been totally bad; for example, the BANK.C programs you've
been working with use manual entry. You must type in all the data from the
keyboard. So the odds are pretty long that you'll never chew up all memory
by typing something in. But if you're reading data from disk (which is the
The following program uses malloc to assign 32K chunks of data. Now malloc
example, the address isn't saved. I'm just trying to prove a point:
Name: GOBBLE.C
#include <stdio.h>
#include <stdlib.h>
void main()
int x;
for(x=0;x<10000;x++)
exit(0);
Be a masochist and type the above source code into your editor, saving it
Allocating block 0
Allocating block 1
If you're lucky, you may get more output than what I got above. But
eventually, at some point in the run, the program stops because there is
The program uses the (char *) prototype to allocate 32,676 bytes (32K)
of memory.
Malloc returns the address of the memory block allocated. That value
The actual number of 32K chunks the program allocates depends upon which
memory module your compiler is using. For DOS programs, that's typically
the "small" or "tiny" module, which gives the program only 64K of
"outrageous" module to see how much memory gets allocated before it's
all gone.
It's frustrating to have a PC with megabytes of RAM, yet you can write a
silly little program that supposedly gobbles up all memory in only two 32K
chunks. Now you're actually facing a conundrum many PC users have: "My
computer has megabytes of RAM, how come I'm running out of memory?
The truth is, memory must be allocated, used and then freed for use by
something else. It's only fair. But DOS (and Windows to some extent)
doesn't really, truly manage memory in a PC. For example, Microsoft Word
when it ran. If you ever worked with Word for a long period of time,
eventually you would get the cheery error message "Not enough memory to
save document." (That was just bad programming; Word's programmers were
hogging up resources and not returning them when they were done.)
To make life better for yourself and your users, it's always nice to free
up memory after you've used it. Say, for example, you write a program that
reads a file from disk, gathers information, changes settings, and then
closes the file. It's just plain nice to free up the space used by the
buffer. And to do that, you use the free function. ( Click here for a
definition.)
And any time you allocate memory that's not used again in a program, you
should employ the free function to clear up that memory. The following
Name: CHEW.C
#include <stdio.h>
#include <stdlib.h>
void main()
int x;
char *buffer;
for(x=0;x<10000;x++)
{
puts("Unable to allocate memory!");
exit(0);
free((void *)buffer);
You'll notice that the program runs all the way through, allocating memory
You don't really have to use free every time you use malloc. However,
any time you allocate memory that isn't used again, you should free it
up.
information that's used the entire time the program runs. In that case,
the memory is freed by the operating system when the program quits.
The next lesson, when it's published here on the Web, deals with
Bonus C For Dummies Lesson 18-1Lesson 18-1 – Setting the Right Mode
Nothing puts the twinkle in a programmer's eye like graphics programming.
There's something about it that just seems naturally fun. And there's
nothing wrong with that. Graphics are fun. But unlike a lot of other
Oh no! Math!
Relax. Always remember that the computer does the math. Still, it's up to
you to know the equations. If you've been through Algebra in high school
you may know some of them. Here are two popular equations you might
The first is the equation for a line: Y and X are coordinates you'd plot
on a graph (or on the screen). M is the slope of the line, up or down, and
The second equation is for plotting a circle, with X squared and Y squared
the coordinates and R (also squared) being the circle's radius. Simple.
Simple. Simple. (And I bet if you knew you'd be plotting graphics on a PCs
As long as you can work with those boogers in C, tie them into a loop, and
translate the results to the giant pixel grid on your computer's monitor,
you should be in great shape! (Or great shapes, depending on what your
program draws.)
A Quick [Boring] PC Graphics History Lesson
computing. Oh, well, maybe the Apple II had a worse system (and God bless
the few who really understood it). The Mac is far better. Best? The Amiga.
But that's trivia. What's important to know is that the PC has several
MDA. Originally, the PC came with the Monochrome Misplay Adapter (MDA)
text on a black background or amber text. (I liked the amber text myself.
In fact, my friend Tom still has my old amber monitor.) Color? Nope.
CGA. If you wanted color, you waited a few months until IBM released the
Graphics? Yes. There were two graphics modes in the CGA: The low
resolution 320 x 200 mode with four colors (black, white, magenta and
cyan) or a high resolution 640 x 200 with only two colors, black and
you get. The lower the resolution, the more colors. It's a nice
trade-off since you can use more colors to fool the eye into thinking it
Let me be blunt: CGA sucked. The text was horrid. That was one reason I
used monochrome for years before switching to VGA in 1988. But I didn't
monographics. The Hercules card was a clone of the old MDA, but it also
had a special graphics mode. Sure, the graphics were black-and-white, but
they looked fabulous and the text was much better than CGA. I even had a
few games that used Hercules graphics modes. And my Hercules card even
displayed italics and underlined fonts in the old DOS WordPefect. (Man, I
EGA. To improve upon CGA, IBM created the EGA (Enhanced Graphics Adapter)
standard. EGA offered better-looking text over CGA plus a few new graphics
VGA. EGA was quickly replaced by the VGA standard, which IBM introduced in
1987 with its PS/2 computers. Actually, there were two VGA standards. The
first was MCGA, which came with IBM's PS/1 (the "home" computer). MCGA,
SVGA. Eventually, the "industry" improved upon VGA and produced Super VGA
or SVGA, the graphics standard nearly all PCs have been sold with since
Because you must set your PC to the proper graphics mode before you can
program in graphics. Your programs do this for you automatically. When you
(resolution and colors) proper for the game. When you program in graphics,
then press Alt+Enter so that it fills the screen -- just like the good
old days!
MODE 40
Press Enter. Welcome to 40-column mode! This is an old CGA graphics mode,
designed primarily so that people could use their PCs with a TV set as a
monitor. (I wonder if anyone ever did?) In fact, the DIR command was
formatted for 40-column output primarily for this reason. (They changed
If you're using an SVGA video system, then your computer has 15 different
modes you can use to display text or graphics. You pick the resolution and
the number of colors and go from there. The following table lists the
graphics modes you have to choose from. (If you don't see a mode listed in
the table, then the SVGA adapter cannot produce it; these are typically
MDA, PCjr and EGA graphics modes on one uses anymore anyway anyhow.)
ModeTypeResolutionColors
0x00Text40 x 2516
0x01Text40 x 2516
0x02Text80 x 2516
0x03Text80 x 2516
0x04Graphics
0x05Graphics320 x 2004
0x06Graphics640 x 2002
0x07Graphics720 x 350
720 x 400*2
0x0dGraphics320 x 20016
0x0eGraphics640 x 20016
0x0fGraphics640 x 3502
0x11Graphics640 x 4802
0x12Graphics640 x 48016
0x13Graphics320 x 200256
** Only EGA adapters with 64K of video RAM display 4 colors in mode 0x10.
My favorite mode is 0x13, which is an old MCGA mode available on all VGA
adapters. It uses a rather low resolution, 320 x 200 pixels, but has a ton
of colors: 256.
More modes are available than those shown above. The table lists only the
standard VGA modes. I know that Super VGA has even more colors and
VGA graphics.
Wow! This chapter has way too much text. But the point's been made: Before
you do doodle with graphics, you must first set the graphics mode.
Actually, you should do several things: You should discover what graphics
mode the PC is currently in, save it, set the mode to what you want, then
reset the mode back to what it was when you're done. That's a lot of work,
all other C language compilers probably don't. Because of that, I'm going
to use in-line Assembly language to run the graphics basics for this
To set the mode you use the PC's Video Interrupt, 0x10, to call the BIOS.
through 255, which you would pluck from the table shown earlier in this
Lesson. That mode is saved into the AL register, the value zero put into
the AH register and the function sped off to Interrupt 10h (which is
you may leave your user in some low-rez dorky mode and they won't have a
clue as to how to get back to normal. (The MODE 80 command does the trick
{
unsigned char mode;
return(mode);
The value mode is returned from Interrupt 0x10 in the AL register. That's
saved into the mode variable and returned from the get_mode function.
Name: GRAFMODE.C
#include <stdio.h>
save = get_mode();
getchar();
set_mode(LOWGRAF);
getchar();
set_mode(HIGRAF);
getchar();
//Low rez MCGA colorful mode
set_mode(VGA256);
getchar();
set_mode(save);
return(mode);
copy.
Compile!
Run the program in a DOS window (if you're using Windows). And switch the
Press Enter.
Finally you have the high color VGA image. That's the one you'll be
working with in this Lesson. Press Enter and your system will be restored
much so. You can mix graphics and text any time. The cursor moves the
Feel free to modify the program to display other modes shown in the
Table.
To see if the program really does save the graphics mode, type MODE 40
before you run it. If the program restores the 40-column mode when it's
If you're using DJGPP, then you'll need to use the ATT nottaion, not the
(If you have Microsoft Visual C++, click the icon below.)
The graphics screen is a big grid. Well, the text screen is a big grid,
too. So if you've been plotting out text on the screen using rows and
columns, you should get used to plotting graphics on its grid in no time.
But with graphics, you're not plotting characters, you're plotting pixels.
All graphics, no matter how complex they look or what they do, are merely
you start by plotting pixels on a grid. And since you're programming, you
can afford to have the computer do all the plotting work for you.
Other routines, for drawing lines and circles and such, are all
and color. (Again, this is like text, where each character has a row and
pixel grid starts in the upper left corner of the screen at position 0,0.
This is the same for all graphics resolutions. The maximum values for X
and Y differ from graphics mode to graphics mode. In the high color VGA
mode 0x13, the maximum X value is 320 and the maximum Y value is 200.
(Incidentally, that's the size of the graphic image shown above: 320 x 200
pixels.)
In addition to the X and Y locations, pixels also have a color value. Like
the resolution, this value depends on the graphics mode. Color values
range from 2 (on and off, or "black" and "white") on up to 256. The colors
That's the basics of all graphics. No matter what you see on the screen,
X locations go from zero upward as you move from left to right across
Y locations go from zero upward as you move from the top down on your
screen. This is different from the graph paper you used in school (where
Plotting Pixels
Before you can do any graphics on any computer, you must have a function
that plots a single pixel on the screen. The good news is that it's simple
to do. The bad news is that there are dozens of ways to do it.
directly to video memory. Yikes! You can also plot pixels by manipulating
the graphics hardware inside your computer. I have technical books full of
VGA and SVGA documentation that tell über nerds how to manipulate the
Some folks opt to get graphics libraries for their programming whims. For
For this chapter, I'm going to show you the tried and true method for
plotting pixels: using the PC's BIOS with in-line Assembly. This isn't the
fastest way to do things (people into computer graphics are into speed),
color. These values are stuffed into the proper microprocessor registers
0x0C, which writes a pixel to the screen, and Video Interrupt 0x10 is
called.
Note that the pset function doesn't check to see if value numbers are
used. That's good in a way, since the BIOS function writes pixels in any
mode; the maximum value for X could be anything from 320 to 400 to 640 to
1024 or more. Of course, the pixel appears only in the proper graphics
mode.
I'll get into color values in a few pages, but generally speaking, zero is
always black (or turning a pixel off). Values from 1 on up could be any
color, though.
Name: PIXELS1.C
#include <stdio.h>
void main()
int x,y;
/* Initialze things */
set_mode(VGA256);
/* Main routine */
x=XMAX/2;
y=YMAX/2;
c=1;
pset(x,y,c);
getchar();
return(mode);
}
void set_mode(unsigned char mode)
Type in the above source code or, better still, Shift+click here to
download a copy.
Compile! Run! The screen goes graphical and you should see a single, blue
pixel -- one dot -- in the middle of the screen. That's one tiny building
block with which you can do anything you can visualize on your PC's
graphics screen.
As you know, I'm a big fan of defines. In the PIXELS1.C program there
are three of them: VGA256, XMAX and YMAX. VGA256 is the graphics mode
and XMAX and YMAX represent the maximum horizontal and vertical
Using the XMAX and Y MAX values in the program is a lot easier than
having to remember the values every time you write a graphics equation.
resolution, then you can always use XMAX or XMAX/2 to represent the far
left or center of the screen -- no matter which graphics mode you're in.
Refer to the Table in Lesson 18-1 for more information on graphics modes
and resolutions.
More Dots
The following program uses a nested for loop to paint the entire low rez
VGA screen with all 256 possible color combinations. Dazzle your friends!
Name: PIXELS2.C
#include <stdio.h>
void main()
int x,y;
/* Initialze things */
set_mode(VGA256);
/* Main routine */
for(c=0;c<MAXCOLORS;c++)
for(y=0;y<YMAX;y++)
for(x=0;x<XMAX;x++)
pset(x,y,c);
getchar();
}
void pset(int x,int y,unsigned char color)
return(mode);
Compile! Run!
The nested for loops paint the entire screen, top to bottom. If you have a
slower PC, you may actually see the pixels fill the screen. (Yes, this
isn't the most efficient method for white washing a computer screen.)
Press ENTER to view the next color screen. Here's how the colors map out:
Black, Blue, Green, Cyan, Red, Magenta, Brown, Gray, Dark Gray, Bright
Blue, Bright Green, Bright Cyan, Bright Red, Bright Magenta, Yellow,
Bright White. (Incidentally, these are the same codes and colors for
16 to 31 - Grayscale
Shades of Blue, Red and Green in high, moderate and low saturation.
Shades of Blue, Red and Green in high, moderate and low saturation.
Shades of Blue, Red and Green in high, moderate and low saturation.
248 to 255 - Black
Black, black, black, black, black, black, black and black again.
Now you don't have to press the ENTER key 255 times to get the whole idea.
If you tire of it, press Ctrl+C to get out of the loop. You'll then have
to type MODE 80 to return to the normal text screen, or just keep working
Actually, if you're interested in viewing the VGA colors, you can refer to
Now you can get really silly with pixels. Don't worry about stringing them
into lines and circles yet. Instead, take that old chestnut the random
start field program out of the closet. This program combines the
this Lesson. The results are predictable, but fun to watch nonetheless.
Name: PIXELS3.C
#include <stdio.h>
#include <stdlib.h>
void seedrnd(void);
void main()
int loop,x,y;
/* Initialze things */
set_mode(VGA256);
/* Main routine */
x=rnd(XMAX);
y=rnd(YMAX);
c=rnd(MAXCOLORS);
pset(x,y,c);
for(delay=0;delay<50000;delay++);
getchar();
}
unsigned char get_mode(void)
return(mode);
int r;
r=rand()%range; //spit up random num.
return(r);
void seedrnd(void)
Type the above source code into your editor, or Shift+Click here to
Compile! Run!
Problem: the program loops only 1000 times. Can you imagine a better way
to halt it on your own? Something that would cause the stars to twinkle
until you pressed a key on the keyboard, say? I'll leave it to you to
You can adjust the value of the delay for loop to make the stars twinkle
Wow! Does this program remind you of the DIBBLE.C program from the end
from the end of Volume I into a program that displays pixels on the
screen. You'll need to adjust the maximum X and Y values, plus change
overwrite the drunk with color 0 (zero), which is black. See what you
that thing you wait in while you're at Disneyland. And not just
Studios, Los Angeles to go on the Jurassic Park ride. The line was 3½
hours long. That line, too, was connecting two points: the point where my
son was and the point where people were boarding the 10-minute long ride.
Too much.
Back in geometry class, you drew line by first defining the two points on
graph paper. You drew a dot at the first location and a dot at the second
location. Then you used a ruler to connect the two dots. Amazing. On a
computer screen, which works like graph paper, you take the starting
location of the line and the ending location and then pray that there is
some simple line-drawing algorithm you can use like a ruler to connect
them. That's the gist of it. And don't worry -- this is still C for
Dummies. There won't be any math here.
Yes, I have the line drawing algorithm all worked out. It's explained in
The line requires two locations on the computer screen. I'll refer to
the starting location as X1, Y1 and the ending location as X2, Y2.
Sunday in July, the last day of a promotional special. The park was
jammed. The line was 5 hours long to get into the Backdraft exhibit.
All lines are drawn using the simple line drawing formula you probably
You don't have to read this explanation: Y and X are the vertical and
horizontal coordinates of the line; for every Y position on the line there
the C compiler can understand. After doing that, you work it out so that
the function can also plot pixels for all the X and Y coordinates of the
line. So, using the vast skills you honed after years of schooling, you
The simplest type on line to draw is the straight line. For a horizontal
line, you would plot pixels from X1 to X2 with the same value of Y – a
simple for loop. For a vertical line, you plot pixels from Y1 to Y2 with
the same value of X – another simple for loop. However, a vertical line
must be treated as a special case, one that cannot follow the y=mx+b
Name: VERTLINE.C
#include <stdio.h>
#define RED 4
void main()
int x1,y1,x2,y2;
/* Initialze things */
set_mode(VGA256);
/* Main routine */
printf("Coordinates [x1,y1,x2,y2]:");
scanf("%i,%i,%i,%i",&x1,&y1,&x2,&y2);
printf("(%i,%i) to (%i,%i)",x1,y1,x2,y2);
getchar();
line(x1,y1,x2,y2,RED);
getchar();
int x,y;
for(y=y1;y<=y2;y++)
pset(x1,y,color);
return(mode);
This program uses the pset function from Lesson 18-2 to help you plot the
line. In addition to the line drawing function, I added code that lets you
input the starting and ending coordinates for the line. Now don't get
cocky with your values! It's easy to crash this program by typing in
your own.)
Type in the above source code or, if you're not a masochist, Shift+click
Compile! Run!
Type in the four sets of coordinates, separating each by commas. Oh, heck,
160,0,160,200
That's 160 for both values of X, which puts the line in the center of the
screen. Y1 is equal to 0 (at the top of the screen) and Y2 is equal to 200
(bottom). Press Enter to see the results. Press Enter again to quit.
Now. The program can draw any vertical line on the screen. It ignores the
X2 coordinate (which your compiler may alert you to when you created it),
but uses the two Y coordinates to draw the line. Alas, this isn't without
its problems.
Run the program again. This time type in the following for the
coordinates:
160,200,160,0
This is essentially the same thing, but with the coordinate sets reversed.
But will the program draw the line up? Press Enter to find out.
Nope. And it shouldn't surprise you. Review your program's for loop:
for(y=y1;y<=y2;y++)
The loop never works, not once. If Y1 is greater than Y2, then the for
loop quits before it loops even once. And it should because that's the way
the C language works. But, obviously, that's not going to fit into the
grand scheme of things when you draw a line. Obviously there will be times
when Y1 is greater than Y2 and your program will still need to draw the
line.
The solution? Reverse the coordinates. Swap them. Add the following
int temp;
temp = *a;
*a = *b;
*b = temp;
Defining the variables as pointers here allows you to swap their values
without having to swap names. (It also allows the function to be used
lesson.)
And finally, you'll need to modify the line function to take care of the
case when Y2 is larger than X2. Here's how that function looks:
int x,y;
if(y1 > y2)
swap(&y1,&y2);
for(y=y1;y<=y2;y++)
pset(x1,y,color);
If so, the values are swapped. (Refer to Chapter 10 in Volume II for more
160,200,160,0
The value of X is merely determines where the vertical line will slice the
There are actually many line drawing algorithms, but y=mx+b is the most
common. The puzzlement is how to shift the values of X1,Y1 and X2,Y2 into
that equation. The core code you can probably figure out yourself:
for(x=x1;x<=x2;x++)
{
y = m*x+b;
pset(x,y,color);
A for loop whizzes the value X from X1 to X2. Then the value for Y is
calculated using y=mx+b. Finally, the pset function is used to plot the
M is the slope of the line, or the ratio of the change in Y over the
From your basic C knowledge, you should remember that anytime you use
division, you'll be dealing with a floating point number. So right off the
bat, you should know that M is a floating point variable. And you,
therefore, must typecast the results of the Y over X thing. But don't
m = (float)(y2-y1)/(float)(x2-x1);
b = y1 - (m*x1);
the new line function as floating point numbers. In fact, here is the
entire new line function for you:
int x,y;
float m,b;
if (x2==x1)
swap(&y1,&y2);
for(y=y1;y<=y2;y++)
pset(x1,y,color);
return;
m = (float)(y2-y1)/(float)(x2-x1);
b = y1 - (m*x1);
for(x=x1;x<=x2;x++)
{
y = m*x+b;
pset(x,y,color);
Above, you'll note that the new floating point M and B variables are
defined. Then comes the code for plotting a straight vertical line. That's
determined by matching the values of X1 and X2. If they're equal, then you
have a vertical line. The rest of the code between the if statements'
Next comes the new stuff. First the value of M is calculated, then the
value of B. Then a for loop steps through the points in the line using the
old y=mx+b chestnut. pset slaps down all the pixels in the proper spot.
Make the appropriate changes in your VERTLINE.C source code, adding in the
new stuff for the line function as shown above. Save your new creation to
LINE1.C.
0,0,320,200
Press Enter. Thwoop! A nice red line from the upper left corner down to
160,200,0,0
That's a line from the bottom center of the screen up and back to the
Or not, as the case may be. You see, it's the for loop again. It expects
the values of X to crawl ahead from little to big. When you try to draw a
line in the other direction, the loop never loops. This isn't a major
coordinates are "backwards" and then re-reverse them using the swap
function.
The following, final rendition of the line program, LINE.C, does the job
Name: LINE.C
#include <stdio.h>
#define RED 4
void pset(int x,int y,unsigned char color);
void main()
int x1,y1,x2,y2;
/* Initialze things */
set_mode(VGA256);
/* Main routine */
printf("Coordinates [x1,y1,x2,y2]:");
scanf("%i,%i,%i,%i",&x1,&y1,&x2,&y2);
printf("(%i,%i) to (%i,%i)",x1,y1,x2,y2);
getchar();
line(x1,y1,x2,y2,RED);
getchar();
int x,y;
float m,b;
if (x2==x1)
swap(&y1,&y2);
for(y=y1;y<=y2;y++)
pset(x1,y,color);
return;
swap(&x1,&x2);
swap(&y1,&y2);
m = (float)(y2-y1)/(float)(x2-x1);
b = y1 - (m*x1);
for(x=x1;x<=x2;x++)
y = m*x+b;
pset(x,y,color);
int temp;
temp = *a;
*a = *b;
*b = temp;
return(mode);
}}
Shift+click here to download a final copy for your files. Then compile and
run. The program draws lines between any two points on the screen. No
problem.
The new chunk of code in the line function merely checks to see if X1 is
greater than X2. If so, then both coordinates are swapped, X1,Y2 and
X2,Y2. After all, it doesn't matter which direction the line goes, merely
that it connects those two points. Again, the handy swap function is used
The next lesson continues your graphics studies with some polygons drawn
On your own, you should try to devise a program that draws lines between
random coordinates using random colors.
Another program to consider: a line that bounces around the screen (like
own. Shift+click here to see a copy, but don't cheat! Come up with your
own first before you compare it to mine. (And remember that there are