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

Advanced C 1992

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

Data Types, Constants, Variables, and Arrays

C C C

 

C2C

 

C C C

 

C

Let’s look at an example of a program called REPEAT.C that reads in strings, places them in an array, and prints them to a terminal. This program, shown in Listing 2.10, forms the basis for the sort program you write in a later chapter.

Listing 2.10. REPEAT.C.

/* REPEAT, written 19 May 1992 by Peter D. Hipson */

/* Prints, in the same order, the strings that are entered. */

/* On PCs with memory models, you can compile with LARGE model */

#include <stdio.h> // Make includes first part of file #include <string.h> // For string functions

int main(void); // Define main() and the fact that this program doesn’t // use any passed parameters.

#define MAX_CHARACTERS

32767

/* Total maximum characters */

#define MAX_LINES

1000

/*

Total maximum lines */

#define BIGEST_LINE

128

/*

The longest line readable from keyboard

*/

 

 

 

/* Although these variables are defined as external, they can

*be defined inside the function or be allocated dynamically,

*depending on the program’s needs and memory available.

*/

 

char

szInput[BIGEST_LINE];

char

szBuffer[MAX_CHARACTERS];

char

*pBuffer[MAX_LINES];

int

nBufferPointer = {0};

int

nLine = 0;

int main()

{

int i;

continues

59

Part I • Honing Your C Skills

Listing 2.10. continued

printf(

“Enter lines, when last one is entered\n”

“provide a End-Of-File (ctrl-Z on most systems)\n” “to print the entered text\n\n”);

while (gets(szInput))

{

if ((nBufferPointer + strlen(szInput)) > MAX_CHARACTERS) { // The line won’t fit! End input loop.

break;

}

pBuffer[nLine] = &szBuffer[nBufferPointer];

//The strcpy() could have been written as:

//strcpy(&szBuffer[nBufferPointer], szInput);

strcpy(pBuffer[nLine], szInput);

//the + 1 skips over the terminating NULL in each string. nBufferPointer += strlen(szInput) + 1;

if (++nLine >= MAX_LINES)

{ // Too many lines! End input loop. break;

}

}

//

// Later, you add a sort to provide sorted output.

//

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

{

printf(“String %d ‘%s’\n”, i, pBuffer[i]);

}

printf(“\n”);

return (0);

}

60

Data Types, Constants, Variables, and Arrays

C C C

 

C2C

 

C C C

 

C

This program allocates space for as much as 32,767 bytes of strings, and a maximum of 1,000 strings. These limits may not be reasonable for a program that will be used. Also, when either limit is exceeded, REPEAT.C simply assumes that the end of the input file has been reached. In reality, a (meaningful) message to the user is in order.

Following the #define statements that define your limiting parameters, you allocate storage for the necessary variables. As the comments in the C program indicate, these variables can be defined inside the main() function; because an external (or static) variable is automatically initialized to zero (or zeroes), however, you don’t have to initialize the variables. Again, the way your program (or function) is used dictates how or where you allocate the storage.

In allocating storage, you create first a character array called szBuffer that is used to hold the strings as they are read in. The next variable, pBuffer, an array of pointers to type char, is declared. The first member in this array points to the first string stored in szBuffer, the second member in pBuffer points to the second string stored, and so on.

A count of the number of strings entered by the user is kept in nLine. This variable is initialized to zero (the first string) and is incremented until the user finishes entering strings. It then is used in the for() loop that is used to print the user’s strings.

An index pointing to the character position in szBuffer in which the next string will be placed is kept in nBufferPointer. This variable is initialized to zero (the first character position in szBuffer) and is incremented by the number of characters in each of the user’s strings until the user finishes entering strings.

The program’s input is handled using a while() loop, which calls gets(), a C library function that reads a line from stdin (the keyboard).

while (gets(szInput))

{

if ((nBufferPointer + strlen(szInput)) > MAX_CHARACTERS) { // The line won’t fit! End input loop.

break;

}

pBuffer[nLine] = &szBuffer[nBufferPointer];

//The strcpy() could have been written as:

//strcpy(&szBuffer[nBufferPointer], szInput);

61

Part I • Honing Your C Skills

strcpy(pBuffer[nLine], szInput);

//The + 1 skips over the terminating NULL in each string. nBufferPointer += strlen(szInput) + 1;

if (++nLine >= MAX_LINES)

{ // Too many lines! End input loop. break;

}

}

In the input while() loop, first you check to see whether szBuffer has enough room for this line, and then abort the input if there is no more room. Then you add the line to szBuffer and update the pointers. If no more input line pointers remain in pBuffer, you end the input phase as well. This error checking is not the best, but this program is intended to show a usage for an array of pointers—not to show error checking.

When the user signals the end of input, the program then can process the lines. This program alludes only to the fact that perhaps you sort the lines, or count characters, lines, and words, or justify the text or change its case. Who knows, and for now, who cares? You have a program that reads lines in and writes them out.

To write the lines out, a simple for() loop has been used. This loop simply uses printf() to print the user’s inputted lines:

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

{

printf(“String %d ‘%s’\n”, i, pBuffer[i]);

}

In the call to printf(), you use the pointer to the string in the buffer rather than try to use an array index—again, to show the use of an array of pointers.

Summary

C provides the basic data types necessary to create most programs. C’s flexibility is due in part to its capability to create new data types as they are needed. The limits of each type of variable were described in this chapter.

62

Data Types, Constants, Variables, and Arrays

C C C

 

C2C

 

C C C

 

C

Using constants in C is much like using a constant in any other computer language. The only different situation is that in C you can modify a character constant (even though it’s an error).

