The questions answered here are divided into several categories:

1. Null Pointers 2. Arrays and Pointers 3. Order of Evaluation 4. ANSI C 5. C Preprocessor 6. Variable-Length Argument Lists 7. Lint 8. Memory Allocation 9. Structures 10. Declarations 11. Boolean Expressions and Variables 12. Operating System Dependencies 13. Stdio 14. Style 15. Miscellaneous (Fortran to C converters, YACC grammars, etc.) Section 1. Null Pointers
1. What is this infamous null pointer, anyway? A: The language definition states that for each pointer type, there is a special value -- the "null pointer" -- which is distinguishable from all other pointer values and which is not the address of any object. That is the address-of operator & will never yield a null pointer, nor will a successful call to malloc. (malloc returns a null pointer when it fails, and this is a typical use of null pointers: as a "special" pointer value with some other meaning, usually "not allocated" or "not pointing anywhere yet.") A null pointer is conceptually different from an uninitialized pointer. A null pointer is known not to point to any object; an uninitialized pointer might point anywhere. See also questions 49, 55, and 85. As mentioned in the definition above, there is a null pointer for each pointer type, and the internal values of null pointers for different types may be different. Although programmers need not know the internal values, the compiler must always be informed which type of null pointer is required, so it can make the distinction if necessary (see below). References: K&R I Sec. 5.4 pp. 97-8; K&R II Sec. 5.4 p. 102; H&S Sec. 5.3 p. 91; ANSI Sec. p. 38.

2. How do I "get" a null pointer in my programs? A: According to the language definition, a constant 0 in a pointer context is converted into a null pointer at compile time. That is, in an initialization, assignment, or comparison when one side is a variable or expression of pointer type, the compiler can tell that a constant 0 on the other side requests a null pointer, and generate the correctly-typed null pointer value. Therefore, the following fragments are perfectly legal: char *p = 0; if(p != 0) However, an argument being passed to a function is not necessarily recognizable as a pointer context, and the compiler may not be able to tell that an unadorned 0 "means" a null pointer. For instance, the Unix system call "execl" takes a variable-length, null-pointer-terminated list of character pointer arguments. To generate a null pointer in a function call context, an explicit cast is typically required: execl("/bin/sh", "sh", "-c", "ls", (char *)0); If the (char *) cast were omitted, the compiler would not know to pass a null pointer, and would pass an integer 0 instead. (Note that many Unix manuals get this example wrong.) When function prototypes are in scope, argument passing becomes an "assignment context," and most casts may safely be omitted, since the prototype tells the compiler that a pointer is required, and of which type, enabling it to correctly cast unadorned 0's. Function prototypes cannot provide the types for variable arguments in variable-length argument lists, however, so explicit casts are still required for those arguments. It is safest always to cast null pointer function arguments, to guard against varargs functions or those without prototypes, to allow interim use of non-ANSI compilers, and to demonstrate that you know what you are doing. Summary: Unadorned 0 okay: Explicit cast required: initialization function call, no prototype in scope assignment variable argument in comparison varargs function call function call, prototype in scope, fixed argument References: K&R I Sec. A7.7 p. 190, Sec. A7.14 p. 192; K&R II Sec. A7.10 p. 207, Sec. A7.17 p. 209; H&S Sec. 4.6.3 p. 72; ANSI Sec. 3. What is NULL and how is it #defined?

A: As a matter of style, many people prefer not to have unadorned 0's scattered throughout their programs. For this reason, the preprocessor macro NULL is #defined (by or ), with value 0 (or (void *)0, about which more later). A programmer who wishes to make explicit the distinction between 0 the integer and 0 the null pointer can then use NULL whenever a null pointer is required. This is a stylistic convention only; the preprocessor turns NULL back to 0 which is then recognized by the compiler (in pointer contexts) as before. In particular, a cast may still be necessary before NULL (as before 0) in a function call argument. (The table under question 2 above applies for NULL as well as 0.) NULL should _only_ be used for pointers; see question 8. References: K&R I Sec. 5.4 pp. 97-8; K&R II Sec. 5.4 p. 102; H&S Sec. 13.1 p. 283; ANSI Sec. 4.1.5 p. 99, Sec. p. 38, Rationale Sec. 4.1.5 p. 74. 4. How should NULL be #defined on a machine which uses a nonzero bit pattern as the internal representation of a null pointer? A: Programmers should never need to know the internal representation(s) of null pointers, because they are normally taken care of by the compiler. If a machine uses a nonzero bit pattern for null pointers, it is the compiler's responsibility to generate it when the programmer requests, by writing "0" or "NULL," a null pointer. Therefore, #defining NULL as 0 on a machine for which internal null pointers are nonzero is as valid as on any other, because the compiler must (and can) still generate the machine's correct null pointers in response to unadorned 0's seen in pointer contexts. 5. If NULL were defined as follows: #define NULL (char *)0 wouldn't that make function calls which pass an uncast NULL work? A: Not in general. The problem is that there are machines, which use different internal representations for pointers to different types of data. The suggested #definition would make uncast NULL arguments to functions expecting pointers to characters to work correctly, but pointer arguments to other types would still be problematical, and legal constructions such as FILE *fp = NULL; could fail. Nevertheless, ANSI C allows the alternate #define NULL (void *)0 definition for NULL. Besides helping incorrect programs to work (but only on machines with homogeneous pointers, thus questionably valid assistance) this definition may catch programs which use NULL incorrectly (e.g. when the ASCII NUL character was really intended). 6. I use the preprocessor macro

3. and use the correct value. A7. as a reminder that the value is to be thought of as a pointer. !. though perfectly legal. It does not even save keystrokes.3. see question 2. and a true value otherwise. 3. ||. are considered by some to be bad style. 3.4. 3.!. the compiler essentially acts as if it had been written as if(expr != 0) Substituting the trivial pointer expression "p" for "expr. compilers do work this way." we have if(p) is equivalent to if(p != 0) and this is a comparison context. References: K&R II Sec. .15. and _all_ other pointer usages much more carefully. Is the abbreviated pointer comparison "if(p)" to test for non-null pointers valid? What if the internal representation for null pointers is nonzero? A: When C requires the boolean value of an expression (in the if. though popular in some circles.3.4. That is. 204.3.3. If "NULL" and "0" are equivalent. Its use suggests to the reader that the author is shaky on the subject of null pointers. and prefer to use unadorned "0" instead. 3. its invocations. 91.3 p. and ?: operators).3. It is not needed in assignments and comparisons. while. whenever one writes if(expr) where "expr" is any expression at all. 5. The Boolean negation operator.#define Nullptr(type) (type *)0 to help me build null pointers of the correct type. can be described as follows: !expr is essentially equivalent to expr?0:1 It is left as an exercise for the reader to show that if(!p) is equivalent to if(p == 0) "Abbreviations" such as if(p). for. and generate identical code for both statements. H&S Sec. 3. A: This trick.6. There is no trickery involved here. which should I use? A: Many programmers believe that "NULL" should be used in all pointer contexts.6. ANSI Secs.3. and 3. and do statements. does not buy much. and requires the reader to check the #definition of the macro. a false value is produced when the expression compares equal to zero. See also question 71.7 p. 7. The internal representation of a pointer does _not_ matter. There is no one right answer. and with the &&.14.1. 3. 8.13.9. Others feel that the confusion surrounding "NULL" and "0" is only compounded by hiding "0" behind a #definition. so the compiler can tell that the (implicit) 0 is a null pointer.5 .

the language guarantees that source-code 0's (in pointer contexts) generate null pointers. Provide your own definition #define NUL '\0' if you must. The internal (or run-time) representation of a null pointer. The NULL macro. I'm confused.. since they use. but the null pointer is not? A: When the term "null" or "NULL" is casually used. 9. 5. and comparison contexts. 10. The ASCII null character (NUL). the character "0" for sense 3. Reference: K&R II Sec. which is #defined to be "0" or "(void *)0"..4 p. we have. which does have all bits zero. NULL is used only as a stylistic convention. .. Authors of C programs never see them. Finally. 4. 102. which is the single character "0". programmers should not depend on it (either for their own understanding or the compiler's) for distinguishing pointer 0's from integer 0's.. The conceptual null pointer. the abstract language concept defined in question 1. Any usage of "NULL" (as opposed to "0") should be considered a gentle reminder that a pointer is involved. Once again.. as a red herring. 2. one of several things may be meant: 1.C programmers must understand that "NULL" and "0" are interchangeable and that an uncast "0" is perfectly acceptable in initialization. even though it might work. Although symbolic constants are often used in place of numbers because the numbers might change. 5. which will not work in non-pointer contexts. But wouldn't it be better to use NULL (rather than 0) in case the value of NULL changes.. It is often hidden behind. this is _not_ the reason that NULL is used in place of 0.) In particular. and the capitalized word "NULL" for sense 4. which may or may not be all-bits-0 and which may be different for different pointer types. do not use NULL when the ASCII null character (NUL) is desired.. NULL should _not_ be used when another kind of 0 is required. assignment. perhaps on a machine with nonzero null pointers? A: No. The source code syntax for null pointers. 3. The actual values should be of concern only to compiler writers. It is implemented with.. This article always uses the phrase "null pointer" (in lower case) for sense 1. but has no relation to the null pointer except in name. NULL is guaranteed to be 0. because doing so sends the wrong stylistic message. (ANSI allows the #definition of NULL to be (void *)0.

