C in a Nutshell by Peter Prinz & Tony Crawford This errata page lists errors outstanding in the most recent printing. If you have technical questions or error reports, you can send them to booktech@oreilly.com. Please specify the printing date of your copy. This page was updated June 6, 2007. 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 Confirmed errors: {23} Table 2-4; The maximum value listed for a four byte unsigned int is shown as: 2,147,483,647. That would be correct for a four byte signed int, but for a four byte unsigned int the value should be: 4,294,967,295. (57) line 2: Change "expression" to "assignment" (68) last paragraph, line 5: Change "... if the left operand yields 1; " to "... if the left operand yields a non-zero value; " {75} second to last line before the heading "Other Operators" (last line of the three code example lines): Add missing right parenthesis before the dot: (*(arrArticle+i)).number {106} The 6th non-blank line of Example 7-7 (the body of function 'swapf'); The last occurrence of 'p2' should be preceded by an asterisk. {109} under the list item "void va_end( va_list, argptr );", line 3: Change "a function pointer" to "an argument pointer" (113) in both code fragments, middle and bottom of page: Change "myarray" to "myArray" in a total of three instances (117) Code snippet, middle of page; if ( sizeof(str1) >= ( strlen( str1 ) + strlen( str2 ) + 1 ) should be: if ( sizeof(str1) >= ( strlen( str1 ) + strlen( str2 ) + 1 ) ) {127} bottom/128, top: Omit "(see "Implicit Pointer Conversion" in Chapter 4)" and at the end of the paragraph (page 128, top), add: "(see "Comparative Operators" in Chapter 5)" ^ {129} bottom, last line before the example: Change "a constant pointer does not necessarily point to a constant object:" to "a constant pointer is not the same thing as a pointer to a constant object:" {131} bottom, line 1 of the example: Change "int a[200];" to "char a[200];" {140} line 7 (the second one-line code snippet): Change struct Date { short year, month, day; }; to struct Date { short month, day, year; }; [[to match subsequent initialization on p. 144]]. {172} Third bullet point; Please change the third bullet point as follows * Nodes in a binary tree are placed according to this rule: the value of a node is greater than or equal to the values of any descendant in its left branch, and less than or equal to the value of any descendant in its right branch. (181) line 5: Change "Example 12-2" to "Example 12-3" {192} bottom: If possible, insert two "include" directives before the searchFile function begins, as follows: // ------------------------------------------------- #include #include int searchFile( FILE fpIn, const char *keyword ) {194} line 16 Change "ARRAY_LEN" to "ARRAY_LEN * sizeof(Record_t)" and move the comment up a line, thus: else //Create the buffer. if ((pArray = malloc( ARRAY_LEN * sizeof(Record_t) )) == NULL ) error_exit( 3, "Insufficient memory."); {194} line 32 (8 lines above the "Formatted Output" heading): Change if ( i > 0 ) // Write the remaining records. to if ( i > 0 && !ferror(fpOut) ) // Write the remaining records. {205} bottom, second to last text line before example: Change "message.txt" to "messages.txt" {264} top: There are four more functions that actually belong in Table 16-18. They are declared in inttypes.h, so that the table should have another column on the right. Furthermore, the paragraph introducing the table needs a couple more sentences to introduce these functions. These changes may be too extensive for the English version, but they have been made in preparing the German version. Here is how the table and its introduction should look, following on the existing sentence "The functions for char strings are declared in the header stdlib.h, and those for wide strings in wchar.h.": Four new functions introduced in C99, declared in inttypes.h, convert a string into the widest available signed or unsigend integer type, intmax_t or uintmax_t. Table 16-18: Conversion of numeral strings Conversion Functions in stdlib.h Functions in wchar.h Functions in inttypes.h -------------------------------------------------------------------------------------------------------- String to int atoi() String to long atol(), strtol() wcstol() String to unsigned long strtoul() wcstoul() String to long long atoll(), strtoll() wcstoll() String to unsigned long long strtoull() wcstoull() String to intmax_t strtoimax() wcstoimax String to uintmax_t strtoumax() wcstoumax String to float strtof() wcstof() String to double atof(), strtod() wcstod() String to long double strtold() wcstold() (287) Section "carg", line 1 of the Example: Change "real" to "complex", thus: /* Convert a complex number from Cartesian to polar coordinates. */ {288} section "casinh", the Synopsis line: Change "cosine" to "sine", thus: Calculates the inverse hyperbolic sine of a number (288) end of page: Omit the last part of the "See Also" list from the last semicolon on: i.e., let the list end with "and tanh()" {290} section "cbrt", last line of the example: Change "sma_km" to "dist_km", thus: printf("Then your planet must be about %.0lf km from the Sun.\n", dist_km ); {295} Insert a section for the function clog() before section "conj" (if possible). Contents as follows (keeping it short): clog C99 ___________________________________________________________________ Calculates the natural logarithm of a complex number #include double complex clog( double complex z ); float complex clogf( float complex z ); long double complex clogl( long double complex z ); The clog() function returns the logarithm to base e of its complex argument. The imaginary part of the return value is in the interval [-pii, +pii] Example double complex z = clog( -1.0 ); // z = 0.0 + 3.1415926 * I See Also: cexp(), cpow() (312) section "feholdexcept", lines 2 and 8 of the example: Change "hypoteneuse" to "hypotenuse" in two instances. {315} top, second to last line of the example for feraiseexcept(): Change "%flags X.\n" to "flags %X.\n" (316) section "fesetround": Add "C99" tag at right in the heading line, thus: fesetround C99 ________________________________________________________ {318} section "fflush": First paragraph, third sentence: Change "If the file is only opened for reading, the function clears the buffer." to "If the file is only opened for reading, the behavior of fflush() is not specified by the standard. Most implementations simply clear the input buffer." Insert a sentence at the beginning of the second paragraph: "The argument passed to fflush() may be a null pointer. In this case, fflush() flushes the output buffers of all the program's open streams. {323} section "fgetws", first text paragraph, line 3: Change "char pointer" to "wchar_t pointer" {334} bottom, last text paragraph, first line: Change "of the input string,tony:x:1002:1002:, and copies" to "of the input string,tony:x:1002:31:, and copies" {337} lines 21 to 33 of the example code. (Code change because fgets() returns NULL at end-of-file): Change 21 if ( ! fgets(sLine,MAX_LINE,fp )) // Read next line from file. 22 { 23 fprintf(stderr,"Unable to read from %s \n",argv [2 ] )); 24 break; 25 } 26 } while ( strstr( sLine, argv[1] ) == NULL ); // Test for argument in sLine. 27 28 /* Dropped out of loop: Found search keyword or EOF */ 29 if ( feof(fp) ) 30 { 31 fprintf( stderr,"Unable to find \"%s\" in %s\n", argv[1], argv[2] ); 32 rewind(fp); 33 } to if ( ! fgets(sLine,MAX_LINE,fp )) // Read next line from file. { break; } } while ( strstr( sLine, argv[1] ) == NULL ); // Test for argument in sLine. /* Dropped out of loop: Found search keyword or EOF */ if ( feof(fp) || ferror(fp) ) { fprintf( stderr,"Unable to find \"%s\" in %s\n", argv[1], argv[2] ); rewind(fp); } In other words, delete line 23 of the example completely, and and insert "|| ferror(fp) " in line 29. (339) lines 2 and 3: Change "under wchar.h in Chapter 15" to "in table 16-2" {343} line 2 of the example for gets: Delete the line: char *ptr = buffer; [[because ptr is not used in the example]] {344} section "getwchar", last two sentences of the text paragraph: Change "file" to "stream" and "stdin" (as at getchar), thus: "A return value of WEOF indicates an error or an attempt to read past the end of the input stream. In these cases the function sets the error or end-of-file flag for stdin as appropriate." {345} text paragraph after the description of the structure struct tm, and before the "Example" heading: Change "as a" to "in", move "usually", and add a comma, thus: "The type time_t is defined in time.h, usually as equivalent to long or unsigned long." {350} section "isdigit": Delete one and a half sentences, which span a paragraph break: "The results depend on the current locale setting for the localization category LC_CTYPE, which you can query or change using the setlocale() function. In the default locale C, " The resulting single text paragraph should read: The function isdigit( ) tests whether its character argument is a digit. isdigit() returns a nonzero value (that is, true) for the ten characters between '0' (not to be confused with the null character, '\0') and '9' inclusive. Otherwise, the function returns 0 (false). (358) section "isunordered": In the "isunordered" section heading line, add the "C99" tag at right. (362) section "iswblank": In the "iswblank" section heading line, add the "C99" tag at right. {364} section "iswdigit", second paragraph of descriptive text: Delete the first two lines of the paragraph and capitalize the "The" that follows. The resulting second paragraph should read: The digit wide characters are L'0' (not to be confused with the null character L'\0') through L'9'. The iswdigit() function returns a nonzero value (that is, true) if the wide character represents a digit; if not, it returns 0 (false). (365) section "iswlower", last sentence of first paragraph of descriptive text: Change "islower()" to "iswlower()". {368} top (above the section header "iswxdigit") At the end of the "See Also" list for isxdigit, delete the following repeated phrase: "; the extensible wide-character classification function, iswctype()" I.e., the "See Also" list should end after "setlocale()". (375) bottom, sectiom "log1p": In the last two lines, which show the prototypes of log1pf() and log1pl(), delete the "(C99)" tags at right. (Because *all three* function variants are C99, as marked in the section header!) {376} section "log2": Delete the "(C99)" tag to the right of these two function prototypes: float log2f( float x ); long double log2l( long double x ); {380} Example: Change lines 8, 12, and 17 of the example code. Change from this: 8 while ( NULL != fgets( buffer, fp_in ) ) 9 { 10 if ( head == NULL ) /* Chain not yet started; add first link */ 11 { 12 head = malloc( sizeof(struct linelink)); 13 if ( head != NULL ) 14 { 15 head->line = malloc( strlen( buffer ) + 1 ); 16 if ( head->line != NULL ) 17 strcpy( head->line, buffer ); ... to this: while ( NULL != fgets(buffer, sizeof(buffer), fp_in )) { if ( head == NULL ) /* Chain not yet started; add first link */ { head = tail = malloc( sizeof(struct linelink)); if ( head != NULL ) { head->line = malloc ( strlen( buffer ) + 1 ); if ( head->line != NULL ) { strcpy( head->line, buffer); head->next = NULL; } {383} section "mbrtowc", second text paragraph: Add the following sentence at the end of the paragraph: "If no valid multibyte character is found within the maximum length specified by the maxsize argument, mbrtowc() returns -2." [[maxsize in monospaced italics; mbrtowc in monospaced font.]] {395} subsection "Conversion specification syntax", after the syntax statement: Change the first descriptive sentence to include '#' in the possible flag characters, thus: "The flags consist of one or more of the characters +, ' '(space), -, 0, or #." {397} just below the middle of the page: Change "256" to "512" in the example code and in the output, thus: printf("512 times pi cubed equals %.2e, or %.2a.\n", bignumber, bignumber); This printf() call produces the following output: 512 times pi cubed equals 1.59e+04, or 0x1.f0p+13. - Same location, first line of text after the example's output edited above: Delete "of [Greek letter pi] ", thus: "The first representation shown here, produced by" etc. (399) section "putc", subsection "See Also": Delete "C99 ", leaving "the functions to read and write" (400) section "putchar", subsection "See Also": Again, delete "C99 ", leaving "the functions to read and write" {412} bottom: The second and third items in the bullet list need to be amended as follows: . A matching failure: a non-whitespace character in the input failed to match the conversion specification or the character in the corresponding position in the format string. . An input failure: no further characters could be read from the input, or an encoding error occurred. {418} section "setvbuf", list item "_IOLBF": Change to: _IOLBF Line buffered: On read and write operations, characters are placed in the buffer until one of them is a newline character, or until the buffer is full. Then the contents of the buffer are written to the stream. The buffer is also written to the stream whenever the program requests, from an unbuffered stream or a line-buffered stream, input which requires characters to be read from the execution environment. (419) section "signal": The bullet list should be only three items; the fourth bullet item should be a plain text paragraph. {421} about the middle of the page, the code lines that begin the definition of the function sigint_handler(): Change "char c;" to "int c = 0;" (because tolower() returns int), thus: void sigint_handler(int sig ) { int c = 0; - In the same example, five lines farther down: Change three code lines from this: while (( c = tolower( getchar( ) )) != 'y' && c != 'n' ) ; if ( c == 'y' ) to this: while (( c = tolower( getchar( ) )) != 'y' && c != 'n' && c != EOF ) ; if ( c != 'n' ) (433) Table 17-10: The table entry for 'd' occurs twice, before and after 'D'. Delete the second occurrence. (435) top, line 1 of the example: Append a semicolon at the end of the line. {443} middle of page, section "strtoumax", subsection "See Also": Change first item, "strtoumax()", to "strtoimax()". {444} middle of page, in the example for section "strxfrm": Change lines 15, 17 and 18 of the code as follows: Line 15: change "originals[i]" to "stringpairs[i].original" Line 17: change "->" to "." Line 18: delete the final semicolon. In other words, change the for-loop from this: 12 for ( int i = 0; i < 8 ; i++ ) 13 { 14 stringpairs[i].xformed 15 = malloc( strxfrm( xformbuffer, originals[i], 1024 ) +1 ); 16 if ( stringpairs[i].xformed != NULL ) 17 strcpy( stringpairs[i]->xformed, xformbuffer ); 18 }; to this: for ( int i = 0; i < 8 ; ++i) { stringpairs[i].xformed = malloc( strxfrm ( xformbuffer, stringpairs[i].original, 1024 ) + 1 ); if ( stringpairs [i].xformed != NULL ) strcpy(stringpairs[i].xformed, xformbuffer); } {444} section "swprintf", in the example, code line 5: Break up the line: static wchar_t buffer[16], sign[2] = L""; into two lines as follows (because sign should not be static): static wchar_t buffer[16]; wchar_t sign[2] = L""; {450} section "toupper": Change: "The tolower() function returns" to: "The toupper() function returns" (465) line 2: Delete: ",or arrays of wide characters," leaving: "The two strings are equal." {465} section "wcscopy": In the function prototype, change "s1" to "dest" and change "s2" to "src". In the first line of the descriptive text below that, change "char" to "wchar_t". (471) section "wcsrtombs": In the function prototype at the top of the section, in the indented line beginning with "size_t", change "len" to "n". (483) section "wmemchr", first line of descriptive text: Change the italic "c" in "with the value of c" to "wc". (484) line 4: Delete "(evaluated as unsigned char) ". {486} bottom, section "wmemset": In the first line of the descriptive text (third to last line of the page), change "The memset() function" to "The wmemset() function". (487) Table 17-11, last line, right column: Delete ", no string terminator". (Do not change the similar entry two lines higher in the table.) (498) Second paragraph, last line; LIBARY_PATH should be LIBRARY_PATH. {498} Command line example after third paragraph.; The example: $gcc -lm -Wl,-M circle.c circulararea.c > circle.map does not redirect the map file to circle.map because the map output is written to stderr, not stdout. TO FIX: Change the command line example to: $gcc -lm -Wl,-Map,circle.map circle.c circulararea.c In this case the explanatory paragraph following the command line example should read: The option -Wl,-Map,circle.map on the GCC command line passes the option -Map,circle.map to the linker command line, instructing the linker to print a link script and a memory map of the linked executable to the specified file, circle.map. (503) Third paragraph, 1st sentence; "The -Wextra option also warns expressions..." should be: "The -Wextra option also warns about expressions..." ^^^^^ (523) second par.; SYMTABS = $(OBJ .o=.sym) must be SYMTABS = $(OBJ:.o=.sym) (Don't put any whitespace behind the colon.) {523}, Example 19-4, middle of page: clean: $(RM) $(OBJ) *.sym circle dcircle should read: clean: $(RM) $(OBJ) *.sym circle circle-dbg (529) in the paragraph describing the list item ".LOW_RESOLUTION_TIME", line 4: Change "low-resolution" to "high-resolution". {543} in the paragraph describing the list item ".NOTPARALLEL", last sentence: Change this: "such recursions still run parallel to the present instance, unless their makefiles also contain" to this: "the new instance of make still executes commands in parallel, unless its makefile also contains" [[My error was based on an error in the GNU Make manual. I filed a bug report, http://savannah.gnu.org/bugs/?17701]] {562} example at the top of the page, last three lines of the example: In the third to last line of the example, change "21" to "27", and In the last line of the example, change "14" to "16". The resulting three lines: 1 breakpoint keep y 0x004010e7 in swap at gdb_example.c:27 ignore next 5 hits 3 breakpoint del n 0x004010c0 in main at gdb_example.c:16