Advanced C 1992
.pdfPointers and Indirection |
C C C |
|
C3C |
|
C C C |
|
C |
To make up for the shortcomings in C’s character handling, a large number of string functions are in the standard library (see Chapter 14, “ANSI C Library Functions”). Because the particular functionality your application requires might not be present in one of the C library functions, you can write a function to do whatever you want.
This section doesn’t show you how to count words in a string (the demo program does that), but it does show you how easy it is to work with strings and manipulate pointers to strings.
By now, you should not still be writing programs that compare strings using logical operators, as in the following example:
char szFirst[] = {“This is a string”}; char szNext[] = {“Before this one”);
if (szFirst > szNext)
{
/* the test was meaningless! */
}
This comparison simply evaluates the addresses of the two strings, not their contents. The result of the test is undefined because you cannot predict where in memory the strings will be located, nor are their contents related to their memory address.
The correct way to compare two strings is to call the library function strcmp(), which returns a value based on the logical relationship between the two strings:
char szFirst[] = {“This is a string”}; char szNext[] = {“Before this one”);
if (strcmp(szFirst, szNext) > 0)
{
/* szFirst is before szNext! */
}
This relationship is much more useful to your programs than are the string’s addresses. NUMWORD.C counts the number of words in a sentence that are entered from the keyboard (see Listing 3.4).
75
Part I • Honing Your C Skills
Listing 3.4. NUMWORD.C.
/* NUMWORD, written 20 May 1992 by Peter D. Hipson */ /* Program to count words in sentences. */
#include <stdio.h> // Make includes first part of file #include <string.h> // For string functions
#define |
TRUE |
1 |
#define |
FALSE |
0 |
int main(void); // Define main() and the fact that this program doesn’t // use any passed parameters.
int |
NumberWords(char |
* pString); |
|
#define |
BIGEST_LINE |
256 |
/* The biggest line readable from keyboard */ |
/* Though these variables are defined as external, they can be
*defined inside the function or be allocated dynamically,
*depending on the program’s needs and the amount of memory available */
char szInput[BIGEST_LINE];
int main()
{
int i;
printf(
“Enter lines, when last one is entered\n”
“provide a End-Of-File (ctrl-Z on most systems)\n” “to end the program.\n\n”);
while (gets(szInput))
{
76
Pointers and Indirection
printf(“Words = %2d ‘%.50s’\n”,
|
NumberWords(szInput), |
|
szInput); |
} |
|
printf(“\n”); |
|
return (0); |
|
} |
|
int |
NumberWords( |
char |
szString[]) |
{ |
|
int |
i; |
int |
nBlank = TRUE; |
int |
nCount = 0; |
for (i = 0; szString[i]; i++)
{
if (szString[i] != ‘ ‘)
{
if (nBlank)
{
++nCount;
}
nBlank = FALSE;
}
else
{
nBlank = TRUE;
}
}
return(nCount);
}
C C C
C3C C
C C C
77
Part I • Honing Your C Skills
NUMWORD has a very simple loop that calls gets() until the end-of-file is reached. After gets() returns, the loop itself calls printf(), which has as one of its parameters a call to the NumberWords() function.
printf(“Words = %2d ‘%.50s’\n”, NumberWords(szInput), szInput);
C first calls NumberWords() and then passes to printf() the returned value, along with the other parameters.
for (i = 0; szString[i]; i++)
{
if (szString[i] != ‘ ‘)
{
if (nBlank)
{
++nCount;
}
nBlank = FALSE;
}
else
{
nBlank = TRUE;
}
}
NumberWords() has a loop that looks at the passed string and parses out the words. The format for this loop is a for() loop; while() can be used, however. This loop moves through the character string and increments an index to the passed string. When the loop starts, it is assumed that a blank has been encountered already. This assumption is made by setting the blank flag (nBlank) on so that you can count the first word regardless of whether it’s preceded by blanks. Also, the word count (nCount) is set to zero, which indicates that no words have been counted.
When the first nonblank character is found, the word counter is incremented (a word has been found), and the blank flag is turned off. The loop continues searching for the next blank; when it is found, the blank flag is set to on and the process continues until the end of the string is found.
78
Pointers and Indirection |
C C C |
|
C3C |
|
C C C |
|
C |
Indirection to Access Character Strings
To change NUMWORD to use indirection to access the string, the loop in NumberWords() must change slightly (see Listing 3.5).
Listing 3.5. NUMWORD1.C.
/* NUMWORD1, written 21 May 1992 by Peter D. Hipson */ /* Program to count words in sentences. */
#include <stdio.h> // Make includes first part of file #include <string.h> // For string functions
#define |
TRUE |
1 |
#define |
FALSE |
0 |
int main(void); // Define main() and the fact that this program doesn’t // use any passed parameters.
int |
NumberWords(char |
* pString); |
|
#define |
BIGEST_LINE |
256 |
/* The biggest 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];
int main()
{
int i;
printf(
continues
79
Part I • Honing Your C Skills
Listing 3.5. continued
“Enter lines, when last one is entered\n”
“provide a End-Of-File (ctrl-Z on most systems)\n” “to end the program.\n\n”);
while (gets(szInput))
{
printf(“Words = %2d ‘%.50s’\n”,
|
NumberWords(szInput), |
|
szInput); |
} |
|
printf(“\n”); |
|
return (0); |
|
} |
|
int |
NumberWords( |
char |
* pString) |
{ |
|
int |
nBlank = TRUE; |
int |
nCount = 0; |
do |
|
{ |
|
|
if (*(pString) && *(pString) != ‘ ‘) |
|
{ |
|
if (nBlank) |
|
{ |
|
++nCount; |
|
} |
nBlank = FALSE;
}
else
{
nBlank = TRUE;
}
80
Pointers and Indirection |
C C C |
|
C3C |
|
C C C |
|
C |
} while(*(pString++));
return(nCount);
}
NumberWords() again has a loop that looks at the passed string and parses out the words. The format for this loop is do()...while(). A straight while() or even a for() loop, however, can be used:
do
{
if (*(pString) && *(pString) != ‘ ‘)
{
if (nBlank)
{
++nCount;
}
nBlank = FALSE;
}
else
{
nBlank = TRUE;
}
} while(*(pString++));
You no longer need to use an index variable, because you are using the pointer that was passed to keep track of where you are in the string. One possible advantage to this method is that by incrementing the pointer rather than an index to a string, the function generally is both faster and smaller.
This loop moves through the character string and increments the passed pointer. Remember that this passed pointer is a private copy for this function and can be modified. It is assumed that a blank has been encountered already, by setting the blank flag on so that you can count the first word regardless of whether it is preceded by blanks. Also, the word count is set to zero so that no words are counted. When the first nonblank character is found, the word counter is incremented (a word has been found) and the blank flag is turned off. The loop continues searching for the next blank; when it is found, the blank flag is set to on and the process continues until the end of the string is found.
81
Part I • Honing Your C Skills
Listing 3.6 shows the assembly listing for the version of NumberWords() that uses pointer indexing. The compiler produces this machine code, commented with the original source lines, when the function is compiled.
Listing 3.6. NUMWORD3.COD, the assembly listing for the pointer version of NumberWords().
;Edited for size.
;Static Name Aliases
TITLE numword3.c NAME numword3
.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 |
||
EXTRN |
|
--acrtused:ABS |
|
EXTRN |
|
--chkstk:NEAR |
|
_TEXT |
|
SEGMENT |
|
ASSUME |
CS: _TEXT |
;|*** /* NUMWORD3, written 21 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( |
|
|
82
|
|
|
|
|
|
Pointers and Indirection |
C C C |
|
|
|
|
|
|
|
C3C |
|
|
|
|
|
|
|
C C C |
;|*** |
char |
* pString) |
|
|
C |
||
|
|
|
|||||
;|*** |
|
|
|
|
|
|
|
;|*** { |
|
|
|
|
|
|
|
; Line 15 |
|
|
|
|
|
|
|
PUBLIC |
|
_NumberWords |
|
|
|
||
_NumberWords |
PROC |
NEAR |
|
|
|
||
*** 000000 |
55 |
|
|
push |
bp |
|
|
*** 000001 |
8b |
ec |
|
mov |
bp,sp |
|
|
*** 000003 |
b8 |
06 |
00 |
mov |
ax,6 |
|
|
*** 000006 |
e8 |
00 |
00 |
call |
__ chkstk |
|
;pString = 4
;nBlank = -2
;nCount = -4
;|***
;|*** int |
|
nBlank |
= TRUE; |
|
|
|
|
|
; Line 17 |
|
|
|
|
|
|
|
|
*** 000009 |
c7 |
46 |
fe 01 00 |
|
mov |
WORD PTR [bp-2],1 |
||
;nBlank |
|
|
|
|
|
|
|
|
;|*** int |
|
nCount |
= 0; |
|
|
|
|
|
; Line 18 |
|
|
|
|
|
|
|
|
*** 00000e |
c7 |
46 |
fc 00 00 |
|
mov |
WORD PTR [bp-4],0 |
||
;nCount |
|
|
|
|
|
|
|
|
;|*** |
|
|
|
|
|
|
|
|
;|*** |
do |
|
|
|
|
|
|
|
; Line 20 |
|
|
|
|
|
|
|
|
|
|
|
$D239: |
|
|
|
|
|
;|*** |
{ |
|
|
|
|
|
|
|
; Line 21 |
|
|
|
|
|
|
|
|
;|*** |
|
if (*(pString) && *(pString) != ‘ ‘) |
|
|||||
; Line 22 |
|
|
|
|
|
|
|
|
*** 000013 |
8b |
5e |
04 |
mov |
bx,WORD PTR [bp+4] |
;pString |
||
*** 000016 |
8a |
07 |
|
mov |
al,BYTE PTR [bx] |
|
||
*** 000018 |
88 |
46 |
fa |
mov |
BYTE PTR [bp-6],al |
|
||
*** 00001b |
0a |
c0 |
|
or |
al,al |
|
|
|
*** 00001d |
74 |
15 |
|
je |
$I242 |
|
|
|
*** 00001f |
3c |
20 |
|
cmp |
al,32 |
|
|
|
*** 000021 |
74 |
11 |
|
je |
$I242 |
|
|
|
;|*** |
|
{ |
|
|
|
|
|
|
; Line 23 |
|
|
|
|
|
|
|
|
;|*** |
|
if |
(nBlank) |
|
|
|
|
continues
83
Part I • Honing Your C Skills
Listing 3.6. continued
; Line 24 |
|
|
|
|
|
|
|
|
*** 000023 |
83 |
7e fe 00 |
cmp |
WORD PTR [bp-2],0 |
;nBlank |
|||
*** 000027 |
74 |
03 |
je |
$I243 |
|
|
|
|
;|*** |
|
{ |
|
|
|
|
|
|
; Line 25 |
|
|
|
|
|
|
|
|
;|*** |
|
|
++nCount; |
|
|
|
|
|
; Line 26 |
|
|
|
|
|
|
|
|
*** 000029 |
ff 46 fc |
inc |
WORD PTR [bp-4] |
;nCount |
||||
;|*** |
|
} |
|
|
|
|
|
|
; Line 27 |
|
|
|
|
|
|
|
|
;|*** |
|
|
|
|
|
|
|
|
;|*** |
|
nBlank = FALSE; |
|
|
|
|
|
|
; Line 29 |
|
|
|
|
|
|
|
|
|
|
|
$I243: |
|
|
|
|
|
*** 00002c |
c7 |
46 fe 00 00 |
|
mov |
WORD PTR [bp-2],0 |
|
||
;nBlank |
|
|
|
|
|
|
|
|
;|*** |
|
} |
|
|
|
|
|
|
; Line 30 |
|
|
|
|
|
|
|
|
;|*** |
|
else |
|
|
|
|
|
|
; Line 31 |
|
|
|
|
|
|
|
|
*** 000031 |
eb 06 |
jmp |
SHORT $I244 |
|
|
|||
*** 000033 |
90 |
|
nop |
|
|
|
|
|
|
|
|
$I242: |
|
|
|
|
|
;|*** |
|
{ |
|
|
|
|
|
|
; Line 32 |
|
|
|
|
|
|
|
|
;|*** |
|
nBlank = TRUE; |
|
|
|
|
|
|
; Line 33 |
|
|
|
|
|
|
|
|
*** 000034 |
c7 |
46 fe 01 00 |
|
mov |
WORD PTR [bp-2],1 |
|
||
;nBlank |
|
|
|
|
|
|
|
|
;|*** |
|
} |
|
|
|
|
|
|
; Line 34 |
|
|
|
|
|
|
|
|
|
|
|
$I244: |
|
|
|
|
|
;|*** |
|
|
|
|
|
|
|
|
;|*** |
} while(*(pString++)); |
|
|
|
|
|
||
; Line 36 |
|
|
|
|
|
|
|
|
*** 000039 |
8b |
5e 04 |
mov |
bx,WORD PTR [bp+4] |
;pString |
|||
*** 00003c |
ff 46 04 |
inc |
WORD PTR [bp+4] |
;pString |
||||
*** 00003f |
80 |
3f 00 |
cmp |
BYTE PTR [bx],0 |
|
|
||
*** 000042 |
75 |
cf |
jne |
$D239 |
|
|
|
84