(If "nil" were used to request null pointers rather than "0. Why is there so much confusion surrounding null pointers? Why do these questions come up so often? A: C programmers traditionally like to know more than they need to about the underlying machine implementation. Given all the confusion surrounding null pointers. use "0" or "NULL". which works almost as well. in fact. and if that uncast 0 was supposed to be a null pointer. rather than 0 to a pointer type. The rest of the discussion has to do with other people's misunderstandings. 2. the urge to assume an internal zero representation would not even arise. 2. doing so would be ill-advised because it would unnecessarily constrain implementations which would otherwise naturally represent null pointers by special. or on some weird machine. have any actual machines really used nonzero null pointers? . Finally. because the _size_ of the pointer might still be different from that of an int. Assuming that null pointers are internally zero does not make any code easier to write (except for a certain illadvised usage of calloc. wouldn't it be easier simply to require them to be represented internally by zeroes? A: If for no other reason. A: Follow these two simple rules: 1. The use of a preprocessor macro (NULL) suggests that the value might change later. I'm still confused. before the comparison. whether zero or nonzero. If the usage of "0" or "NULL" is an argument in a function call. Besides. 13. nonzero bit patterns. like Pascal) with which null pointers were requested. or complain when it could not. The compiler could either turn "nil" into the correct type of null pointer.11. I just can't understand all this null pointer stuff. Seriously. Understand questions 1. the code may not work. the distinction between the several uses of the term "null" (listed above) is often overlooked. and 3 and consider 8 and 11. 12. When you want to refer to a null pointer in source code. and internally to most machines. except that an uncast "0" in a non-pointer context generates an integer zero instead of an error message. particularly when those values would trigger automatic hardware traps for invalid accesses. Known-zero internal pointers would not obviate casts in function calls. and you'll do fine. Now. what would this requirement really accomplish? Proper understanding of null pointers does not require knowledge of the internal representation. when it could determine the type from the source code (as it does with 0's in reality). One good way to wade out of the confusion is to imagine that C had a keyword (perhaps "nil". see question 55). cast it to the pointer type expected by the function being called. as zero invites unwarranted assumptions. The construct "if(p == 0)" is easily misread as calling for conversion of p to an integral type. or with the internal representation of null pointers." as mentioned in question 11. which you shouldn't need to know.) 14. The fact that null pointers are represented both in source code. in C the keyword for a null pointer is not "nil" but "0".

References: CT&P Sec. offset 0 for the null pointer. The pointer is to be known by the name "p. a picture is worth a thousand words. there is a location named "a" at which six characters can sit." That is. see question 19. Later models used segment 0.Portable C. does not even have conventional numeric pointers. Arrays and Pointers 15. 3. evidently as a sop to all the extant poorly-written C code which made incorrect assumptions. by H. 33-4. 64-5. Sec. The statements char a[] = "hello". a tagged architecture. A: Not at all. (What you heard has to do with formal parameters to functions. some large Honeywell-Bull machines use the bit pattern 06000 to encode the null pointer. 1990. page 147." requests that space for six characters be set aside.) Arrays are not pointers. at least for PL/I." on the other hand. offset 0 for null pointers in C. Section 2." Use extern char x[]. Prentice-Hall." and can point to any char (or contiguous array of chars) anywhere. I had the definition char x[6] in one source file. The array declaration "char a[6]. The type "pointer-totype-T" is not the same as "array-of-type-T. necessitating new instructions such as TCNP (Test C Null Pointer). 16. Why didn't it work? A: The declaration extern char *x simply does not match the actual definition.A: "Certain Prime computers use a value different from all-bits-0 to encode the null pointer. 4. The "certain Prime computers" were the segmented 50 series. to be known by the name "a. it uses the pair (basically a nonexistent handle) as a C null pointer. requests a place which holds a pointer. would result in data structures which could be represented like this: +---+---+---+---+---+---+ a: | h | e | l | l | o |\0 | +---+---+---+---+---+---+ +-----+ +---+---+---+---+---+---+ p: | *======> | w | o | r | l | d |\0 | +-----+ +---+---+---+---+---+---+ .5 pp. and in another I declared extern char *x. But I heard that char x[] was identical to char *x. char *p = "world". The Symbolics Lisp Machine. Also. As usual. The pointer declaration "char *p. Rabinowitz and Chaim Schaap." -. which used segment 07777.3 pp.

3 pp. 5. In the example above. Sec.1 p. exactly equivalent to *((x)+(i)).2.) 18. References: K&R I Sec. any parameter declarations which "look like" arrays. Therefore.1. the type of the resultant pointer is pointer-to-T. there is not really any difference in the behavior of the "array subscripting" operator [] as it applies to arrays and pointers. by definition. (See also question 98.6 . In either case.3. So what is meant by the "equivalence of pointers and arrays" in C? A: Much of the confusion surrounding pointers in C can be traced to a misunderstanding of this statement. nowhere else. Saying that arrays and pointers are "equivalent" does not by any means imply that they are interchangeable.3 p. 5. it emits code to start at the location "a. 93. but the compiler gets there differently. following the rule above. since that is what the function will receive if an array is passed: f(a) char *a. In an expression of the form a[i]. 3. add three to the pointer. 19. 3. and is then subscripted exactly as would be a pointer variable in the expression p[i]. K&R II Sec. e. and finally fetch the character pointed to. the expression x[i] (where x is an array or a pointer) is. when the compiler sees the expression a[3]. Th1is conversion holds only within function formal parameter declarations. Then why are array and pointer declarations interchangeable as function formal parameters? A: Since arrays decay immediately into pointers. H&S Sec. 93-6. many people have concluded that the confusion it causes . avoid it. You mean that a reference like x[3] generates different code depending on whether x is an array or a pointer? A: Precisely. it emits code to start at the location "p. When it sees the expression p[3].g. ANSI Sec." fetch the pointer value there. Referring back to the sample declarations in the previous question. "Equivalence" refers to the following key definition: An lvalue of type array-of-T which appears in an expression decays (with three exceptions) into a pointer to its first element. both a[3] and p[3] happen to be the character 'l'. the array reference "a" decays into a pointer. an array is never actually passed to a function. If this conversion bothers you. and fetch the character there. or is a literal string initializer for a character array." move three past it. f(a) char a[].4. 5.17.) As a consequence of this definition. (The exceptions are when the array is the operand of the sizeof() operator or of the & operator.3. are treated by the compiler as if they were pointers. 99.

the intervening ones) must be included.3 pp. The "shape" of the array is still important. ANSI Sec. Someone explained to me that arrays were really just constant pointers.3 p.7. . the compiler performs the usual implicit parameter rewriting of "array of array" to "pointer to array.4.} or f(int (*ap)[XSIZE]) {.1 p. 205.6. array subscripting is commutative in C.) If you are passing a two-dimensional array to a function: int array[YSIZE][XSIZE]. A10. as the discussion and pictures in question 16 should make clear. can be omitted. so the number of "rows. 96.3 p. This unsuspected commutativity is often mentioned in C texts as if it were something to be proud of. for _any_ expression e and primary expression a. Sec. not a pointer to a pointer. My compiler complained when I passed a two-dimensional array to a routine expecting a pointer to a pointer. An array of arrays (i. A: The rule by which arrays decay into pointers is not applied recursively." in the second form the pointer declaration is explicit. References: K&R I Sec. H&S Sec. 100. 5. but an array is _not_ a pointer. A8.outweighs the small advantage of having the declaration "look like" the call and/or the uses within the function. Sec.. A10. 3.1. 20. 5. so the "column" dimension XSIZE (and. 33-4. A: That person did you a disservice. 226. namely that a[e] is exactly equivalent to *((a)+(e)). Sec. Sec. including some versions of pcc and pcc-derived lint's. 3. for 3. which improperly accept assignments of multi-dimensional arrays to multi-level pointers.. CT&P Sec. as long as one of them is a pointer expression and one is integral..} /* ap is a pointer to an array */ In the first declaration. K&R II Sec.3 p.e.. Virginia.3. Pointers to arrays can be confusing. Since the called function does not allocate space for the array. f(array). An array name is "constant" in that it cannot be assigned to. (The confusion is heightened by the existence of incorrect compilers. it does not need to know the overall size.1 p. the function's declaration should match: f(int a[][XSIZE]) {. I came across some "joke" code containing the "expression" 5["abcdef"] . How can this be legal C? A: Yes. a two-dimensional array in C) decays into a pointer to an array.4. 95. and must be treated carefully. 5. 22. but it finds no useful application outside of the Obfuscated C Contest (see question 95). 3. This curious fact follows from the pointer definition of array subscripting.3 p." YSIZE.or more dimensional arrays. 21.5. 218.

i < nrows. of course. which is convenient. which don't look exactly like multidimensional array subscripts. although it is not necessarily contiguous in memory as a real array would be.If a function is already declared as accepting a pointer to a pointer. How can I dynamically allocate a multidimensional array? A: It is usually best to allocate an array of pointers. they usually mean a pointer to its first element.) When people speak casually of a pointer to an array. i++) array[i] = (int *)malloc(ncolumns * sizeof(int)). you can simulate a two-dimensional array with a single.jth element with array[i * ncolumns + j]. (A macro can hide the explicit calculation. it is probably incorrect to pass a two-dimensional array directly to it. i < nrows.) You can keep the array's contents contiguous. but the resulting type. subscripting or incrementing the resultant pointer access the individual members of the array. and then initialize each pointer to a dynamically allocated "row. However. you must now perform subscript calculations manually. you don't want to. 24. In either case. How do I declare a pointer to an array? A: Usually." where N is the size of the array. and each return value checked. Here is a two-dimensional example: int **array = (int **)malloc(nrows * sizeof(int *)). i++) array[i] = array[0] + i * ncolumns. and are generally only useful when operating on multidimensional arrays. True pointers to arrays. if at all.) . with a bit of explicit pointer arithmetic: int **array = (int **)malloc(nrows * sizeof(int *)). for(i = 1. array[0] = (int *)malloc(nrows * ncolumns * sizeof(int)). 23." is useless.) If the size of the array is unknown. If the double indirection implied by the above schemes is for some reason unacceptable. step over entire arrays. but invoking it then requires parentheses and commas. dynamically allocated one-dimensional array: int *array = (int *)malloc(nrows * ncolumns * sizeof(int)). If you really need to declare a pointer to an entire array. (See also question 66. N can be omitted. Arrays of type T decay into pointers to type T. when subscripted or incremented. malloc should be declared correctly. while making later reallocation of individual rows difficult." The resulting "ragged" array can save space. accessing the i. use something like "int (*ap)[N]. the elements of the dynamic array can be accessed with normal-looking array subscripts: array[i][j]. Consider using a pointer to one of the array's elements instead. (In "real" code. for(i = 0. (See question 22 above. "pointer to array of unknown size.

Any book on C should make this clear. K&R II Sec.12 p.14 p. 55. It is merely guaranteed that the update will be performed sometime before the expression is considered "finished" (before the next "sequence point. K&R II Sec.3.12 pp. (as well as ?: ). (Ignore H&S Sec. 52. as K&R wisely point out. 3. a cast operator does not mean "pretend these bits have a different type.7 p. the code int i = 7. each of them does imply a sequence point (i. 46-7. CT&P Sec.perform the operations after yielding the former value. that a compiler's choice. left-to-right evaluation is guaranteed). ||. 7.3. (It was an anomaly in certain versions of pcc that expressions such as the above were ever accepted.5 pp. 3. i++ * i++).12 p.3 p.) 27.6 p. "if you don't know _how_ they are done on various machines.11-12 pp. many people misunderstand the implication of "after. (Note. and comma operators? I see code like "if((c = getchar()) == EOF || c == '\n')" . 207-8. the compiler chose to multiply the previous value by itself and to perform both increments afterwards. 2.17 p. Section 3. The behavior of code. CT&P Sec. 54.25.e. 53. 2. prints 49.) Don't even try to find out how your compiler implements such things (contrary to the ill-advised exercises in many C textbooks).3. that innocence may help to protect you.1415 pp. which contains ambiguous or undefined side effects (including ambiguous embedded assignments). ANSI Sec. In the example. Regardless of the order of evaluation. work? A: In C. A7. 41. But what about the &&. 3. 2. Why doesn't ((int *)p)++. especially under ANSI rules." It is _not_ guaranteed that the operation is performed immediately after giving up the previous value and before any other part of the expression is evaluated. 190-1. 9. 120-1. 47. for "undefined behavior" may be to refuse to compile the code. and I want to step it over them. 3.3. 190-1. 50. Secs.." it is a conversion operator. and treat them accordingly. Order of Evaluation 26. 52. or incremented with ++. 3. which is obsolete. too. Secs. I have a char * pointer that happens to point to some ints. Under my compiler. 38." in ANSI C's terminology).6 p. PCS Sec. 2.7 pp. printf("%d\n". and by definition it yields an rvalue. which cannot be assigned to. A: There is a special exception for those operators. has always been undefined. References: K&R I Sec. A7." References: K&R I Sec. 3. 3.) Say what you mean: use p = (char *)((int *)p + 1). ANSI Secs..13 p. . shouldn't it print 56? A: Although the postincrement and postdecrement operators ++ and -.15 p. 39.

has printed the Rationale. with a few additions from C++ (most notably function prototypes) and support for multinational character sets (including the much-lambasted trigraph sequences).") The Standard has been adopted as an international standard. and discusses a number of subtle points. (The Rationale is "not part of ANSI Standard X3. The published Standard includes a "Rationale. the committee's work was finally ratified as an American National Standard. Does anyone have a tool for converting old-style C programs to ANSI C. 1989.00 shipping.S. How can I get a copy of the Standard? A: Copies are available from American National Standards Institute 1430 Broadway New York.) Silicon Press. For the most part. X3J11. and published in the spring of 1990. to standardize the C language. on December 14. 30. so electronic copies are _not_ available.159-1989. (Note that ANSI derives revenues to support its operations from the sale of printed standards. After a long. by itself. plus $6. although the Rationale is currently not included. The ANSI C standard also formalizes the C run-time library support routines. ISO/IEC 9899:1990. ANSI C 28. or for automatically generating prototypes? A: Two programs.Section 4.00. 29. CA 92714 USA (+1) 714 261 1455 (800) 854 7179 (U. X3. arduous process. but is included for information only. (These programs do _not_ handle full-blown . Quantity discounts are available. What is the "ANSI C Standard?" A: In 1983. including several widespread public reviews." which explains many of its decisions. convert back and forth between prototyped and "old style" function definitions and declarations. including several of those covered here. ANSI C standardizes existing practice. protoize and unprotoize. ISBN 0-929306-07-4. & Canada) The cost from ANSI is $50. the American National Standards Institute commissioned a committee.159-1989. NY 10018 USA (+1) 212 642 4900 or Global Engineering Documents 2805 McGaw Avenue Irvine.

Can I declare main as void. #ifdef. many as modifications to lint. 2..1. and no newlines inside quotes.e.71. or #ifndef must still consist of "valid preprocessing tokens..) Reference: ANSI Sec.0 in pub/gnu at prep. and arranges that doubles being passed are coerced back to floats if the formal parameters are declared that way.) These programs exist as patches to the FSF GNU C compiler. 3.mit.) .2. Several prototype generators exist. natural-language comments and pseudocode should always be written between the "official" comment delimiters /* and */. "char * const p" is a constant pointer to a (variable) character (i.) 32. 33." This means that there must be no unterminated comments or quotes (note particularly that an apostrophe within a contracted word could look like the beginning of a character constant). (But see also question 96. it would be clearest to change the old-style definition to use double as well.2 .edu (18.39. the text inside a "turned off" #if.2 p.) 31. What's the difference between "char const *p" and "char * const p"? A: "char const *p" is a pointer to a constant character (you can't change the character).0. int func(x) float x. 34. Therefore. } or by changing the new-style prototype declaration to match the old-style definition: extern int func(double). in the absence of prototypes) silently promotes floats to doubles when passing them as arguments. {.translation between "Classic" C and ANSI C. as long as the address of that parameter is not taken. Look for the file protoize-1. The problem can be fixed either by using new-style syntax consistently in the definition: int func(float x) { . to shut off these annoying "main returns no value" messages? (I'm calling exit(). 6.. (In this case. 3.. Old C (and ANSI C. so main doesn't return." with the old-style definition "int func(x) float x.3.1.) References: ANSI Sec. gcc.38). My ANSI compiler complains about a mismatch when it sees extern int func(float). (Read these "inside out" to understand them.ai. or at several other FSF archive sites. Sec. 19 line 37. A: You have mixed the new-style prototype declaration "extern int func(float). See question 66.1 p. I'm getting strange syntax errors inside code which I've #ifdeffed out. A: Under ANSI C. you can't change the pointer). (See also question 94.".

(The Rationale notes that its retention was "most painful.1. 2. What are #pragmas and what are they good for? A: The #pragma directive provides a single.A: No. 3. Sec. This limitation is annoying. main must be declared as returning an int. 19-21. in spite of its superficial attractions.6. What was noalias and what ever happened to it? A: noalias was another type qualifier.1 p. If you're calling exit() but still getting warnings. read the excellently worded section 3.e.1. How can I write a generic macro to swap two values? . and sparked widespread. etc.2 p. C Preprocessor 38. 3. References: ANSI Sec. no matter how vehemently some people oppose it. 96. well defined “escape hatch” which can be used for all sorts of implementation-specific controls and extensions: source listing control.9. structure packing. and is marked in the Standard as "obsolescent. not that they be restricted to six characters in length. you'll have to insert a redundant return statement (or use a "notreached" directive. if available)." i. Rationale Sec. but certainly not unbearable.2 in the X3.2. warning suppression (like the old lint/* NOTREACHED*/ comments).159 Rationale (see question 28).6. Because of the criticism and the difficulty of defining noalias well. the Committee wisely declined to adopt it. 21. 3. restrictive linkers really had to be made. 36. acrimonious debate.9. in the same syntactic class as const and volatile.") If you disagree. which have them. 3. Section 5. This concession to current. The limitation is only those identifiers be _significant_ in the first six characters. which discusses several such schemes and explains why they could not be mandated.2 pp. It was phenomenally difficult to define precisely and explain coherently.1.1. 37. 7-8.2. References: ANSI Sec. 3. 35.1 pp. which was intended to assert that the object pointed to was not also pointed to ("aliased") by other pointers. which are neither under the control of the ANSI standard nor the C compiler developers on the systems. References: ANSI Sec. or have thought of a trick by which a compiler burdened with a restrictive linker could present the C programmer with the appearance of more significance in external identifiers. and as taking either zero or two arguments (of the appropriate type). a future revision will likely relax it. References: ANSI Sec. Why does the ANSI Standard not guarantee more than six monocase characters of external identifier significance? A: The problem is older linkers.8.

ANSI introduced a well-defined token-pasting operator. */ \ } while(0) /* (no trailing .) . 40. A: That comments disappeared entirely and could therefore be used for token pasting was an undocumented feature of some early preprocessor implementations. unless you don't mind passing in the type as a third argument. The macro body cannot be a simple brace-delineated compound statement. although lint may complain. However. and the "obvious" supercompressed implementation for integral types a^=b^=a^=b is. which can be used like this: #define Paste(a. it cannot use a temporary. b) a/**/b but it doesn't work any more... If the values are integers. (An optimizing compiler will remove any "dead" tests or branches on the constant condition 0.A: There is no good answer to this question. and standard C does not provide a typeof operator. 91. but with a resultant extra semicolon) as the if branch of an if/else statement with an explicit else clause. This means that the "caller" will be supplying the final semicolon. illegal due to multiple sideeffects. \ stmt2. 66-7. The best all-around solution is probably to forget about using a macro. The traditional solution is to use #define Func() do { \ /* declarations */ \ stmt1. 39.3 p. because syntax errors would result if it were invoked (apparently as a single statement. Rationale pp. strictly speaking. b) a##b Reference: ANSI Sec.. (and it will not work if the two values are the same variable. but it will not work for floating-point values or pointers.. 3. I have some old code that tries to construct identifiers with a macro like #define Paste(a. since it does not know what type of temporary it needs. this expansion becomes a single statement regardless of context. \ /* .).8. What's the best way to write a multi-statement cpp macro? A: The usual goal is to write a macro that can be invoked as if it were a single function-call statement.3. since the need for pasting tokens was demonstrated and real. ##. ANSI affirms (as did K&R) that comments are replaced with white space. and. a well-known trick using exclusive-OR could perhaps be used. ) */ When the "caller" appends a semicolon. so the macro body should not. notably Reiser's. If the macro is intended to be used on values of arbitrary type (the usual goal).

the older). 41. char *retbuf.") Reference: CT&P Sec. 6. while((p = va_arg(argp. va_start(argp. How can I write a cpp macro which takes a variable number of arguments? A: One popular trick is to define the macro with a single argument. if(first == NULL) return NULL. (It is often best to use a bona-fide function. .. which appear to the preprocessor to indicate a single argument: #define DEBUG(args) {printf("DEBUG: ").. .) { size_t len = 0. char *)) != NULL) len += strlen(p). another technique is to write a single. len = strlen(first). if you must.) Section 6. How can I write a function that takes a variable number of arguments? A: Use the header (or.3 pp.If all of the statements in the intended macro are simple expressions. n)). va_end(argp). printf args. and call it with a double set of parentheses. which can take a variable number of arguments in a welldefined way. Variable-Length Argument Lists 42. first). Here is a function. va_list argp. size_t */ #include /* for va_ stuff */ #include /* for strcat et al */ #include /* for malloc */ char *vstrcat(char *first. 82-3. See questions 42 and 43 below. which concatenates an arbitrary number of strings into malloc'ed memory: #include /* for NULL. parenthesized expression using one or more comma operators. rather than a macro. (This technique also allows a value to be "returned. The obvious disadvantage is that the caller must always remember to use the extra parentheses. with no declarations or loops. char *p.} if(n != 0) DEBUG(("n is %d\n".

References: K&R II Sec.3 p. 4. {"). and use the older varargs package instead of stdarg. "world!"..1. /* error */ (void)strcpy(retbuf. B7 p. 286-9.retbuf = malloc(len + 1).) { va_list argp. "error: "). 13. H&S Sec. 43. and use int instead of size_t. va_start(argp. How can I write a function that takes a format string and a variable number of arguments.) Under a pre-ANSI compiler. replace "#include " with "extern char *malloc(). } Usage is something like char *str = vstrcat("Hello. /* +1 for trailing \0 */ if(retbuf == NULL) return NULL. fprintf(stderr.". and passes them to printf to do most of the work? A: Use vprintf. 155. include rather than . ANSI Secs. See the next question for hints. (Also note that the caller must free the returned.. malloc'ed storage. va_end(argp). (char *)NULL). rewrite the function definition without a prototype ("char *vstrcat(first) char *first. 7. which prints an error message. . Note the cast on the last argument. vfprintf. return retbuf. while((p = va_arg(argp. .4 pp. first). like printf. preceded by the string "error: " and terminated with a newline: #include #include void error(char *fmt. ".8 through 4. p). or vsprintf.3. first). You may also have to delete the (void) casts. Here is an "error" routine. char *)) != NULL) (void)strcat(retbuf.8. Sec. 254.

fprintf(stderr.8. but its use is questionable. as does vfprintf in the example above.va_start(argp.9. 45.12 p.) Any function which takes a variable number of arguments must be able to determine from the arguments themselves how many of them there are. change the va_start line to va_start(argp).3 p. ANSI Secs.6. you cannot. (Note that there is no semicolon after va_dcl. 4. If the arguments must be passed directly as . 8. not the number of arguments. printf-like functions do this by looking for formatting specifiers (%d and the like) in the format string (which is why these functions fail badly if the format string does not match the argument list). fmt. 4. char *). -1. 44. since it typically returns the number of words pushed.) References: K&R II Sec. change the function header to: void error(va_alist) va_dcl { char *fmt.7. 174. 245. Sec. which takes a variable number of arguments and passes them to some other function (which takes a variable number of arguments)? A: In general. between the calls to va_start and vfprintf. How can I discover how many arguments a function was actually called with? A: This information is not available to a portable program. vfprintf(stderr. instead of.6. and add the line fmt = va_arg(argp. fmt). B1. Some systems provide a nonstandard nargs() function.9. 17.9.2 p. H&S Sec. argp). 4. 337. } To use the older package. Another common technique (useful when the arguments are all of the same type) is to use a sentinel value (often 0. or an appropriately-cast null pointer) at the end of the list (see the execl and vstrcat examples under questions 2 and 42 above). How can I write a function.6. You must provide a version of that other function which accepts a va_list pointer. va_end(argp).9. (Floating point values and structures are usually passed as several words. "\n").

47. printf("You typed \"%s\"\n".) Section 7. and cannot be told." which is handed to the gets function as the location into which the response should be stored.compilers. but a simpleminded #definition will also suppress meaningful messages about truly incorrect invocations. that malloc "returns a pointer to space suitably aligned for storage of any type of object. gets(answer). and it's acting strangely. answer). Many C compilers are really only half. PA 19426 USA (+1) 215 584 4261 The System V release 4 lint is ANSI-compatible. electing not to diagnose numerous source code difficulties which would not actively preclude code generation. 48. or from System V resellers. has not been set to point to any valid storage. Memory Allocation 49. Where can I get an ANSI-compatible lint? A: A product called FlexeLint is available (in "shrouded source form. and is available separately (bundled with other C tools) from Unix Support Labs (a subsidiary of AT&T).actual arguments (not indirectly through a va_list pointer) to another function which is itself variadic (for which you do not have the option of creating an alternate. A: The pointer variable "answer. How can I shut off the "warning: possible pointer alignment problem" message lint gives me for each call to malloc? A: The problem is that traditional versions of lint do not know. perhaps in an automated way with grep -v. which effectively shuts this warning off. we cannot say . I just typed in this program. Can you see anything wrong with it? A: Try running lint first." for compilation on 'most any system) from Gimpel Software 3207 Hogarth Lane Collegeville. Section 8. printf("Type something:\n"). using a #define inside of #ifdef lint. Why doesn't this fragment work? char *answer. It may be easier simply to ignore the message. va_list-accepting version) no portable solution is possible. (The problem can be solved by resorting to machine-specific assembly language. Lint 46. That is." It is possible to provide a pseudoimplementation of malloc.

) The simplest way to correct the question-asking program is to use a local array. fgets does not automatically delete the trailing \n. and typically contain garbage. C compilers only allocate memory for objects explicitly mentioned in the source code (in the case of "strings." this includes character arrays and string literals). Reference: CT&P Sec. I tried char *s1 = "Hello. s2).) It would also be possible to use malloc to allocate the answer buffer. Therefore. How am I supposed to know to allocate things? . so that the size of the array can be specified. or by calling malloc. if((p = strchr(answer. 100. it is not even guaranteed that "answer" starts out as a null pointer. but I got strange results. the second string is appended to the first one.where the pointer "answer" points. 51. strcat performs no allocation. *p. A: Again. Note that this example also uses fgets instead of gets (always a good idea). char *s2 = "world!". '\n')) != NULL) *p = '\0'. one fix would be to declare the first string as an array with sufficient space: char s1[20] = "Hello. 50. Since strcat returns the value of its first argument (s1. printf("Type something:\n"). and let the compiler worry about allocation: #include char answer[100]. instead of a pointer. so that fgets will not overwrite the end of the array if the user types an overly long line. 32. typically by declaring arrays. But the man page for strcat says that it takes two char *'s as arguments. 3. the s3 variable is superfluous. (Since local variables are not initialized. ". as gets would. See question 85.2 p. ". answer). I can't get strcat to work. and/or to parameterize its size (#define ANSWERSIZE 100). the problem is that space for the concatenated result is not properly allocated. fgets(answer. char *s3 = strcat(s1. (Unfortunately for this example. in this case). The programmer must arrange (explicitly) for sufficient space for the results of run-time operations such as string concatenation. stdin). printf("You typed \"%s\"\n". in place. C does not provide an automatically-managed string type.

} and notice what would happen if the more-obvious loop iteration expression listp = listp->next were used. The Synopsis section at the top of a Unix-style man page can be misleading. without the temporary nextp pointer. 102.g. listp != NULL. it is usually the caller's problem. which frees). How does free() know how many bytes to free? A: The malloc/free package remembers the size of each block it allocates and returns. free((char *)listp).A: In general. for(listp = base. when using pointers you _always_ have to consider memory allocation. 52. Few programmers would use the contents of freed memory deliberately.) Another common example is stat(). can you? A: No.. References: ANSI Sec. Consider the following (correct) code for freeing a singly-linked list: struct list *listp. CT&P Sec. 95. many routines which accept pointers (e. listp = nextp) { nextp = listp->next. References: ANSI Rationale Sec. 54. at least to make sure that the compiler is doing it for you. Is it legal to pass a null pointer as the first argument to realloc()? Why would you want to? A: ANSI C sanctions this usage (and the related realloc(. 55.. *nextp. or do you need a cfree? .10. or an array – see questions 18 and 19.10 p. In particular. Passing an initially-null pointer to realloc can make it easier to write a self-starting incremental allocation algorithm. 4. The code fragments presented there are closer to the function definition used by the call's implementor than the invocation used by the caller. 4.2 p. 7.3.3. but several earlier implementations do not support it. 53. to structs or strings).10. but it is easy to do so accidentally. so it is not necessary to remind it of the size when freeing.. What is the difference between calloc and malloc? Is it safe to use calloc's zero-fill guarantee for pointer and floating-point values? Does free work on memory allocated with calloc. are usually called with the address of some object (a struct. If a library routine's documentation does not explicitly mention allocation. so it is not widely portable. 0). You can't use dynamically-allocated memory after you free it. Some early man pages for malloc stated that the contents of freed memory was "left undisturbed.4 ." this ill-advised guarantee was never universal and is not required by ANSI.

