102 Intermediate C Programming
fclose ( infptr ) ;25
return EXIT _FAILUR E ;26
}27
28
int num_lines = 0;29
char buffer [ LIN E _SIZE ];30
// count the number of lines in the file31
while ( fgets ( buffer , LINE_SIZE , infptr ) != NULL )32
{33
num_lines ++;34
}35
36
fseek ( infptr , 0 , SEEK_SET );37
// return to the begi n ning of the file38
char ** lines = malloc ( s i z e o f (char *) * num_lin e s );39
int i;40
for (i = 0; i < nu m _lines ; i ++)41
{42
i f ( feof ( infptr ) )43
{44
printf (" not enough num_lines in file ! n ") ;45
fclose ( infptr ) ;46
fclose ( outfptr );47
return EXIT _FAILUR E ;48
}49
lines [i ] = malloc ( s i z e o f ( char ) * LINE_SIZE );50
fgets ( lines [i ], LINE_SIZE , infptr );51
}52
fclose ( infptr ) ;53
54
int total_ length = 0;55
for (i = 0; i < nu m _lines ; i ++)56
{57
total _length += my_strlen ( lines [ i ]) ;58
}59
// count the length of each line60
i f ( strcmp ( argv [1] , " strlen ") == 0)61
{62
for (i = 0; i < nu m _lines ; i ++)63
{64
fprintf ( outfptr , " length : %d n" ,65
my_strlen ( lines [ i]) );66
}67
}68
/* for each line , count the occur r ence of the first69
letter in the line */70
i f ( strcmp ( argv [1] , " countchar " ) == 0)71
{72
for (i = 0; i < nu m _lines ; i ++)73
{74
fprintf ( outfptr , " count (% c): %d n" , lines [i ][0] ,75
Programming Problems and Debugging 103
my_co untchar ( lines [ i], lines [ i ][0]) );76
}77
}78
i f ( strcmp ( argv [1] , " strupper ") == 0)79
{80
for (i = 0; i < nu m _lines ; i ++) {81
my_str upper ( lines [i ]) ;82
fprintf ( outfptr , "% s" , lines [i ]) ;83
}84
}85
86
for (i = 0; i < nu m _lines ; i ++)87
{88
free ( lines [i ]) ;89
}90
free ( lines );91
fclose ( outfptr );92
return EXIT _SUCCES S ;93
}94
The if condition at line 9 checks whether or not the program has three arguments in
addition to the program’s name. For now, we do not need to worry about the code between
lines 15 and 59. These lines read the input file line by line. We will return to this subject later.
Line 61 checks the command in argv[1]. If the command is “strlen”, then this program
calls my strlen for each line and prints the length to the output file. In similar fashion,
line 71 checks whether argv[1] is “countchar”. Line 76 calls my countchar by using each
line as the string and the first character of the line as the character. Line 82 converts the
characters in each line to uppercase.
When running the program with this command
$ ./mystring strlen input output strlen
the output is stored in the file called output strlen. The first four lines of the file are
length : 631
length : 702
length : 703
length : 694
The original article has a blank line at the eleventh line. A blank line means that it only
has the new line character n’. Thus, this line actually has one character. Similarly, line
21 also has one character. When running the program with this command
$ ./mystring strlen input output countchar
the output is stored in the file called output countchar. The first four lines of the file are
count (I ): 11
count (n ): 62
count (n ): 33
count (d ): 14
This is the final command
$ ./mystring strlen input output strupper
104 Intermediate C Programming
and the first four lines of the correct output are
IF WE CO NSIDER THAT PART OF THE THEORY OF RE L ATIVI T Y WHICH MAY1
NOW ADAYS IN A SENSE BE R EGARD ED AS BONA FIDE SCIENT IFIC KNOWLEDGE , WE2
NOTE TWO ASPECTS WHICH HAVE A MAJ OR BEAR ING ON THIS THEORY . THE WHOLE3
DEVE LOPMENT OF THE THEORY TURNS ON THE Q UESTI ON OF WHET HER THERE ARE4
7.1.5 Makefile
The Makefile should look familiar:
GCC = gcc1
CFLAGS = -g - Wall - Wshadow2
OBJS = mystring . o main . o3
HDRS = mystring . h4
VAL = val g ri nd -- tool = memcheck -- leak - check = full5
VAL += -- verbose -- log - file =6
7
mystring : $ ( OBJS ) $ ( HDRS )8
$( GCC ) $ ( CFLAGS ) $( OBJS ) -o $@9
10
.c .o:11
$( GCC ) $ ( CFLAGS ) -c $ *. c12
13
clean :14
rm -f mystring $ ( OBJS ) out_ * log *15
16
testall : test0 test1 test217
18
test0 : mystring19
$( VAL ) log0 ./ mystri n g strlen input out_len20
diff -q out_len expec ted_st rlen21
22
test1 : mystring23
$( VAL ) log1 ./ mystri n g count c har input ou tput_ c ountc har24
diff -q ou tput_ countc har expe cted_ count char25
26
test2 : mystring27
$( VAL ) log2 ./ mystri n g strupper input out_upper28
diff -q out_u p per e xpect ed_st ruppe r29
This Makefile introduces several new concepts:
Line 6 appends more options to the symbol VAL. This approach makes it easy to add
a symbol with many options.
The symbol $@ is used on line 9. It means the symbol before the : at line 8. In this
case, the $@ means mystring. Using $@ is a convenient way to manage rules.
Lines 11 and 12 mean “If an object file is needed, compile the corresponding .c file.”
It determines the object files on an as-needed basis. In this case, mystring depends on
OBJS and it depends on mystring.o and main.o. To invoke the mystring rule, make
will ensure that both mystring.o and main.o are up to date. If they need updating,
then the rule on lines 11 and 12 is invoked in order to generate the object files from
the corresponding .c file. Lines 11 and 12 are equivalent to the following:
Programming Problems and Debugging 105
mystring.o: mystring.c
$(GCC) $(CFLAGS) -c mystring.c
main.o: main.c
$(GCC) $(CFLAGS) -c main.c
If a program requires many object files, lines 11 and 12 can shorten Makefile signifi-
cantly.
7.1.6 mystring.c
The following is a reference solution for mystring.c:
// mystrin g . c1
#in clude " mystring .h "2
#in clude < ctype .h >3
int my_strlen ( const char * str )4
{5
int len = 0;6
while ( str [ len ] != 0 )7
{8
len ++;9
}10
return len ;11
}12
13
int my_cou ntchar ( const char * str , char ch )14
{15
int count = 0;16
while (* str != 0 )17
{18
i f (* str == ch )19
{20
count ++;21
}22
str ++;23
}24
return count ;25
}26
27
void my_stru pper ( char * str )28
{29
while (* str != 0 )30
{31
* str = toupper (* str ) ;32
str ++;33
}34
}35
36
char * m y_strchr ( const char * str , char ch)37
{38
int ind = 0;39
106 Intermediate C Programming
while ( str [ ind ] != 0 )40
{41
i f ( str [ ind ] == ch )42
{43
return (& str [ ind ]) ;44
}45
ind ++;46
}47
// if the program reaches here , ch is not in str48
return NULL ;49
}50
The argument str stores the address of the first element of the input string. Since a
string is an array of characters, we treat str as an array, as shown at line 7. We can also
treat str as a pointer, as shown at lines 17, 19, 23, 30, 32, and 33. As you can see, lines 7, 17,
and 30 use the null terminator character, 0’, to determine the end of the input strings.
Lines 17, 19, and 30 read the value at the address stored in str. This is the third usage of *
described in Table 4.1. Both lines read the value at that address. Line 23 increments str so
that it points to the next character in the array. Line 32 both reads from and writes to the
address. At the right side of =, it reads the value. At the left side of =, it writes the value.
Test your understanding of the program by answering this question: What happens
if lines 22 and 23 are exchanged (moving str ++; into the if condition right under
count ++;)? Is function my countchar still correct? Why?
7.1.7 Using const
The arguments of my countchar say that str is a constant. However, line 23 modifies
str. The seeming contradiction happens because const can be applied in two different
ways, with different meanings. The following example illustrates with two pointers chptr1
and chptr2:
// const .c1
#in clude < stdio .h >2
#in clude < stdlib .h >3
#in clude < string .h >4
int main ( i n t argc , char * argv [])5
{6
char str1 [20];7
char str2 [20];8
strcpy ( str1 , " First " );9
strcpy ( str2 , " Second ") ;10
const char * chptr1 = & str1 [0]; // const before char11
char * const chptr2 = & str1 [0]; // const after char12
// * chptr1 = C ; // not allowed13
* chptr2 = C ; // OK14
chptr1 = & str2 [0]; // OK15
// chptr2 = & str2 [0]; // not allowed16
return EXIT _SUCCES S ;17
}18
Both chptr1 and chptr2 are pointers and their values store the address of the first
element of str. The following shows the call stack. For simplicity, we do not show argc and
argv.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset