Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Advanced C 1992

.pdf
Скачиваний:
96
Добавлен:
17.08.2013
Размер:
4.28 Mб
Скачать

Part II • Managing Data in C

Listing 9.4. continued

fprintf(stdprn,

“Line %2d of 50 lines”

“ being written to stdprn by a program.\n\r”, i);

}

/* An explicit form feed is used to force a page eject * if the printer is a laser printer

*/

fprintf(stdprn, “\f”);

return (0);

}

This program shows how easy it is to use a printer from a C program. Listing 9.5 is a more flexible program—the user can choose the screen, the communications port, or the printer.

Listing 9.5. STDFILE.C.

/* STDFILE, written 1992 by Peter D. Hipson

*This program prints to the selected destination. It

*should be run under DOS on a PC.

*/

 

 

#include

<stdio.h>

// Make includes first part of file

#include

<string.h>

// For string functions.

#include

<stdlib.h>

// Standard include items.

#include

<process.h> // For exit(), etc.

int main(

 

// Define main() and the fact that this program

int

argc,

// uses the passed parameters

char

*argv[],

 

char

*envp[]

 

);

 

 

276

Disk Files and Other I/O

int main(

 

int

argc,

char

*argv[],

char

*envp[]

)

 

{

 

FILE * OutputFile = NULL;

int

nFile = 0;

int

i;

while (nFile < 1 || nFile > 3)

{

printf(

“Which file to write to:\n”

1 - stdprn (the printer)\n”

2 - stdaux (the communications port)\n”

3 - stdout (the console)\n”

enter 1, 2 or 3: “);

scanf(“%d”, &nFile);

}

switch(nFile)

{

case 1:

OutputFile = stdprn; break;

case 2:

OutputFile = stdaux; break;

case 3:

OutputFile = stdout; break;

}

C C C

C9C C

C C C

continues

277

Part II • Managing Data in C

Listing 9.5. continued

 

for (i = 0; i < 50; i++)

 

 

{

 

/*

stdprn is opened in the

binary mode, so a CR/LF

*

must be supplied explicitly, using \n\r

*/

 

 

 

fprintf(OutputFile,

 

 

“Line %2d of 50

lines”

 

“ being written

to user-selected destination by a program.\n\r”,

 

i);

 

 

}

 

/*

Use an explicit form feed to force a page eject if the

* printer is a laser printer. */

fprintf(OutputFile, “\f”);

return (0);

}

This program shows the effect of assigning standard file handles to a userspecified file. This technique enables you to have one output routine and several destinations. This is useful when you want the user to be able to preview a report or easily select a secondary printer connected to a communications port.

Low-Level I/O and File Handles

All file I/O functions described so far perform primarily high-level I/O, and all require stream files. (Functions that require stream files receive a FILE * structure pointer.)

You can also access a file more directly using low-level file I/O techniques. Before describing the details of these techniques, however, several important issues should be covered.

A file that has been opened as a stream file can be read and written to using lowlevel file I/O functions. To get the necessary integer file handle, you must use the fileno() function.

278

Disk Files and Other I/O

C C C

 

C9C

 

C C C

 

C

A low-level file can be used with stream functions by opening it with the fdopen() function. Be careful not to take a file that has been opened as a stream file, get its file handle, then open it a second time with fdopen(). You would then have to close the file twice.

The low-level file I/O functions are shown in Table 9.2. These functions generally have a stream file function counterpart.

Table 9.2. Low-level file functions.

Function Description

close()

creat()

dup()

dup2()

Closes the specified file.

Creates a new file.

Creates a new, duplicate file handle.

Creates a new, duplicate file handle and sets the second (specified) file handle to the first file.

eof()

lseek()

open()

read()

sopen()

tell()

write()

Tests for an end-of-file.

Seeks (changes the read/write pointer) to a new place in the file.

Opens an existing file.

Reads an opened file.

Opens a file in shared mode.

Returns the value of the read/write pointer.

Writes data to a file that has been opened for output.

Before you use stream functions with a low-level file, be sure that you open the file using the correct stream function. Generally, it is best if you use one type of function with any specific file.

There are several reasons for using low-level functions, including the following:

Low-level functions do not try to format data, read from a file, or write to a file.

Low-level file I/O is not buffered. When an I/O statement is executed, what is written goes directly to the file. (This may slow the program’s execution.)

279

Part II • Managing Data in C

Most programs benefit from the use of stream functions. The capability to open, read, and write any data object is present in both low-level files and stream files. The problems caused by buffering, if important, can be circumvented using the file flushing routines.

Standard Low-Level File Handles

Because stdin, stdout, stdaux, stderr, and stdprn are stream files, they can be referenced using the fileno() function. These files can also be used with low-level I/O functions directly, however. The file handle numbers for the standard stream files follows:

stdin

stdout

stderr

stdaux

stdprn

0

1

2

3

4

These low-level file numbers should not be used if possible. The fileno() function is more portable, especially when a program must run on different systems.

Console and Port I/O

Much of the direct access to the computer’s terminal (the screen and keyboard) is system dependent. On a PC, you can have any of a number of keyboards, all of which have different keys, and different scan codes. Several functions interact more directly with the keyboard, and though not all are ANSI standard, they are often part of many C compilers. These functions are shown in Table 9.3.

You can easily simulate most console functions by using the stream functions and the predefined file handles. A few functions, however, have no equal. This section describes the console functions and how to use them.