2 p. 3. References: K&R I Sec.2. which must be widely portable. memory allocated with alloca is local to a particular function's "stack frame" or context. 3. memset(p. and is difficult to implement on machines without a stack.5.1.2 p. m * n).10. Although a few early C compilers lacked struct assignment. Structures 57.10. stdin). For these reasons. A: What K&R I said was that the restrictions on struct operations would be lifted in a forthcoming version of the compiler. alloca cannot be used in programs. 58. 0. Section 9. H&S Sec. The zero fill is all-bits-zero. 6. What is alloca and why is its use discouraged? A: alloca allocates memory which is automatically freed when the function which called alloca returns. ANSI Secs. 3.point values.1. n) is essentially equivalent to p = malloc(m * n).3. 4.A: calloc(m. 100. and does not therefore guarantee useful zero values for pointers (see questions 1-14) or floating. and it is part of the ANSI C standard. How does struct passing and returning work? A: When structures are passed as arguments to functions.2. free can (and should) be used to free the memory allocated by calloc.2 p. 103. the entire struct is typically pushed on the stack.6. using as many words as are required. so there should be no reluctance to use it.16. Its use is problematical (and the obvious implementation on a stack-based machine fails) when its return value is passed directly to another function.2.) . alloca cannot be written portably. all modern compilers support it.3. no matter how useful it might be. 6. That is. as in fgets(alloca(100). I heard that structures could be assigned to variables and passed to and from functions. (Pointers to structures are often chosen precisely to avoid this overhead. 121.2.3 to 4. 56. References: ANSI Secs. 129. 5. K&R II Sec. and in fact struct assignment and passing were fully functional in Ritchie's compilers even as K&R I was being published. but K&R I says not.

