Table of Contents for
Intermediate C Programming

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Intermediate C Programming by Yung-Hsiang Lu Published by CRC Press, 2015
  1. Front Cover
  2. Contents (1/2)
  3. Contents (2/2)
  4. List of Figures (1/2)
  5. List of Figures (2/2)
  6. List of Tables
  7. Foreword
  8. Preface
  9. Author, Reviewers, and Artist
  10. Rules in Software Development
  11. Source Code
  12. I. Computer Storage: Memory and File
  13. 1. Program Execution (1/2)
  14. 1. Program Execution (2/2)
  15. 2. Stack Memory (1/5)
  16. 2. Stack Memory (2/5)
  17. 2. Stack Memory (3/5)
  18. 2. Stack Memory (4/5)
  19. 2. Stack Memory (5/5)
  20. 3. Prevent, Detect, and Remove Bugs (1/2)
  21. 3. Prevent, Detect, and Remove Bugs (2/2)
  22. 4. Pointers (1/6)
  23. 4. Pointers (2/6)
  24. 4. Pointers (3/6)
  25. 4. Pointers (4/6)
  26. 4. Pointers (5/6)
  27. 4. Pointers (6/6)
  28. 5. Writing and Testing Programs (1/4)
  29. 5. Writing and Testing Programs (2/4)
  30. 5. Writing and Testing Programs (3/4)
  31. 5. Writing and Testing Programs (4/4)
  32. 6. Strings (1/3)
  33. 6. Strings (2/3)
  34. 6. Strings (3/3)
  35. 7. Programming Problems and Debugging (1/4)
  36. 7. Programming Problems and Debugging (2/4)
  37. 7. Programming Problems and Debugging (3/4)
  38. 7. Programming Problems and Debugging (4/4)
  39. 8. Heap Memory (1/3)
  40. 8. Heap Memory (2/3)
  41. 8. Heap Memory (3/3)
  42. 9. Programming Problems Using Heap Memory (1/4)
  43. 9. Programming Problems Using Heap Memory (2/4)
  44. 9. Programming Problems Using Heap Memory (3/4)
  45. 9. Programming Problems Using Heap Memory (4/4)
  46. 10. Reading and Writing Files (1/3)
  47. 10. Reading and Writing Files (2/3)
  48. 10. Reading and Writing Files (3/3)
  49. 11. Programming Problems Using File (1/2)
  50. 11. Programming Problems Using File (2/2)
  51. II. Recursion
  52. 12. Recursion (1/4)
  53. 12. Recursion (2/4)
  54. 12. Recursion (3/4)
  55. 12. Recursion (4/4)
  56. 13. Recursive C Functions (1/4)
  57. 13. Recursive C Functions (2/4)
  58. 13. Recursive C Functions (3/4)
  59. 13. Recursive C Functions (4/4)
  60. 14. Integer Partition (1/5)
  61. 14. Integer Partition (2/5)
  62. 14. Integer Partition (3/5)
  63. 14. Integer Partition (4/5)
  64. 14. Integer Partition (5/5)
  65. 15. Programming Problems Using Recursion (1/5)
  66. 15. Programming Problems Using Recursion (2/5)
  67. 15. Programming Problems Using Recursion (3/5)
  68. 15. Programming Problems Using Recursion (4/5)
  69. 15. Programming Problems Using Recursion (5/5)
  70. III. Structure
  71. 16. Programmer-Defined Data Types (1/6)
  72. 16. Programmer-Defined Data Types (2/6)
  73. 16. Programmer-Defined Data Types (3/6)
  74. 16. Programmer-Defined Data Types (4/6)
  75. 16. Programmer-Defined Data Types (5/6)
  76. 16. Programmer-Defined Data Types (6/6)
  77. 17. Programming Problems Using Structure (1/4)
  78. 17. Programming Problems Using Structure (2/4)
  79. 17. Programming Problems Using Structure (3/4)
  80. 17. Programming Problems Using Structure (4/4)
  81. 18. Linked Lists (1/3)
  82. 18. Linked Lists (2/3)
  83. 18. Linked Lists (3/3)
  84. 19. Programming Problems Using Linked List (1/2)
  85. 19. Programming Problems Using Linked List (2/2)
  86. 20. Binary Search Trees (1/4)
  87. 20. Binary Search Trees (2/4)
  88. 20. Binary Search Trees (3/4)
  89. 20. Binary Search Trees (4/4)
  90. 21. Parallel Programming Using Threads (1/5)
  91. 21. Parallel Programming Using Threads (2/5)
  92. 21. Parallel Programming Using Threads (3/5)
  93. 21. Parallel Programming Using Threads (4/5)
  94. 21. Parallel Programming Using Threads (5/5)
  95. IV. Applications
  96. 22. Finding the Exit of a Maze (1/5)
  97. 22. Finding the Exit of a Maze (2/5)
  98. 22. Finding the Exit of a Maze (3/5)
  99. 22. Finding the Exit of a Maze (4/5)
  100. 22. Finding the Exit of a Maze (5/5)
  101. 23. Image Processing (1/3)
  102. 23. Image Processing (2/3)
  103. 23. Image Processing (3/3)
  104. 24. Huffman Compression (1/10)
  105. 24. Huffman Compression (2/10)
  106. 24. Huffman Compression (3/10)
  107. 24. Huffman Compression (4/10)
  108. 24. Huffman Compression (5/10)
  109. 24. Huffman Compression (6/10)
  110. 24. Huffman Compression (7/10)
  111. 24. Huffman Compression (8/10)
  112. 24. Huffman Compression (9/10)
  113. 24. Huffman Compression (10/10)
  114. A. Linux
  115. B. Version Control
  116. C. Integrated Development Environments (IDE) (1/3)
  117. C. Integrated Development Environments (IDE) (2/3)
  118. C. Integrated Development Environments (IDE) (3/3)
