
Advanced C 1992
.pdf
|
|
|
|
|
|
Pointers and Indirection |
|
C C C |
|
|
|
|
|
|
|
|
|
C3C |
|
|
|
|
|
|
|
|
|
C C C |
|
;|*** |
|
|
|
|
|
|
C |
||
|
|
|
|
|
|
|
|
||
;|*** |
return(nCount); |
|
|
|
|
|
|||
|
; Line 38 |
|
|
|
|
|
|
|
|
*** 000044 |
8b |
46 fc |
mov |
ax,WORD PTR [bp-4] |
;nCount |
||||
*** 000047 |
8b |
e5 |
mov |
sp,bp |
|
|
|
||
*** 000049 |
5d |
|
pop |
bp |
|
|
|
||
|
*** 00004a |
c3 |
|
ret |
|
|
|
|
|
|
*** 00004b |
90 |
|
nop |
|
|
|
|
|
|
_NumberWords |
ENDP |
|
|
|
|
|
|
|
|
_TEXT |
ENDS |
|
|
|
|
|
|
|
|
END |
|
|
|
|
|
|
|
|
;|*** } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Listing 3.7 is the assembly listing for the version of NumberWords() that uses an index to the passed array. As in the preceding example, the compiler produces this machine code, commented with the original source lines, when the function is compiled.
Listing 3.7. NUMWORD4.COD, the assembly listing for the array indexed version of NumberWords().
;Edited for size.
;Static Name Aliases
TITLE numword4.c NAME numword4
.8087 |
|
|
_TEXT |
SEGMENT |
WORD PUBLIC ‘CODE’ |
_TEXT |
ENDS |
|
_DATA |
SEGMENT |
WORD PUBLIC ‘DATA’ |
_DATA |
ENDS |
|
CONST |
SEGMENT |
WORD PUBLIC ‘CONST’ |
CONST |
ENDS |
|
_BSS |
SEGMENT |
WORD PUBLIC ‘BSS’ |
_BSS |
ENDS |
|
DGROUP |
GROUP |
CONST, _BSS, _DATA |
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
continues
85