*/ main(argc.2 p. If you want to compare two structures. the generated code for main() actually expects three arguments. References: K&R II Sec.9 p. 47.) Since struct-valued functions are usually implemented by adding a hidden return pointer. although only two were passed (in this case.6.. argv) . 3. H&S Sec. char name[1]. which ANSI C disallows.3 pp. Reference: ANSI Sec. but it dumps core after it finishes. A field-by-field comparison would require unacceptable amounts of repetitive. 5. in-line code for large structures. you must write your own function to do so. by the C start-up code). Why can't you compare structs? A: There is no reasonable way for a compiler to implement struct comparison. 60. The following program works correctly. . 2. 21-2. static location for structure returns. which is consistent with C's low-level flavor.3 p. A: A missing semicolon causes the compiler to believe that main return a struct list. 129.Structures are typically returned from functions in a location pointed to by an extra. See also question 101. 6. Older compilers often used a special. 2. although this made struct-valued functions nonreentrant. struct list *next. A byte-by-byte comparison could be invalidated by random bits present in unused "holes" in the structure (such padding is used to keep the alignment of later fields correct). compilersupplied "hidden" argument to the function. } /* Here is the main program. I came across some code that declared a structure like this: struct name { int namelen. C++ would let you arrange for the == operator to map to your function.2 p. 61. 59. 103. ANSI Rationale Sec. Why? struct list { char *item.. 13.2.3. (The connection is hard to see because of the intervening comment. Reference: CT&P Sec.

using the offsetof() macro. (Compilers which check array bounds carefully might issue warnings. How can I access structure fields by name at run time? A: Build a table of names and offsets. Reference: ANSI Sec. See the next question for a usage hint. Section 10.(char *)((type *) 0))) This implementation is not 100% portable. 63. use short. use int. and then did some tricky allocation to make the name array act like it had several elements.5.}. Declarations 64. (But beware mixtures of signed and unsigned. . If you don't have it. Exceptions apply if the address of a variable is taken and must have a particular type.1. b's value can be set indirectly with *(int *)((char *)structp + offsetb) = value. Is this legal and/or portable? A: This technique is popular. although Dennis Ritchie has called it "unwarranted chumminess with the compiler. b) If structp is a pointer to an instance of this structure.) 62. Otherwise. see . use the corresponding unsigned types. which should be used if available. some compilers may legitimately refuse to accept it. It seems to be portable to all known implementations. a suggested implementation is #define offsetof(type. How do you decide which integer type to use? A: If you might need large values (above 32767 or below -32767). if space is very important (there are large arrays or many structures). use long. Otherwise. How can I determine the byte offset of a field within a structure? A: ANSI C defines the offsetof macro. The offset of field b in struct a is offsetb = offsetof(struct a." The ANSI C standard allows it only implicitly. mem) ((size_t) \ ((char *)&((type *) 0)->mem . If welldefined overflow characteristics are important and/or negative values are not.) Similar arguments apply when deciding between float and double. 4. and b is an int field with offset as computed above.

5 of K&R make this clear. 5. . } *NODEPTR. The problem with this example is that the NODEPTR typedef is not complete at the point where the "next" field is declared. K&R II Sec. the discussion and example in section 6.3. and there at least three other equivalently correct ways of arranging it. H&S Sec. 65. /* pointer to char */ . with a similar solution. 6. To fix it. can arise when attempting to declare a pair of typedef'ed mutually recursive structures. I can't seem to define a linked list successfully. Can't a struct in C contain a pointer to itself? A: Structs in C can certainly contain pointers to themselves. 3. 66. and/or move the typedef declaration wholly before or wholly after the struct declaration. 102.2. Then. typedef struct node *NODEPTR.5 p. A similar problem. but the compiler gave me error messages. }. Build the declaration up in stages.5 p.5.". char *(*(*a[5])())(). 2. struct node *next. doing so is often more trouble than it is worth. References: K&R I Sec.Although char or unsigned char can be used as a "tiny" int type. 101. 6. using typedefs: typedef char *pc. 139. How do I declare an array of pointers to functions returning pointers to functions returning pointers to characters? A: This question can be answered in at least three ways (all assume the hypothetical array is to have 5 elements): 1. One fixed version would be struct node { char *item. I tried typedef struct { char *item.6. ANSI Sec. declare the "next" field as "struct node next.1 p. first give the structure a tag ("struct node"). NODEPTR next.