There is a difference between a variable’s declaration (which allocates storage and defines the variable’s attributes) and a variable’s definition (which only defines the variable’s attributes and does not allocate storage).

The use and initialization of variables were discussed, along with arrays, including using indirection as a method to access an array’s members. The chapter discussed multidimensional arrays and how they are stored in memory, with a demonstration of one-, two-, and three-dimensional arrays provided by an example program.

The last part of the chapter described arrays of pointers and a simple program demonstrated their use.

63

Part I • Honing Your C Skills

64

The C Philosophy

C C C

 

C1C

 

C C C

 

C

Table 1.1. ANSI compiler minimums.

Minimum

Item

6

Significant characters in an external name

8

#include nesting

8

#if, #ifndef, #ifdef and #elif

12

(), [], or * in a declaration

15

Nested compound statements

15

Levels of struct or union nesting

31

() declarators within a declaration

31

Significant characters in a macro or identifier

31

Parameters passed to a function or macro (important for

 

printf(), scanf(), and so on)

32

Levels of nested parentheses

127

Local identifiers in a block

127

Members in a single struct, union or enum

257

case statements in a switch() statement

509

Characters in a literal string (after any concatenation)

511

External identifiers in a single source file

1024

Simultaneously defined macros

32767

Bytes in a single data object

 

 

Of course, nothing prevents a compiler producer from extending these limits; however, you should review the documentation supplied with your compiler to see whether any (or all) limits are different from the ANSI standard. If your compiler does extend these limits and you use the extensions, you can be sure that when your program is compiled with another compiler, it will either not compile correctly or not execute correctly.

5

Part I • Honing Your C Skills

Some of these limits will change (soon, I hope) with future revisions of the ANSI specification. One of the most bothersome limits, six significant characters in an external name, was issued because some linkers cannot use more than the first six characters in an external name. As noted by the ANSI standards committee, this limit is a rather poor one and probably will change soon. If your compiler doesn’t have a published limit on the number of significant characters in an external name, you can test it. Compile and link the programs shown in Listing 1.1 (it has two source files). As noted in the listing, changing the names of the functions called (and the missing one) can be used to indicate the number of characters that are significant (13 in this example) in an external name.

Listing 1.1. External name lengths for FILEONE.C and FILETWO.C.

FILEONE.C

void sixchr1234567(void); void sixchr1234567(void);

int

main()

{

 

 

sixchr1234567();

 

sixchr12345678(); /* Will be unresolved external if more than */

 

/* 13 characters are significant. */

}

 

FILETWO.C

void

sixchr1234567()

{

 

 

return;

}

 

 

 

Another significant factor in external names is that most linkers ignore case. You should be very careful, therefore, not to have two functions that differ only in the case of their names, such as in the following example (in which both functions are external):

OurPrinter(); /* Print, using initial caps. */ OURPRINTER(); /* Print, using all caps. */ ourprinter(); /* Print, using only lowercase. */

6

The C Philosophy

C C C

 

C1C

 

C C C

 

C

In this fragment, the three different names will be linked to the same function by the linker. Some linkers have the option to retain case, which solves this problem, but many don’t. Be careful: I got burned by this one once, and it took a long time to determine why the wrong function was being called. (I didn’t know about the other, different-case function).

A number of keywords are reserved in ANSI C (see Table 1.2). You must be careful not to use these names (all of the ANSI keywords are in lowercase) as identifiers in your program. Generally, the compiler “complains” when you incorrectly use any reserved keyword.

Table 1.2. ANSI C reserved identifiers.

Keyword Usage

asm FORTRAN

Begins assembly code and is not part of the ANSI standard.

The entry follows FORTRAN calling conventions; FORTRAN may be in lowercase for some implementations and is not part of the ANSI standard.

PASCAL

The entry follows PASCAL calling conventions; PASCAL may be in lowercase for some implementations and is not part of the ANSI standard. Generally, the PASCAL conventions are identical to FORTRAN’s.

const

The variable will be used as a constant and will not be modified.

volatile

The compiler may make no assumptions about whether the variable’s value is current. This keyword limits optimization, and possibly slows program execution.

signed

The variable is a signed integer (with the actual size

 

unspecified).

auto

The variable is created when the function is called, and is

 

discarded when the function exits. An auto variable is not

 

initialized by the compiler.

 

continues

7

Part I • Honing Your C Skills

Table 1.2. continued

Keyword

Usage

break

Ends the enclosing do(), for(), switch()/case or while()

 

statement and is used most often to end a case statement.

 

Using break outside of a switch()/case block may be

 

considered to be unstructured programming, in the same

 

way that embedded return statements are considered by

 

some programmers.

case

Used with the switch() statement to mark the beginning of

 

a group of statements that are executed when the case’s

 

value matches the switch() statement’s value. Execution

 

continues until a break statement is encountered or no more

 

statements are in the switch() statements.

char

A character variable that may be either signed or unsigned.

continue

Passes control to the next iteration of a do(), for(), or

 

while() statement.

default

Used with a switch() statement, the statements following

 

the default statement are executed until the first break

 

statement if no case statement value matches the switch()

 

statement’s expression.

do

Used with the while() statement, the statement or state-

 

ments between the do and the closing while() are executed

 

until the while() condition evaluates to false. The state-

 

ments between are executed at least one time.

double

An eight-byte floating point variable.

else

Used with the if() statement, the statement or statements

 

within the else block are executed if the if() expression

 

evaluates to false.

enum

An integer defining a range of values. The actual internal representation of the value is not significant.

extern float

The object is defined in a different source file.

A four-byte floating point variable.

8