Part I • Honing Your C Skills
Listing 3.7. continued
EXTRN |
--acrtused:ABS |
|
EXTRN |
--chkstk:NEAR |
|
_TEXT |
|
SEGMENT |
ASSUME |
CS: _TEXT |
;|*** /* NUMWORD, written 20 May 1992 by Peter D. Hipson */
;|*** |
|
|
|
|
|
|
;|*** #include <stdio.h> |
// Make includes first part of file |
|||||
;|*** #include <string.h> // For string functions |
||||||
;|*** |
|
|
|
|
|
|
;|*** #define |
TRUE |
1 |
|
|
||
;|*** #define |
FALSE |
0 |
|
|
||
;|*** |
|
|
|
|
|
|
;|*** |
|
|
|
|
|
|
;|*** int |
|
NumberWords(char |
* pString); |
|||
;|*** |
|
|
|
|
|
|
;|*** |
|
|
|
|
|
|
;|*** int |
|
NumberWords( |
|
|
|
|
;|*** |
char |
szString[]) |
|
|
||
;|*** |
|
|
|
|
|
|
;|*** { |
|
|
|
|
|
|
; Line 16 |
|
|
|
|
|
|
PUBLIC |
|
_NumberWords |
|
|
|
|
_NumberWords |
PROC NEAR |
|
|
|
||
*** 000000 |
55 |
|
|
push |
bp |
|
*** 000001 |
8b |
ec |
|
mov |
bp,sp |
|
*** 000003 |
b8 |
08 00 |
|
mov |
ax,8 |
|
*** 000006 |
e8 |
00 00 |
|
call |
--chkstk |
|
*** 000009 |
56 |
|
|
push |
si |
;szString = 4
;i = -6
;nBlank = -2
;nCount = -4
;|***
;|*** int |
i; |
|
|
|
;|*** int |
nBlank |
= TRUE; |
|
|
; Line 19 |
|
|
|
|
*** 00000a |
c7 |
46 fe 01 00 |
mov |
WORD PTR [bp-2],1 |
;nBlank |
|
|
|
|
;|*** int |
nCount |
= 0; |
|
|
86

|
|
|
|
|
|
Pointers and Indirection |
|
C C C |
||
|
|
|
|
|
|
|
|
|
|
C3C |
|
|
|
|
|
|
|
|
|
|
C C C |
; Line 20 |
|
|
|
|
|
|
|
|
|
C |
|
|
|
|
|
|
|
|
|
|
|
*** 00000f |
c7 |
46 |
fc 00 00 |
|
mov |
WORD PTR [bp-4],0 |
|
|||
;nCount |
|
|
|
|
|
|
|
|
|
|
;|*** |
|
|
|
|
|
|
|
|
|
|
;|*** |
for (i = 0; szString[i]; i++) |
|
|
|
|
|
||||
; Line 22 |
|
|
|
|
|
|
|
|
|
|
*** 000014 |
c7 |
46 |
fa 00 00 |
|
mov |
WORD PTR [bp-6],0 |
;i |
|||
*** 000019 |
eb 09 |
|
jmp |
SHORT $F240 |
|
|
|
|||
*** 00001b |
90 |
|
|
nop |
|
|
|
|
|
|
|
|
|
$I243: |
|
|
|
|
|
|
|
;|*** |
{ |
|
|
|
|
|
|
|
|
|
;|*** |
|
if (szString[i] != ‘ ‘) |
|
|
|
|
|
|||
;|*** |
|
{ |
|
|
|
|
|
|
|
|
;|*** |
|
if (nBlank) |
|
|
|
|
|
|
||
;|*** |
|
{ |
|
|
|
|
|
|
|
|
;|*** |
|
|
++nCount; |
|
|
|
|
|
|
|
;|*** |
|
} |
|
|
|
|
|
|
|
|
;|*** |
|
|
|
|
|
|
|
|
|
|
;|*** |
|
nBlank = FALSE; |
|
|
|
|
|
|
||
;|*** |
|
} |
|
|
|
|
|
|
|
|
;|*** |
|
else |
|
|
|
|
|
|
|
|
;|*** |
|
{ |
|
|
|
|
|
|
|
|
; Line 34 |
|
|
|
|
|
|
|
|
|
|
;|*** |
|
nBlank = TRUE; |
|
|
|
|
|
|
||
; Line 35 |
|
|
|
|
|
|
|
|
|
|
*** 00001c |
c7 |
46 |
fe 01 00 |
|
mov |
WORD PTR [bp-2],1 |
|
|||
;nBlank |
|
|
|
|
|
|
|
|
|
|
;|*** |
|
} |
|
|
|
|
|
|
|
|
; Line 36 |
|
|
|
|
|
|
|
|
|
|
;|*** |
} |
|
|
|
|
|
|
|
|
|
; Line 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
$FC241: |
|
|
|
|
|
|
|
*** 000021 |
ff 46 fa |
inc |
WORD PTR [bp-6] |
;i |
|
|
||||
|
|
|
$F240: |
|
|
|
|
|
|
|
*** 000024 |
8b |
5e |
fa |
mov |
bx,WORD PTR [bp-6] |
|
;i |
|
||
*** 000027 |
8b |
76 |
04 |
mov |
si,WORD PTR [bp+4] |
|
;szString |
|||
*** 00002a |
8a |
00 |
|
mov |
al,[bx][si] |
|
|
|
||
*** 00002c |
88 |
46 |
f8 |
mov |
BYTE PTR [bp-8],al |
|
|
|
||
*** 00002f |
0a |
c0 |
|
or |
al,al |
|
|
|
|
|
*** 000031 |
74 |
15 |
|
je |
$FB242 |
|
|
|
|
continues
87

Part I • Honing Your C Skills
Listing 3.7. continued
;|*** |
{ |
|
|
|
|
|
|
; Line 23 |
|
|
|
|
|
|
|
;|*** |
|
if (szString[i] != ‘ ‘) |
|
|
|
|
|
; Line 24 |
|
|
|
|
|
|
|
*** 000033 |
3c 20 |
cmp |
al,32 |
|
|
|
|
*** 000035 |
74 e5 |
je |
$I243 |
|
|
|
|
;|*** |
|
{ |
|
|
|
|
|
; Line 25 |
|
|
|
|
|
|
|
;|*** |
|
if (nBlank) |
|
|
|
|
|
; Line 26 |
|
|
|
|
|
|
|
*** 000037 |
83 7e fe 00 |
cmp |
WORD PTR [bp-2],0 |
;nBlank |
|||
*** 00003b |
74 03 |
je |
$I244 |
|
|
|
|
;|*** |
|
{ |
|
|
|
|
|
; Line 27 |
|
|
|
|
|
|
|
;|*** |
|
++nCount; |
|
|
|
|
|
; Line 28 |
|
|
|
|
|
|
|
*** 00003d |
ff 46 fc |
inc |
WORD PTR [bp-4] |
;nCount |
|||
;|*** |
|
} |
|
|
|
|
|
; Line 29 |
|
|
|
|
|
|
|
;|*** |
|
|
|
|
|
|
|
;|*** |
|
nBlank = FALSE; |
|
|
|
|
|
; Line 31 |
|
|
|
|
|
|
|
|
|
$I244: |
|
|
|
|
|
*** 000040 |
c7 46 fe 00 00 |
|
mov |
WORD PTR [bp-2],0 |
|
||
;nBlank |
|
|
|
|
|
|
|
;|*** |
|
} |
|
|
|
|
|
; Line 32 |
|
|
|
|
|
|
|
;|*** |
|
else |
|
|
|
|
|
; Line 33 |
|
|
|
|
|
|
|
*** 000045 |
eb da |
jmp |
SHORT $FC241 |
|
|
||
*** 000047 |
90 |
nop |
|
|
|
|
|
|
|
$FB242: |
|
|
|
|
|
;|*** |
|
{ |
|
|
|
|
|
;|*** |
|
nBlank = TRUE; |
|
|
|
|
|
;|*** |
|
} |
|
|
|
|
|
;|*** |
} |
|
|
|
|
|
|
;|*** |
|
|
|
|
|
|
|
88

|
|
|
|
|
|
Pointers and Indirection |
|
C C C |
|
|
|
|
|
|
|
|
|
C3C |
|
|
|
|
|
|
|
|
|
C C C |
|
;|*** |
return(nCount); |
|
|
|
C |
||||
|
|
|
|
|
|||||
|
; Line 39 |
|
|
|
|
|
|
|
|
*** 000048 |
8b |
46 fc |
mov |
ax,WORD PTR [bp-4] |
;nCount |
||||
|
*** 00004b |
5e |
|
pop |
si |
|
|
|
|
|
*** 00004c |
8b |
e5 |
mov |
sp,bp |
|
|
|
|
|
*** 00004e |
5d |
|
pop |
bp |
|
|
|
|
|
*** 00004f |
c3 |
|
ret |
|
|
|
|
|
|
_NumberWords |
ENDP |
|
|
|
|
|
|
|
|
_TEXT |
ENDS |
|
|
|
|
|
|
|
|
END |
|
|
|
|
|
|
|
|
;|*** } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The assembly listings show the major differences from what the original C version shows; you should consider several factors, however, when you are deciding whether to use indexing or to modify pointers:
•Functions that use indexing often are easier to read and understand.
•Functions that use indexing often generate more machine code than functions that use pointer modification. This situation is more prevalent in functions that have many references to the variable (or variables) accessed with pointers.
•Functions that use indexing often are slower than functions that use pointer modification. This situation is more prevalent in functions that have many references to the variable (or variables) accessed with pointers, and occurs because the functions usually must add the index to the array base for each access.
•Functions with array indexing require local variables that require stack space. This consideration usually is a minor one, but it may be a factor when stack usage must be either minimized or eliminated.
You should note that even though the example program used a string (which is a character array), the concepts are the same in other arrays, such as int, long, or float. The important thing with nonstring arrays is that the function the string is being passed to must know how many elements are found in the array, because only strings have a meaningful end marker, NULL.
89