. much as an array name does. */ typedef fpfpc *pfpfpc. 5. (See question 94.e. One is in volume 14 of comp. Any good book on C should explain how to read these complicated C declarations "inside out" to understand them ("declaration mimics use")... /* function returning. 116. it "decays" into a pointer (i. int (*fp)() = func. help with casts. and indicate which set of parentheses the arguments go in (for complicated function definitions. like the above). When the name of a function appears in an expression but is not being called (i. /* function returning pointer to char */ typedef fpc *pfpc.. /* pointer to above */ typedef pfpc fpfpc().e.10. but now how do I initialize one? A: Use something like extern int func(). Reference: H&S Sec. I finally figured out the syntax for declaring pointers to functions. because the function name is not followed by a "("). So where can I get cdecl? A: Several public-domain versions are available.. since implicit external function declaration does not happen in this case (again. it has its address implicitly taken).) Reference: K&R II Sec.1 p. /* array of.typedef pc fpc().. /* pointer to. which turns English into C and vice versa: cdecl> declare a as array 5 of pointer to function returning pointer to function returning pointer to char char *(*(*a[5])())() cdecl can also explain complicated declarations. What's the story? . Use the cdecl program.unix . */ pfpfpc a[5]. 68. 5. is not followed by a "(").sources. 69. An explicit extern declaration for the function is normally needed. I've seen different methods used for calling through pointers to functions. 67. */ 3.12 .