158 Intermediate C Programming
i f ( onechar == C )5
charcount [2] ++;6
i f ( onechar == D )7
charcount [2] ++;8
i f ( onechar == E )9
charcount [3] ++;10
Fifty-two conditions are needed. The problem should be obvious: It is easy to make mistakes.
If fact, there are mistakes in the code above. Can you detect them easily? There is a general
principle in writing good programs: Do not copy-paste code. Write DRY code. DRY stands
for “Don’t Repeat Yourself”. The opposite of DRY code is WET code, which stands for
“We Enjoy Typing”.
There are many reasons to follow the DRY principle. If you copy-paste code, then you
increase the chances of mistakes. This is especially true when the code is modified after it is
written. Once we have two (or more) pieces of WET code, testing, debugging and improving
the code becomes more difficult. We need to remember to change all places that the code is
repeated. If we forget to change some places, then the program will surprise you: In some
situations, the program is correct, but in others it fails.
There are many simple and clear solutions that avoid WET code. For example, if the
two (or more) pieces of code are identical, then create a function and call it twice. If they
are mostly similar but with a few differences, then the function’s arguments can handle the
differences. Spending some time fixing WET code usually helps tremendously in developing
good test cases, since the programmer must think about and ultimately understand the
code. That also helps with debugging, since you will be more familiar with how the program
should behave as you step through it line by line.
Line 49 is the reverse way of using the ASCII values. If the index is 0, it corresponds to
’A’ so the value of ’A’ is added. The output of this program will look something like:
A: 39
B: 1
C: 41
D: 16
E: 69
F: 38
11.3 Counting the Occurrences of a Word
This program takes three arguments:
1. argv[1]: The name of the input file.
2. argv[2]: The name of the output file.
3. argv[3]: A word to be searched for.
This program detects and counts the occurrences of the word in an input file. If a line
in the input file includes the word, the program writes that line to the output file. After
checking all lines in the input file, the program writes the total count to the output file. We
must first think about how words are counted. If the search word is “eye” and a line in the
input file contains “eyeye”, do you count 1 or 2? Both definitions are acceptable in different
circumstances and we need to decide which definition to use. We will explain how to handle
the differences. For simplicity, each line in the input file contains at most 80 characters (and
Programming Problems Using File 159
thus needs memory for 81 characters). The program does not count a word that spans two
or more lines. The program uses strstr to search a word within a line.
// countst r . c1
#in clude < stdio .h >2
#in clude < stdlib .h >3
#in clude < string .h >4
#d ef in e LINE _ LENGTH 815
int main ( i n t argc , char * argv [])6
{7
i f ( argc < 4) // input word output8
{9
return EXIT _FAILUR E ;10
}11
// open the input file12
FILE * infptr ;13
infptr = fopen ( argv [1] , "r ");14
i f ( infptr == NULL )15
{16
return EXIT _FAILUR E ;17
}18
// open the output file19
FILE * outfptr ;20
outfptr = fopen ( argv [2] , "w ");21
i f ( outfptr == NULL )22
{23
fclose ( infptr ) ;24
return EXIT _FAILUR E ;25
}26
int count = 0;27
char oneline [ LINE_L ENGTH ];28
while ( fgets ( oneline , LINE_LENGTH , infptr ) != NULL )29
{30
i f ( strstr ( oneline , argv [3]) != NULL )31
{32
fprintf ( outfptr , "% s" , oneline );33
}34
char * chptr = oneline ;35
while ( chptr != NULL )36
{37
chptr = strstr ( chptr , argv [3]) ;38
i f ( chptr != NULL )39
{40
count ++;41
// if " eyeye " counts as two " eye "42
chptr ++;43
// if " eyeye " counts as one " eye "44
// chptr += strlen ( argv [3]) ;45
}46
}47
}48
160 Intermediate C Programming
fprintf ( outfptr , "% d\n ", count );49
// close the input file50
fclose ( infptr ) ;51
// close outupt file52
fclose ( outfptr );53
return EXIT _SUCCES S ;54
}55
Lines 41 and 45 implement the two definitions. Line 41 increments the address by only
one and searches again. Line 45 increments the address by length of the string. So “eyeye”
contains only one “eye”, because after finding the first “eye”, the program continues its
search from “ye”.
11.4 How to Comment Code
Almost every programming class requires that students comment their code. Addition-
ally, almost every programming book tells readers to comment their code. However, very
few classes or books say how to comment code. Writing comments is like writing an article
and it is difficult to grade comments. Comments are about communicating with the readers
of the code: Style and clarity are important. If comments do not explain code, then they are
not useful. It is not yet possible to check comments’ usefulness by using computer programs.
Grading comments by human eyes (usually by teaching assistants) is labor-intense. As a
result, some professors do not consider comments in grading and most students do not take
comments seriously. Sometimes students even write comments like “because the professors
tell us so.” Some students ask me, “Do I need to write comments for you?” My answer is,
“You need to write comments for yourself.” If your program is longer than, say, 20 lines,
you need to write comments before writing code.
This book frequently lists the steps before writing a program. These steps should be
written in the comments of the code. Remember that programs are written to solve prob-
lems. The programs implement solutions. The solution must be known before the first line
of code is typed. Writing a program without a solution first is like laying bricks for a house
before knowing how many rooms the house will have. Almost everyone agrees that a house
needs to be designed before it is built. Write code after you know the solution. It is good
practice to think about the solution, write down the steps, explain your thinking process in
comments.
In addition to explaining the steps, comments are needed to explain specifics of how
functions work: what is required of the arguments, and what the return result means.
Manual pages are good examples of this. Consider the manual page for fgets:
char *fgets(char *s, int size, FILE *stream);
fgets() reads in at most one less than size characters from
stream and stores them into the buffer pointed to by s. Reading
stops after an EOF or a newline. If a newline is read, it is stored
into the buffer. A terminating null byte (’\0’) is stored after the
last character in the buffer.
fgets() return s on success, and NULL on error or when end of
file occurs while no characters have been read.
Programming Problems Using File 161
This explains the arguments, the behavior of the function, and the return value. Notice
how clear and dense the text is. No word is wasted.
A common mistake is to repeat information that is obvious from the syntax. The fol-
lowing comment is unnecessary:
/* This function has two arguments . Both are integers .1
The funct i on returns an integer . */2
int func ( i n t a , in t b );3
Compare with the informative comment:
/* The functi o n returns1
1 if a > b2
0 if a == b3
-1 if a < b4
*/5
int func ( i n t a , in t b );6
Comments should provide some information that is unavailable from the syntax. Com-
ments are important when explaining complex concepts. The example below shows a call
stack:
/*
---------------------------------------
| Frame | Symbol | Address | Value |
---------------------------------------
| | z | 103 | 5 |
| f2 | y | 102 | 8 |
| | x | 101 | -7 |
---------------------------------------
*/
We can also use comments to show the flow of a function:
/*
open input file -> count the number of lines -|
|
----------------------------------------------|
|
---> allocate memory -> return to the beginning of the file
*/
The following is also good for those who do not like drawing:
/*
1. open input file
2. count the number of lines
3. allocate memory
4. return to the beginning of the file
*/
It should be apparent that comments can express important concepts. It takes practice
to write comments well. It is often helpful to read others’ code to see what comments are
162 Intermediate C Programming
useful, and what are merely distractions. This is important for your own code. If you read
a program written six months ago, can you understand it easily? If the meaning is not
apparent, then the commenting can be improved.
With practice, comments become a good way to further understand your code by testing
your ability to explain it. This, in turn, helps catch subtle problems, and also helps you
generate good test cases. By guiding the eye of the reader through the code, good comments
augment carefully chosen variable names, and clear syntax. Doing this shows that you have
thought deeply about the program.