Part I • Honing Your C Skills
Protecting Strings in Memory
If I could find a way to protect strings in memory, I would be rich. Seriously, the only thing that protects strings in memory is careful programming. Although many operating environments offer some forms of memory protection and some compilers offer bounds checking, this protection is limited and easily circumvented—often unknowingly by programmers.
A number of dangerous functions in the C language’s library don’t know how long a string is and easily can overwrite a string’s memory allocation without notifying the programmer. Even functions that tell you how much of the string they used have possibly already destroyed valuable memory when they write past the end of the string.
Two of the worst offenders are input/output functions and the various string functions. The input/output functions are often given a buffer in order to read in the desired information. The problem is that they don’t know how long the buffer is. In the following example fragment, the programmer made the assumption that a user never would enter a line longer than 80 characters:
char szBuffer[80]; // You’ll never read more than 80 characters // (ha-ha).
if (gets(szBuffer))
{
// Process the buffer inputted.
}
The programmer might have thought, for example, that the terminal to be used allowed only 80 characters per line. The user first used I/O redirection to provide input to the program, though, and the lines in the user’s file were about 200 characters long. Of course, the program crashed.
This problem doesn’t really have a fix that always works. The fix most often consists of putting a realistic maximum on the buffer size, which means that the buffer must be capable of holding a very large string. In the preceding example, it would not be unreasonable to define the input buffer to be several thousand bytes long. I usually create in my programs a generic buffer (called szTempBuffer), which is used for places where I don’t want to experience buffer overflow.
In the following example, a set of two strings has been defined and then concatenated, when necessary.
90