This reasoning. with the * operator (and an extra pair of parentheses. is legal and works correctly. which was adopted in the ANSI standard. yes}. (The usage has always been unambiguous. Boolean Expressions and Variables 70.2 p. What is the right type to use for boolean values in C? Why isn't it a standard type? Should #defines or enums be used for the true and false values? A: C does not provide a standard boolean type. or use raw 1 and 0.2. References: ANSI Sec. if portability to older compilers is important). r = (*fp)().) The choice between #defines and enums is arbitrary and not terribly interesting. and still allowed (and recommended.) Some people prefer variants like #define TRUE (1==1) #define FALSE (!TRUE) or define "helper" macros such as #define Istrue(e) ((e) != 0) .A: Originally. a pointer to a function had to be "turned into" a "real" function. but that "real" functions decay implicitly into pointers (in expressions. there is nothing you ever could have done with a function pointer followed by an argument list except call through it. 41. enum bool {no. 3.) An explicit * is harmless. as long as you are consistent within one program or project. f(). Another analysis holds that functions are always called through pointers. while using char may save data space. as they do in initializations) and so cause no trouble. means that r = fp(). Section 11. Use any of #define TRUE 1 #define YES 1 #define FALSE 0 #define NO 0 enum bool {false. because picking one involves a space/time tradeoff which is best decided by the programmer. 41. (*fp)() = f. Rationale p. true}. (An enum may be preferable if your debugger expands enum values when examining variables. whether fp is a function or a pointer to one. (Using an int for a boolean may be faster. before calling: int r.3. to keep the precedence straight).

41. on success. there is little difference. Sec. Therefore. since any nonzero value is considered "true" in C? What if a built-in boolean or relational operator "returns" something other than 1? A: It is true (sic) that any nonzero value is considered true in C. That "true" is 1 and "false" 0 is guaranteed by the language. 71. 39.15.9. Sec. 3. 72. 3. 2. Section 12.5. (A compiler may also generate nonfatal warnings when enums and ints are indiscriminately mixed.5 p. 5.) return. but it is obviously silly.2 p. 42.3 p. Isn't #defining TRUE to be 1 dangerous.5. the test if((a == b) == TRUE) will work as expected (as long as TRUE is 1). the ANSI standard says that enumerations may be freely intermixed with integral types. K&R II Sec. 3. How can I read a single character from the keyboard without waiting for a newline? . never in a comparison. Operating System Dependencies 73. 3.2.2 .3. 2. (If such intermixing were disallowed without explicit casts.8.6. 206.) The primary advantages of enums are that the numeric values are automatically assigned.These don't buy anything (see below). because some library functions (notably isupper. 204. A7. 3.3. i.3. explicit tests against TRUE and FALSE are undesirable. a nonzero value which is _not_ necessarily 1.9 p. 3. A7. 3. A4. ANSI Secs. (See also question 7. judicious use of enums could catch certain programming errors.4. Although many people might have wished otherwise.1.1.2. if you believe that "if((a == b) == TRUE)" is an improvement over "if(a == b)". 3.5. without errors. or as the return value from a Boolean function.3.3. Achilles and the Tortoise.3.7 p. H&S Sec. of course. When a boolean value is generated by a built-in operator. NULL) are used for code readability.13. but this applies only "on input". A disadvantage is that the programmer has little control over the size (or over those nonfatal warnings). In general. why stop there? Why not use "if(((a == b) == TRUE) == TRUE)"?) A good rule of thumb is to use TRUE and FALSE (or the like) only for assignment to a Boolean variable.2.7 p. 196. 3. ANSI Secs.3. not because the underlying values might ever change. The preprocessor macros TRUE and FALSE (and.14. etc. References: K&R II Sec.) References: K&R I Sec. (Besides. and that a debugger may be able to display the symbolic values when enum variables are examined. 100.3. 3. it is guaranteed to be 1 or 0. 2. What is the difference between an enum and a series of preprocessor #defines? A: At the present time.e.6 p.6.4. Sec.5. where a boolean value is expected. since doing so can still be considered bad style even though it is not strictly illegal). isalpha.3.

10 pp.lang. and cannot be standardized by the C language. How can a file be shortened in-place without completely clearing or rewriting it? .pc. it cannot. Different operating systems implement name/value functionality similar to the Unix environment in different ways. or a system call named "select". Under other operating systems. use ioctl to play with the terminal driver modes (CBREAK or RAW under "classic" versions.c . The delivery of characters from a "keyboard" to a C program is a function of the operating system in use. a process can modify its own environment (some systems provide setenv() and/or putenv() functions to do this). but it is _not_ propagated back to the parent process. or it may contain nothing. Note that the answers are often not unique even across different variants of a system. You may be able to duplicate the command language interpreter's search path logic to locate the executable if the name in argv[0] is present but incomplete.misc . How can I find out if there are characters available for reading (and if so. or the O_NDELAY option to open() or fcntl(). you may also be able to use "nonblocking I/O".unix. 77. and if so. and the modified environment is usually passed on to any child processes. how. Whether the "environment" can be usefully altered by a running program. Under Unix. Depending on your system. 76. try the Screen Management (SMG$) routines. References: PCS Sec.sys. too. Under UNIX.questions and comp. 130-1. 10.A: Contrary to popular belief and many people's wishes. or rdchk(). Sec. you're on your own. 74. How can a process change an environment variable in its caller? A: In general. how can I do a read that will not block if there are no characters available? A: These. use getch(). or the FIONREAD ioctl. Some versions of curses have a nodelay() function. is system-dependent. Operating system specific questions are not appropriate for comp. Many common questions are answered in frequently asked question postings in such groups as comp. Some versions of curses have a cbreak() function which does what you want. However.ibm. Beware that some operating systems make this sort of thing impossible. Bear in mind when answering system-specific questions that the answer that applies to your system may not apply to everyone else's. how many)? Alternatively. ICANON. Under VMS. How can my program discover the complete pathname to the executable file from which it was invoked? A: argv[0] may contain all or part of the pathname. 75. this is not a C-related question.1 pp. there is no guaranteed or portable solution. 128-9. c_cc[VMIN] and c_cc[VTIME] under System V or Posix systems). because character collection into input lines is done by peripheral processors not under direct control of the CPU running your program. Under MS-DOS. or kbhit(). are entirely operating-system-specific.

and then use sscanf() or other string functions to parse the line buffer. 5. and would fail if the file descriptor was a pipe or referred to a deleted file (and could give a misleading answer for a file with multiple links). and a few may provide a (possibly undocumented) fcntl option F_FREESP.) 80. Section 14. (perhaps requiring special permissions) would theoretically be required. Stdio 78. How can I recover the file name given an open file descriptor? A: This problem is. Why does errno contain ENOTTY after a call to printf? A: Many implementations of the stdio package adjust their behavior slightly if stdout is a terminal. It is best to remember the names of open files yourself (perhaps with a wrapper function around fopen). but there is no truly portable solution. When I read from the keyboard with scanf(). In particular. Here's a neat trick: if(!strcmp(s1. in general. Although the output operation goes on to complete successfully. at the "right time. A: It is best to use an explicit fflush(stdout) whenever output should definitely be visible. which is seldom what you want when reading from the keyboard. It is usually better to fgets() to read a whole line. 81. 73. To make the determination. not to expect a newline. Style 82. but to read and discard characters as long as each is a whitespace character. insoluble. it seems to hang until I type one extra line of input. Reference: CT&P Sec. "\n" in a format string means. Section 13. these implementations perform an operation which fails (with ENOTTY) if stdout is not a terminal." but they tend to apply only when stdout is a terminal. 79. s2)) Is this good style? . (See question 78. a scan of the entire disk. errno still contains ENOTTY. especially when I pipe the output through another program. for instance. Several mechanisms attempt to perform the fflush for you.4 p. A: scanf() was designed for free-format input. several others supply chsize(). Under Unix.A: BSD systems provide ftruncate(). My program's prompts and intermediate output don't always show up on the screen.