Some of the most frequently used direct console functions are the character getting functions, getch() and getche(). The main difference between these two functions is that getch() does not echo the character pressed, and getche() does echo

280

Disk Files and Other I/O

C C C

 

C9C

 

C C C

 

C

the character. Although the screen functions can be used to read a keypress and echo it to the screen, you must use the getch() function to read a keypress without echoing it to the screen.

Table 9.3. Console I/O functions.

Console function

Description

cgets()

cprintf()

cputs()

cscanf()

Gets a string from the console.

Performs a formatted print to the console.

Writes a string to the screen.

Performs a formatted read from the console (keyboard).

getch()

Gets a character from the keyboard but does not echo

 

the character to the screen.

getche()

Gets a character from the keyboard and echoes the

 

character to the screen.

kbhit()

Returns immediately with the return code indicating

 

whether a key has been pressed. Will not wait for a

 

keypress.

putch()

ungetch()

Writes a character to the screen.

Allows one character to be pushed back to the keyboard. The character put back does not need to be the last character read. Only one character may be put back.

The next most commonly used function is the kbhit() function, which has no stream function counterpart. The kbhit() function enables you to poll the keyboard for a keypress. Many business applications have little use for this function. Games, however, run in real time, so they must check for user input without stopping the action. The kbhit() function enables a program to do just that.

Listing 9.6, ARCADE.C, does processing while waiting for keyboard input from the user. By a far stretch of the imagination, you could consider this program a simple arcade game.

281

Part II • Managing Data in C

Listing 9.6. ARCADE.C.

/* ARCADE, written 1992 by Peter D. Hipson

*This is a simple arcade game that uses console I/O.

*It should be run under DOS on a PC. It also should

*be compiled with Microsoft C or a compiler that

*supports kbhit() and getch(). In addition, ANSI.SYS

*should be loaded before using this program, and the

*screen size is assumed to be 25 by 80.

*/

 

 

#include <stdio.h>

// Make includes first part of file

#include <conio.h>

// Console I/O functions

#include <string.h>

// For string functions

#include <stdlib.h>

// Standard include items

#include <process.h>

// For exit(), etc.

#include <time.h>

// To seed random numbers

/* ANSI.SYS screen control #defines follow: */

#define BOLD

“\x1B[1m”

#define NORMAL

“\x1B[0m”

#define RED

“\x1B[31m”

#define BLACK

“\x1B[30m”

#define GREEN

“\x1B[32m”

#define CLEAR_SCREEN

“\x1B[2J”

#define CLEAR_EOL

“\x1B[K”

#define MOVE_CURSOR

“\x1B[%d;%df”

#define UP

‘\x48’

#define DOWN

‘\x50’

#define LEFT

‘\x4B’

#define RIGHT

‘\x4D’

#define MAX_HEIGHT 25 #define MAX_WIDTH 80

#define HALF_SECOND (CLOCKS_PER_SEC / 2)

282

 

Disk Files and Other I/O

int main(

// Define main() and the fact that this

int

argc, // program uses the passed parameters

char

*argv[],

char

*envp[]

);

 

int main(

 

int

argc,

char

*argv[],

char

*envp[]

)

 

{

 

char chChar;

clock_t ClockTime; clock_t OldClockTime;

int

i;

 

 

int

nHorizontal

= 0;

/* Randomize for real game */

int

nVertical

= 0;

/* Randomize for real game */

int

nMoneyHorizontal

= 10; /* Randomize for real game */

int

nMoneyVertical

= 10; /* Randomize for real game */

int

nPosition;

 

 

OldClockTime = clock() / HALF_SECOND;

srand((unsigned)time(NULL));

printf(CLEAR_SCREEN);

printf(MOVE_CURSOR, nMoneyVertical, nMoneyHorizontal);

printf(“$”);

printf(MOVE_CURSOR, nVertical, nHorizontal);

printf(“?”);

C C C

C9C C

C C C

continues

283

Part II • Managing Data in C

Listing 9.6. continued

while(1)

{

if (kbhit())

{/* A key has been pressed, so process it as necessary */ chChar = getch();

if (chChar == (char)NULL)

{

chChar = getch();

printf(MOVE_CURSOR, nVertical, nHorizontal);

printf(“ “);

switch(chChar)

{

case DOWN:

if (++nVertical > MAX_HEIGHT)

{

--nVertical;

}

break; case UP:

if (--nVertical < 1)

{

++nVertical;

}

break; case RIGHT:

if (++nHorizontal > MAX_WIDTH)

{

--nHorizontal;

}

break; case LEFT:

if (--nHorizontal < 1)

{

++nHorizontal;

}

break;

284

Disk Files and Other I/O

default:

break;

}

printf(MOVE_CURSOR, nVertical, nHorizontal);

if (nMoneyHorizontal == nHorizontal && nMoneyVertical == nVertical)

{

printf(“\a”);

}

C C C

C9C C

C C C

printf(“?”);

}

else

{

if (chChar == ‘\x1b’)

{/* Exit on Esc keypress */ printf(CLEAR_SCREEN); exit(4);

}

}

}

else

{/* No key has been pressed. Move the money. */ ClockTime = clock() / HALF_SECOND;

if (ClockTime != OldClockTime)

{

OldClockTime = ClockTime;

printf(MOVE_CURSOR, nMoneyVertical, nMoneyHorizontal);

printf(“ “); /* Erase the money */

i = rand();

switch(i % 4) /* Allow four states */

{

case 0:

if (++nMoneyVertical > MAX_HEIGHT)

continues

285