Pointers and Indirection |
C C C |
|
C3C |
|
C C C |
|
C |
char |
szMyName[] = {“Peter |
D. Hipson”); |
char |
szMyAddress[]= {“New |
Hampshire”); |
// bFullAddress says that the user wants my full address:
if (bFullAddress)
{
strcat(szMyName, szMyAddress);
}
The only problem is that szMyName is not large enough to hold both strings. Crash—it’s over! Again, the fix is to be sure that the destination for the library string functions is large enough. One possible fix is to use szTempBuffer to hold the result of the concatenation and then test to see whether it fits into the final destination, as in this example:
strcpy(szTempBuffer, szMyName); strcat(szTempBuffer, szMyAddress);
if (strlen(szTempBuffer) > sizeof(szMyName))
{// Truncate the result to fit. szTempBuffer[sizeof(szMyName) - 1] = ‘\0’;
printf(“String ‘%s’ won’t fit into buffer\n”, szTempBuffer);
}
strcpy(szMyName, szTempBuffer);
Or if the preceding example doesn’t require that the operation take place if the number of characters being assigned to a string doesn’t fit, you can simply test and perform the operation if it fits:
if (strlen(szMyName) + strlen(szMyAddress) < sizeof(szMyName))
{
strcat(szMyName, szMyAddress);
}
else
{
printf(“String ‘%s%s’ won’t fit into buffer\n”, szMyName,
szMyAddress);
}
The primary difference is that the first example copies as many characters as will fit, and the second does not. For either example to work, the compiler must know how
91

Part I • Honing Your C Skills
large the strings are. It knows how large when the strings are declared in the source file, or when they are defined with sizes. Because you often define arrays by specifying their size, you can get into trouble when an error message tells you that the size of the object is unknown.
When you are using sprint() to print to a string, the function can cause innumerable problems because most format specifiers for floating-point numbers, when given an invalid value, print some rather strange results. Often, you assume that your numbers are always correct; that assumption is a weak one, however, because the majority of the numbers the program works with are provided by the user. In this case also, I try to use a large buffer, such as my szTempBuffer, to hold the results of sprintf() until I can be sure that the resulting string is not too large for the intended destination.
Ragged-Right String Arrays
There is a problem with using strings. Suppose that you have a program with a large number of strings, such as list of common sayings. Each line of the sayings is placed in a string buffer. If these strings are used as constants (they won’t be modified), you may well want to pack the strings together, with no wasted space.
A more common way of storing strings is shown in the program FIXSTR.C. It allocates an array of 25 lines, each of which is 80 characters long. The total storage required for this array is 2,000 bytes (see Listing 3.8).
Listing 3.8. FIXSTR.C.
/* FIXSTR, written 20 May 1992 by Peter D. Hipson */ /* Fixed-length strings in a program. */
#include <stdio.h> // Make includes first part of file #include <string.h> // For string functions.
#define MAX_LINES 25 #define MAX_LENGTH 80
int main(void); // Define main() and the fact that this program doesn’t // use any passed parameters.
92

|
|
Pointers and Indirection |
C C C |
|
|
|
C3C |
|
|
|
C C C |
int main() |
|
C |
|
|
|
||
{ |
|
|
|
int |
i; |
|
|
char |
szSaying[MAX_LINES][MAX_LENGTH] = |
|
|
|
{ |
|
|
|
“Firestone’s Law of Forecasting:”, |
|
|
|
“ |
Chicken Little only has to be right once.”, |
|
|
“”, |
|
|
|
“”, |
|
|
|
“Manly’s Maxim:”, |
|
|
|
“ |
Logic is a systematic method of coming to”, |
|
|
“ |
the wrong conclusion with confidence.”, |
|
|
“”, |
|
|
|
“”, |
|
|
|
“Moer’s truism:”, |
|
|
|
“ |
The trouble with most jobs is the job holder’s”, |
|
|
“ |
resemblance to being one of a sled dog team. No one”, |
|
“gets a change of scenery except the lead dog.”, “”, “”,
“Cannon’s Comment:”,
“If you tell the boss you were late for work because you”,
“had a flat tire, the next morning you will have a flat tire.”
};
printf(
“Number of lines is %d\n” “size of item is %d\n” “size of (char) is %d\n”,
sizeof(szSaying) / sizeof(szSaying[0]), // Number of elements.
sizeof(szSaying[0]), |
// Size of char * |
sizeof(szSaying[0][0])); |
// Size of char |
switch (sizeof(char *)) |
|
{ |
|
case 2: // Near pointers |
|
printf(“Addr len saying\n”); |
|
break; |
|
|
continues |
93

Part I • Honing Your C Skills
Listing 3.8. continued
case 4: // Far pointers, 808x segmented pointers. printf(“Address len saying\n”);
break;
}
for (i = 0; i < sizeof(szSaying) / sizeof(szSaying[0]); i++)
{
printf(“%p %3d ‘%s’\n”, szSaying[i], strlen(szSaying[i]), szSaying[i]);
}
return (0);
}
Figure 3.2 shows an example of how the memory for FIXSTR.C’s szSaying is allocated and used. In this program, szSaying is a single, two-dimensional character array.
Figure 3.2. szSaying in FIXSTR.C.
94