such variables are initialized to the null pointer (of the correct type) if they are pointers. This is a classic example of C minimalism carried to an obnoxious degree.95. Where can I get the "Indian Hill Style Guide" and other coding standards? A: Various documents are available for anonymous ftp from: Site: File or directory: cs.) Reference: K&R Sec. also supply a good excuse for avoiding it: The position of braces is less important.cis. and with nearby or common code) than that it be "perfect. just copy K&R. What can I safely assume about the initial values of variables which are not explicitly initialized? If global variables start out as "zero. s2) == 0) 83.ohio-state. A much better solution is to use a macro: #define Streq(s1. local custom or company policy) does not suggest a style. those declared outside of functions. Therefore. The test succeeds if the two strings are equal." is that good enough for null pointers and floating-point zeroes? A: Variables with "static" duration (that is.washington. What's the best style for code layout in C? A: K&R.edu doc/programming giza. but don't warrant repetition here.A: No. It is more important that the layout chosen be consistent (with itself. then use it consistently. although people hold passionate beliefs. See also the Indian Hill Style Guide.edu ~ftp/pub/cstyle. 84.Z (128. We have chosen one of several popular styles. as if the programmer had typed "= 0".edu pub/style-guide Section 15. 1.2 p. 10. and you don't feel like inventing your own. while providing the example most often copied. s2) (strcmp(s1.1. and to 0." If your coding environment (i.e. but its form strongly suggests that it tests for inequality.toronto.0 if they are floating-point. and those declared with the storage class static).tar. are guaranteed initialized to zero. . Pick a style that suits you. Miscellaneous 85. (The tradeoffs between various indenting and brace placement options can be exhaustively and minutely examined.4) (the updated Indian Hill guide) cs.

) References: K&R I Sec.6 p. in this case. They must be cast back to what they "really are" (char **) and dereferenced. 3. p2) /* compare strings through pointers */ char *p1. } 87.Variables with "automatic" duration (i.e. I'm trying to sort an array of strings with qsort. I know that the library routine localtime will convert a time_t into a broken-down struct tm." void * or char *. 88. unless they are explicitly initialized. Nothing useful can be predicted about the garbage. using strcmp as the comparison function. . and that ctime will convert a time_t to a printable string. Now I'm trying to sort an array of structures with qsort. but this is not necessarily useful for pointer or floating-point values (see question 55). 60. K&R II Sec. /* void * for ANSI C */ { return strcmp(*(char **)p1. 86. which converts a struct tm to a time_t. mktime. Dynamically allocated memory obtained with malloc and realloc is also likely to contain garbage. local variables without the static storage class) start out containing garbage. Memory obtained with calloc contains all-bits-0. How can I cast the function pointer to shut off the warning? A: The casts must be in the comparison function. pointers to pointers to char. yielding char *'s which can be usefully compared. *p2. and must be initialized by the calling program. Don't worry that sprintf may be overkill. but it's not working. potentially wasting run time or code space. The arguments are expressed as "generic pointers. 89. (You'll have to allocate space for the result somewhere anyway. which must be declared as accepting "generic pointers" (void * or char *). Can someone tell me how to write itoa (the inverse of atoi)? A: Just use sprintf." The arguments to qsort's comparison function are pointers to the objects being sorted. A: By "array of strings" you probably mean "array of pointers to char. see questions 49 and 50. 64. My comparison routine takes pointers to structures. *(char **)p2). as appropriate. Write a comparison function like this: int pstrcmp(p1. 3. but the compiler complains it's of the wrong type for qsort. it works well in practice.6 p. Several public-domain versions of this routine are available in case your compiler does not support it yet. How can I perform the inverse operations of converting a struct tm or a string into a time_t? A: ANSI C specifies a library routine.

and processor can be supplied. References: K&R II Sec. 91. Read your compiler documentation very carefully.4 p. widely distributed with the RCS package). also patches in Volume13?). 4. and perhaps take advantage of prewritten I/O libraries. this one written in Pascal (comp. Ask your compiler vendor why the file was not provided (or to send a replacement copy). Public-domain routines have been written for performing this function (see.sources.unix. because of the wide variety of date and time formats which should be parsed.sources. or CCITT's X.) Be skeptical of arguments which imply that text files are too big. How can I write data files which can be read on other machines with different word size. How can I call Fortran (BASIC. byte order. or that reading and writing them is too slow.) to C? A: Several public-domain programs are available: p2c written by Dave Gillespie. You cannot just pick up a copy of someone else's header file and expect it to work." although the techniques for passing arguments and ensuring correct run-time startup are often arcane. ADA and lisp) functions from C? (And vice versa?) A: The answer is entirely dependent on the machine and the specific calling sequences of the various compilers in use.1. 92.unix contribution. 1990 (Volume 21). . you can improve portability. the file partime. I seem to be missing the system header file . .Converting a string to a time_t is harder.12. B10 p. ptoc another comp. by making use of standardized formats such as Sun's XDR.. (Similar advice also applies to network protocols. operating system.. and posted to comp. "Old" C. Volume 10. Does anyone know of a program for converting Pascal (Fortran. ANSI Sec. for example. or floating point formats? A: The best solution is to use text files (usually ASCII). OSI's ASN. written with fprintf and read with fscanf or the like. and may not be possible at all. 361. lisp.409 . If you must use a binary format.2. unless that person is using exactly the same environment.c.3 . 93. but the advantages of being able to manipulate them with standard tools can be overwhelming.unix in March. 20. Pascal. H&S Sec. Can someone send me a copy? A: Standard headers exist in part so that definitions appropriate to your compiler. Not only is their efficiency frequently acceptable in practice. 90. sometimes there is a "mixed-language programming guide. but they are less likely to become standardized.sources. 256.

95. send the mail message "help" to archie@quiche.2).sources in April.48. 94. Suite 301 Columbus.com. The following companies sell various translation tools and services: Cobalt Blue 2940 Union Ave. The usual approach is to use anonymous ftp and/or uucp from a central. in directory dist/f2c.ca for information.net (192. Where can I get copies of all these public-domain programs? A: If you have access to Usenet.com Contest winners are first announced at the Summer Usenix Conference in mid-June.sources..att. The comp. see the regular postings in the comp. OH 43214 USA (+1) 614 263 5454 Micro-Processor Services Inc 92 Stone Hurst Lane Dix Hills.uunet.misc newsgroups.cs.. CA 95124 USA (+1) 408 723 0474 Promula Development Corp. When will the next International Obfuscated C Contest (IOCCC) be held? How can I get a copy of the current and previous winning entries? A: The contest typically runs from early March through mid-May. which describe.) A PL/M to C converter was posted to alt. To find about f2c. High St. send email to: {pacbell. Previous winners are available on uunet (see question 94) under the directory . NY 11746 USA (+1) 519 499 4461 See also question 30. 3620 N. in some detail. and posted to the net in July.f2c jointly developed by people from Bell Labs.sources. To obtain a current copy of the rules.att.mcgill. publicspirited site. Bellcore.uu. this article cannot track or list all of the available archive sites and how to access them. send the mail message "send index from f2c" to netlib@research.unix and comp. However. (It is also available via anonymous ftp on research.archives newsgroup contains numerous announcements of anonymous ftp availability of various items. and Carnegie Mellon.96.com or research!netlib. the archiving policies and how to retrieve copies. 1991.utzoo}!hoptoad!judges or judges@toad. Suite C San Jose. such as uunet. The "archie" mailserver can tell you which anonymous ftp sites have which packages.

3.lang. see chapter 7 of Kernighan and Plauger's The Elements of Programming Style. Most of the code in most programs is not time-critical. because a program (particularly one which is generating C code as output) might want to print them. it is vital to pick a good algorithm. is not important nearly as often as people tend to think it is. it is less important to "microoptimize" the coding details. Why don't C comments nest? Are they legal inside quoted strings? A: Nested comments would cause more harm than good. The character sequences /* and */ are not special within double-quoted strings. it is far more important that it be written clearly and portably than that it be written maximally efficiently.) It is notoriously difficult to predict what the "hot spots" in a program will be. 97. and Jon Bentley's Writing Efficient Programs.c topic. Reference: ANSI Rationale Sec. very fast. How can I make this code more efficient? A: Efficiency. mostly because of the possibility of accidentally leaving comments unclosed by including the characters "/*" within them. If you simply must know. Often. For this reason.) . though a favorite comp. and do not therefore introduce comments. substituting shift operators for multiplication by powers of two) are performed automatically by even simpleminded compilers. 33. When code is not time-critical. it is important to use profiling software to determine which parts of the program deserve attention. Many of the "efficient coding tricks" which are frequently suggested (e.~/pub/ioccc. as well as good advice on how to increase efficiency when it is important. if available. which can be sped up by using buffering and cacheing techniques. to see if two purported alternatives aren't compiled identically. actual computation time is swamped by peripheral tasks such as I/O and memory allocation. it is usually better to "comment out" large sections of code. When efficiency is a concern. (Often the differences are so slight that hundreds of thousands of iterations are required even to see them. you'll have to time test programs carefully. For more discussion of efficiency tradeoffs. Check the compiler's assembly language output. Heavyhanded "optimization" attempts can make code so bulky that performance is degraded. For the small fraction of code that is time-critical.g.9 p. and that even "inefficient" code can run without apparent delay. 98. 96.1. Are pointers really faster than arrays? Do function calls really slow things down? Is ++i faster than i = i + 1? A: Precise answers to these and many similar questions depend of course on the processor and compiler in use. (Remember that computers are very. which might contain comments. with #ifdef or #if 0 (but see question 33).

This article cannot begin to list the pitfalls associated with. contribute so much to modularity and code clarity that there is rarely good reason to avoid them. not a keystroke-programmable calculator. 99. i += 1. including Turbo C (and Ritchie's original PDP-11 compiler)." A: Some compilers for small machines. and correctly declared other functions returning double. the associative and distributive laws do not hold completely (i." otherwise a compiler for a machine without the "right" model would have to do prohibitively expensive emulations. Function calls. floating-point work. not efficiency. Among other things. Underflow or cumulative precision loss is often a problem. A good programming text should cover the basics. . order of operation may be important. either. and especially don't assume that floatingpoint values can be compared for equality. 100. Floating-point semantics are usually defined as "however the processor does them. leave out floating point support if it looks like it will not be needed. and workarounds appropriate for. A good compiler will generate identical code for ++i. (Don't throw haphazard "fuzz factors" in. %f. My floating-point calculations are acting strangely and giving me different answers on different machines. References: K&P Sec.It is "usually" faster to march through large arrays with pointers rather than array subscripts. but for some processors the reverse is true. The reasons for using ++i or i += 1 over i = i + 1 have to do with style. repeated addition is not necessarily equivalent to multiplication). Before rearranging expressions such as i = i + 1. Don't assume that floating-point results will be exact. A: Most digital computers use floating-point formats which provide a close but by no means exact simulation of real number arithmetic. though obviously incrementally slower than in-line code.) These problems are no worse for C than they are for any other computer language. I'm having trouble with a Turbo C program which crashes and says something like "floating point not loaded. It happens that Turbo C's heuristics for determining whether the program uses floating point are occasionally insufficient. In particular. and the programmer must sometimes insert a dummy explicit floating-point call to force loading of floating-point support. remember that you are dealing with a C compiler. and i = i + 1. and %g. the non-floating-point versions of printf and scanf save space by not including code to handle %e. 6 pp.e. 115-8. Do make sure that you have #included .

Eventually. and those which perform dynamic stack allocation automatically (e.grammar. it dies before the first statement in main. Many systems have fixed-size stacks.uu. The FSF's GNU C compiler contains a grammar. Where can I get extra copies of this list? What about back issues? A: For now.programmer). Cardiff. Where can I get a YACC grammar for C? A: The definitive grammar is of course the one in the ANSI standard.) 102.newusers frequently asked questions postings.) A: You probably have one or more very large (kilobyte or more) local arrays. keep your eyes open. . comp.c on the first of each month.2 . Trivia questions like these aren't any more pertinent for comp.msdos. will find a more receptive audience in a PC newsgroup (e. it is normally posted to comp. Problems with PC compilers.In general. just pull it off the net. USA).48. Does anyone have a C compiler test suite I can use? A: Plum Hall (1 Spruce Ave.c than they are for any of the other groups they frequently come up in. How do you pronounce "char"? What's that funny name for the "#" character? A: You can pronounce the C keyword "char" like the English words "char. Bell Labs once proposed the (now obsolete) term "octothorpe" for the "#" character.lang." the choice is arbitrary.os. You can find lots of information in the net. or via a mailserver.Z . Several copies are floating around. 104.g. This program crashes before it even runs! (When single-stepping with a debugger.96. with an Expiration: line which should keep it around all month.net (192. sells one.c.sources/ansi. and the Usenet ASCII pronunciation list. for instance.lang.lang. 103. It is often better to declare large arrays with static duration (unless of course you need a fresh set with each recursive call).g. the "jargon file" (also published as _The Hacker's Dictionary_)." or "car.2) in net.c .announce. 105. Unix) can be confused when the stack tries to grow by a huge chunk all at once. A. 101. as does the appendix to K&R II. NJ 08232. There is one on uunet.. among others." "care. questions about a particular compiler are inappropriate for comp. References: ANSI Sec. (See also question 59. it may be available for anonymous ftp.

Christopher Calabrese. Ray Dunn. Doug Gwyn. ISBN 0-13-110163-3. Clarke Thatcher. Bibliography ANSI American National Standard for Information Systems -.159-1989 (see question 29). John Lauro. Patricia Shanahan. Kirk Johnson. (A third edition has recently been released. and frequently beyond my endurance. Chris Torek. and Dave Wolverton. Chip Salzenberg.edu@mit. Joshua Simons. Second Edition. There is a more extensive bibliography in the revised Indian Hill style guide (see question 84). C: A Reference Manual. Ron Guilmette. Evan Manning. who (to borrow a line from Steve Johnson) have goaded me beyond my inclination. and particularly to Mark Brader. The C Programming Language. Prentice Hall. Second Edition.J. 1978. Doug Schmidt. Acknowledgements Thanks to Jamshid Afshar. ISBN 0-13-110362-8.mit. Tony Hansen. Kernighan and P. Larry Virden. H&S Samuel P. Kernighan and Dennis M. Raymond Chen. ISBN 0-13-868050-7. Joe Harrington. The Elements of Programming Style.mit. Prentice Hall.edu . Norm Diamond. Sudheer Apte. Erik Talvola. ISBN 0-201-17928-8. Pat Rankin. K&P Brian W. ISBN 0-13-109802-0. 1990.C. Stephen M. 0-13-110370-9. PrenticeHall. ISBN 0-13-970244-X. Harbison and Guy L. James Davies. Older copies are obsolete and don't contain much. 1978.This list is an evolving document. Guy Harris. Dunn. CT&P Andrew Koenig. ANSI X3. 1989. 1987.edu scs%adam. who have contributed. randall@virginia. Special thanks to Karl Heuer. K&R I Brian W. Freek Wiedijk. Plauger. Henry Spencer. Second Edition.) PCS Mark R. Andrew Koenig. Mark Moraes. C Traps and Pitfalls.Programming Language -. 1982. Christopher Lott. Rich Salz. Francois Pinard. Addison-Wesley. Portable C Software. Bjorn Engsig. ISBN 0-07-034207-5. Joe Buehler. Writing Efficient Programs. Ed Vielmetti. Blair Houghton. not just a collection of this month's interesting questions. except the occasional typo. Prentice Hall. Horton. The C Programming Language. McGraw-Hill. Prentice-Hall. Ritchie. K&R II Brian W. Ritchie. to this article. Paul Sand. Peter da Silva. that the current list doesn't. 1988. Kernighan and Dennis M. in relentless pursuit of a better FAQ list. Dan Bernstein. directly or indirectly. Tim McDaniel. Steele. Steve Summit scs@adam. Jon Louis Bentley.

1991 by Steve Summit. etc. It may be freely redistributed so long as the author's name. The C code in this article (vstrcat. error. and this notice. are retained.) is public domain and may be used without restriction. . 1990.mit-eddie!adam!scs This article is Copyright 1988.

Sign up to vote on this title
UsefulNot useful