Practical C Programming, 3rd edition by Steve Oualline Unconfirmed error reports are taken directly from email from readers. They have not yet been reviewed by the author or editor and solely represent the opinion of the reader. This page was updated June 8, 2005. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification UNCONFIRMED errors and comments from readers: {8} 4th paragraph, after the example: reads "statment," should be "statement". {30} Screen Shots: Because the book uses Screen Shots from Win3.1 and refers to an old compiler (version 3-5?) the instructions make no sense. This is not just one page (23-33). (47) second paragraph from the bottom, the first sentence should probably be: "Avoid complex logic like multiple nested ifs." rather than: "Avoid complex logic like multiply nested ifs." [54] Question 4-1: The code written does NOT fail on a PC running Microsoft Visual C++ V.6.0; it actually runs OK. {61} 4th paragraph, 1st sentence: tells the program to print a decimal number, but there....... Tt should say: tells the program to print an integer number, but there....... The reason being for the correction, that you are adding two integers together. Also you use %d in your printf statement, which is used with integers. (61) Example 4-7; When I entered in the program listed in example 4-7, there is a severe runtime error. The program displays a linefeed and the cursor remains on the line below my prompt. Like this: $ _ <------ a blinking cursor.. I have to Ctrl-C to get out of the program.. I am using gcc on RedHat Linux 7.0 [61] Top; In regard to the "unconfirmed error" that one reader sent in, "When I entered in the program listed in example 4-7, there is a severe runtime error. The program displays a linefeed and the curs or remains on the line below my prompt. Like this: $ _ <------ a blinking cursor.. I have to Ctrl-C to get out of the program.. I am using gcc on RedHat Linux 7.0" The program name is the same as the "rev" command. You must use a ./ before it. This one got me for a while. {65} Last paragraph (above note); char string[50]; is in the code example above the paragraph in question. It is said that this: "creates an array (string) that can contain up to 50 characters." and, "Any string up to 49 characters long can be stored in the array." The mistake is that the array is delared to be '0-50'. Which means, the string is 51 characters long, and a string up to 50 characters may be stored in it. The reader was warned of this misconception at the top of the previous page! Perhaps not a serious error that will cause an example to fail, but a real black eye for O'Reilly. Printing version: [3/01]. [71] Example 5-7:/p_array/p_array.c; I'm questioning if the program line int x,y; /* Loop indices */ is erroneous? I have the 4/00 printing. <76> signed program example; In the example on page 76, the first variable is shown as: signed char ver_short yet, later on in the program, the variable name is: very_short The "y" in the declaration of the variable was missing. [89] fib.c code; This may need to be re-filed under suggestions, but a suggested modification to the code in order to follow the KISS principle and encourage portable code: Example 6-1:fib/fib.c #include int old_number; /* previous Fibonacci number */ int current_number; /* current Fibonacci number */ int next_number; /* next number in the series */ int main() { /* start things out */ old_number = 0; current_number = 1; while (current_number < 100) { printf("%d\n", current_number); next_number = current_number + old_number; old_number = current_number; current_number = next_number; } return (0); } {101} 2nd block of code: if (operator = '+') { should read: if (operator == '+') { {146} second example; following definition contains two errors: const box pink_box={1.0, 4.5}; It should be const struct box pink_box={1,4}; box being a struct defined on previous line containing integers instead of floating point numbers. If this example is showing the possibility of misdefining the content of a const struct (int defined with float constants, thus automatically converted), this may be indicated in the example description. [191] Line 3 in `Pointers and Arrays'; The declaration char *array_ptr = &array[0]; is wrong. It should be char *array_ptr = array[0]; This is probably a typo but could be very confusing for beginners (and make it difficult to understand an otherwise excellent explanation). {192-193} Example 13-3: A suggestion... The main point of this example is to demonstrate that elements of an array occupy contiguous locations in memory. Additionally however, the example also introduces new notation for a pointer to (the first element of) an array - i.e. it shows that "&array[0]" and "array" are the same thing. This is indeed latterly explained at the top of P193, however can I suggest that this section would be more appropriately placed BEFORE the example? (Before reading P193, "array" only meant the string to me - i.e. "0123456789". This clearly had no meaning in the context of the example, and I spent some time going backwards looking for an explanation, before giving up and deciding to read on). <198> First pargraph; The second sentence reads: We then split the string by replacing the slash (/) with an end of string (NUL or \0). NUL should be changed to NULL {198} Example 13-10: In the line below the box describing the program, the * should be immediately before the string_ptr, with no space between. {199} Bottom just above Question 13-1; printf("First:%s Last:%s\n", first_ptr, lastptr); Should read printf("First:%s Last:%s\n", first_ptr, last_ptr); As is you get the following compile error: `lastptr' undeclared {207} The book suggests that implicit conversion from float to double always happens in real-number arithmetic. While this is true for standard library functions, ANSI C prototyping should allow to write functions with type float, which compute with single precision (see Numerical Recipes in C, pp 24-25). Even some Kern. & Rich. C compilers can suppress the conversion by flag. {218} There is a syntax error with the fread() and fwrite() functions in chapter 14: File I/O (page 218). This may not be incorrect with the particular C libraries you were using while writing this book, but with the GNU libraries, the fwrite/fread syntax is like this: SYNOPSIS #include size_t fread( void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite( const void *ptr, size_t size, size_t nmemb, FILE *stream); Whereas, in the book syntax, the size and nmemb elements are mixed around. fread(ptr, nmemb, size, stream); This is really not that big of an issue, because the GNU man page corrected me, but the syntax difference resulted in about a day of bug tracking and hair pulling. It would probably be in the best interest of your readers to post this on the website, because it can be quite confusing for anyone using GNU/linux. {221} table 14-3 Standard Unbuffered Files; If I am not mistaking 'standard out' is a standard buffered file and shouldn't be included in the table of standard unbuffered file s. {224} Example 14-5: Two of the fprintf() functions on the page should have stderr as the output file, but instead start right in with the error message. So, currently, the first one reads: fprintf("Error:Unable to open %s\n", argv[1]); but should read: fprintf(stderr, "Error:Unable to open %s\n", argv[1]); The second is: fprintf("Error:Unable to open %s\n", argv[2]); but should read: fprintf(stderr, "Error:Unable to open %s\n", argv[2]); [239] code listing; missing declaration for debug_ptr {241} Example 15-6: I typed in the program in Example 15-6, and found a couple of things that prevented it from compiling. First, you need a prototype of the get_data function at the top to make it "void" instead of defaulting to int when the compiler first finds it on line 12. Second, the argument for get_data needs to be a pointer. So the prototype would be: void get_data(int *); and line 28 would read: void get_data(int *data) {252} The termination condition in ´binary search reads: low>=high but should read: low>high {257} re: C & Optimization: The author gives the advice to order loops over a 2D matrix the way that the innermost loop is most complex. Anyway, if a given matrix is large, this praxis will lead to a very bad cache-efficiency, because the stride of the program rises from 1 (right variable corresponds with inner loop) up to the size of the outer column. Therefore it's better to change columns - again: right variable should correspond with the inner loop... (260) Example 15-18: In glibc 2.2, the memset() function is not defined in memory.h, as it's listed here. Instead, it should be string.h. {p 274} 6th paragraph; the line currently reads as: Is that Celsius or Kelvin (absolute zero or Celsius-273)? better would be: Is that Celsius or Kelvin (Kelvin+273 or absolute zero)? (282) bottom of page: The last sentence has a typo. It reads: however, doing so prevents us from trying to used freed memory "used" should be "use." {286} Line -7 of code: current_ptr = (*current_ptr)->next_ptr; should read: current_ptr = (*current_ptr).next_ptr; {290} Example about inserting new element: The command: if ( item >= insert_ptr->data ) break; should be: if ( item <= insert_ptr->data) break; If the item is smaller than the insert_ptr->data, we then insert the item. {290} code listing: The program listing for entering new elements into the double linked list is "very" incomplete. It appears as though a large portion of the code was not printed. [295] Bottom (line of code just above the return statement); (*node)->word = save_string(word); should be chaged to (*node)->data = save_string(word); [300] End of listing words/words.c; The allocated memory for neither the tree structure nor the strings is freed. AUTHOR: The reader is correct in his observation, however because of the nature of the program, a free is not needed. The program fills the data structure, uses it, and exits. There is no need to reclaim the memory used. It is a good idea to do this, but this concept is a little more advanced that the what we are discussing at this point in the book. (301) code at bottom of page: The second line of code says struct move this_mode; It should be struct move this_move; {306} 2nd paragraph; The second file-listing is called count.c, but the text following it refers to counter.c In the listing itself, there's a missing opening parenthesis '('. It should read: for (index = 0; index < 10; index++) inc_counter(); {359} code for in_file.h: In the description for input_file, one of the functions listed is read_char. Well, later on in the code it's used as in_read_char. I assume that since all other functions start with in_ that the description is incorrect. {363} right above the ch_type.h file: The function that begins on the previous page, in_read_char, should not end with a semicolon after the }. (367) top of page: This is minor, but in the comments for T_L_PAREN, T_R_PAREN, T_L_CURLY, and T_R_CURLY, you use double quotes "" where everywhere else you've been using single quotes ''. (367) middle of page: To the right of #define TRUE 1, there's a comment line that reads: /* Define a simple TRUE/FALSE values */ Well, the "a" represents a single value, but the word "values" is plural. (373) description line for bc_init: The bc_init function is great, but the description line is pc_init, not bc_init. {373} bc_init function: The bc_init function should not have a trailing semicolon after the right curly. {374} declaration of cc_init: The end of the cc_init declaration in the middle of the page should not have a trailing semicolon. ?Reader Suggestion? I think that the book would benefit greatly from an appendix containing a listing of the functionality of some of the standard header files.