Path: utzoo!attcan!uunet!olivea!mintaka!snorkelwacker.mit.edu!bloom-picayune.mit.edu!adam!scs From: scs@adam.mit.edu (Steve Summit) Newsgroups: comp.lang.c Subject: Changes to Answers to Frequently Asked Questions (FAQ) on comp.lang.c Message-ID: <1991Mar1.051329.14965@athena.mit.edu> Date: 1 Mar 91 05:13:29 GMT Sender: news@athena.mit.edu (News system) Reply-To: scs@adam.mit.edu (Steve Summit) Organization: Thermal Technologies, Inc., Cambridge, MA Lines: 794 This article contains changes between the previous posting of the frequently-asked questions list (posted on February 6) and the new one. (Do _not_ worry if you have not seen the new one yet; it's coming up next.) (These diffs have been edited for readability and are not suitable for the patch program.) ========== < [Last modified February 5, 1991 by scs.] --- > [Last modified February 28, 1991 by scs.] ========== > Besides listing frequently-asked questions, this article also summarizes > frequently-posted answers. Even if you know all the answers, it's worth > skimming through this list once in a while, so that when you see one of > its questions unwittingly posted, you won't have to waste time > answering. ========== discouraged. (Any object pointer may be cast to the "universal" pointer type void *, or char * under a pre-ANSI compiler, when < heterogeneous pointers must be passed around.) --- > heterogeneous pointers must be passed around.) It is no longer > guaranteed that a pointer can be cast to a "suitably capacious" > integer and back, unchanged. ========== < A: As a stylistic convention, many people prefer not to have unadorned < 0's scattered throughout their programs. For this reason, the --- > A: As a matter of style, many people prefer not to have unadorned 0's > scattered throughout their programs. For this reason, the ========== < NULL should _only_ be used for pointers. It should not be used when < another kind of 0 is required, even though it might work, because < doing so sends the wrong stylistic message. (ANSI allows the < #definition of NULL to be (void *)0, which will not work in non- < pointer contexts.) In particular, do not use NULL when the ASCII < null character (NUL) is desired. Provide your own definition < < #define NUL '\0' < < if you must. --- > NULL should _only_ be used for pointers; see question 9. ========== < A: This trick, though popular with beginning programmers, does not buy < much. --- > A: This trick, though popular in some circles, does not buy much. ========== > "Abbreviations" such as if(p), though perfectly legal, are > considered by some to be bad style. ========== < distinguishing pointer 0's from integer 0's. Again, NULL should not < be used for other than pointers. --- > distinguishing pointer 0's from integer 0's. > > NULL should _not_ be used when another kind of 0 is required, even > though it might work, because doing so sends the wrong stylistic > message. (ANSI allows the #definition of NULL to be (void *)0, > which will not work in non-pointer contexts.) In particular, do > not use NULL when the ASCII null character (NUL) is desired. > Provide your own definition > > #define NUL '\0' > > if you must. ========== 11. I once used a compiler that wouldn't work unless NULL was used. < A: That compiler was broken. In general, making decisions about a --- > A: Unless the code being compiled was nonportable (see question 6), > that compiler was probably broken. In general, making decisions ========== < This article always uses the phrase "null pointer" for sense 1, the < character "0" for sense 3, and the capitalized word "NULL" for < sense 4. --- > This article always uses the phrase "null pointer" (in lower case) > for sense 1, the character "0" for sense 3, and the capitalized > word "NULL" for sense 4. ========== > 15. Given all the confusion surrounding null pointers, wouldn't it be > easier simply to require them to be represented internally by > zeroes? > > A: If for no other reason, doing so would be ill-advised because it > would unnecessarily constrain implementations which would otherwise > naturally represent null pointers by special, nonzero bit patterns, > particularly when those values would trigger automatic hardware > traps for invalid accesses. > > Besides, what would this requirement really accomplish? Proper > understanding of null pointers does not require knowledge of the > internal representation, whether zero or nonzero. Assuming that > null pointers are internally zero does not make any code easier to > write (except for a certain ill-advised usage of calloc; see > question 57). Known-zero internal pointers would not obviate casts > in function calls, because the _size_ of the pointer might still be > different from that of an int. (If "nil" were used to request null > pointers rather than "0," as mentioned in question 13, the urge to > assume an internal zero representation would not even arise.) > > 16. Seriously, have any actual machines really used nonzero null > pointers? > > A: "Certain Prime computers use a value different from all- > bits-0 to encode the null pointer. Also, some large > Honeywell-Bull machines use the bit pattern 06000 to encode > the null pointer. On such machines, the assignment of 0 to > a pointer yields the special bit pattern that designates the > null pointer." > > -- Portable C, by H. Rabinowitz and Chaim Schaap, > Prentice-Hall, 1990, page 147. > > The "certain Prime computers" were the segmented 50 series, which > used segment 07777, offset 0 for the null pointer, at least for > PL/I. Later models used segment 0, offset 0 for null pointers in > C, necessitating new instructions such as TCNP (Test C Null > Pointer), evidently as a sop to all the extant poorly-written C > code which made incorrect assumptions. > > The Symbolics Lisp Machine, a tagged architecture, does not even > have conventional numeric pointers; it uses the pair > (basically a nonexistent handle) as a C null > pointer. ========== 16. But I heard that char a[] was identical to char *a. < A: This identity (that a pointer declaration is interchangeable with an < array declaration, usually unsized) holds _only_ for formal < parameters to functions. This identity is related to the fact that < arrays "decay" into pointers in expressions. That is, when an array < name is mentioned in an expression, it is converted immediately into < a pointer to the array's first element. Therefore, an array is < never passed to a function; rather a pointer to its first element is < passed instead. Allowing pointer parameters to be declared as < arrays is a simply a way of making it look as though the array was < actually being passed. Some programmers prefer, as a matter of < style, to use this syntax to indicate that the pointer parameter is < expected to point to the start of an array rather than to some < single value. < < Since functions can never receive arrays as parameters, any < parameter declarations which "look like" arrays, e.g. < < f(a) < char a[]; < < are treated as if they were pointers, since that is what the < function will receive if an array is passed: < < f(a) < char *a; < < To repeat, however, this conversion holds only within function < formal parameter declarations, nowhere else. If this conversion < bothers you, don't use it; many people have concluded that the < confusion it causes outweighs the small advantage of having the < declaration "look like" the call and/or the uses within the < function. --- > A: Not at all. (What you heard has to do with formal parameters to > functions; see question 21.) Arrays are not pointers. The > declaration "char a[6];" requests that space for six characters be > set aside, to be known by the name "a." That is, there is a > location named "a" at which six characters can sit. The > declaration "char *p;" on the other hand, requests a place which > holds a pointer. The pointer is to be known by the name "p," and > can point to any char (or contiguous array of chars) anywhere. > > As usual, a picture is worth a thousand words. The statements > > char a[] = "hello"; > char *p = "world"; > char *p2 = a; > > would result in data structures which could be represented like > this: > > +---+---+---+---+---+---+ > a: | h | e | l | l | o |\0 | > +---+---+---+---+---+---+ > ^ > | > +--|--+ > p2: | * | > +-----+ > > +-----+ +---+---+---+---+---+---+ > p: | *======> | w | o | r | l | d |\0 | > +-----+ +---+---+---+---+---+---+ > > 19. You mean that a reference like x[3] generates different code > depending on whether x is an array or a pointer? > > A: Precisely. Referring back to the sample declarations in the > previous question, when the compiler sees the expression a[3], it > emits code to start at the location "a," move three past it, and > fetch the character there. When it sees the expression p[3], it > emits code to start at the location "p," fetch the pointer value > there, add three to the pointer, and finally fetch the character > pointed to. In the example above, both a[3] and p[3] (and p2[3], > for that matter) happen to be the character 'l', but that the > compiler gets there differently. (See also question 100.) ========== 17. 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. Saying that arrays and pointers < are "equivalent" does not by any means imply that they are < interchangeable. (The fact that, as formal parameters to functions, < array-style and pointer-style declarations are in fact < interchangeable does nothing to reduce the confusion.) < < "Equivalence" refers to the fact (mentioned above) that arrays decay < into pointers within expressions, and that pointers and arrays can < both be dereferenced using array-like subscript notation. That is, < if we have < < char a[10]; < char *p = a; < int i; < < we can refer to a[i] and p[i]. (That pointers can be subscripted < like arrays is hardly surprising, since arrays have decayed into < pointers by the time they are subscripted.) ========== > A: Much of the confusion surrounding pointers in C can be traced to a > misunderstanding of this statement. Saying that arrays and > pointers are "equivalent" does not by any means imply that they are > interchangeable. > > "Equivalence" refers to the following key definition: > > An identifier of type array-of-T which appears in an > expression decays (with three exceptions) into a pointer to > its first element; the type of the resultant pointer is > pointer-to-T. > > (The exceptions are when the array is the operand of the sizeof() > operator or of the & operator, or is a literal string initializer > for a character array.) > > As a consequence of this definition, there is not really any > difference in the behavior of the "array subscripting" operator [] > as it applies to arrays and pointers. In an expression of the form > a[i], the array name "a" decays into a pointer, following the rule > above, and is then subscripted exactly as would be a pointer > variable in the expression p[i]. In either case, the expression > x[i] (where x is an array or a pointer) is, by definition, exactly > equivalent to *((x)+(i)). > > 21. Then why are array and pointer declarations interchangeable as > function formal parameters? > > A: Since arrays decay immediately into pointers, an array is never > actually passed to a function. Allowing pointer parameters to be > declared as arrays is a simply a way of making it look as though > the array was being passed. Some programmers prefer, as a matter > of style, to use this syntax to indicate that the pointer parameter > is expected to point to the start of an array rather than to some > single value. > > Since functions can never receive arrays as parameters, any > parameter declarations which "look like" arrays, e.g. > > f(a) > char a[]; > > are treated by the compiler as if they were pointers, since that is > what the function will receive if an array is passed: > > f(a) > char *a; > > To repeat, however, this conversion holds only within function > formal parameter declarations, nowhere else. If this conversion > bothers you, don't use it; many people have concluded that the > confusion it causes outweighs the small advantage of having the > declaration "look like" the call and/or the uses within the > function. ========== > 22. Someone explained to me that arrays were really just constant > pointers. > > A: That person did you a disservice. An array name is "constant" in > that it cannot be assigned to, but an array is _not_ a pointer, as > the discussion and pictures in question 18 should make clear. ========== A: Yes, Virginia, array subscripting is commutative in C. This curious fact follows from the pointer definition of array subscripting, namely that a[e] is exactly equivalent to *((a)+(e)), for _any_ < expression e and primary expression a, as long as one of them is a < pointer expression. This unsuspected commutativity is often --- > for _any_ expression e and primary expression a, as long as one of > them is a pointer expression and one is integral. This unsuspected ========== < Pointers to arrays are confusing, and it is best to avoid them. --- > Pointers to arrays can be confusing, and must be treated carefully. ========== In the first declaration, the compiler performs the usual implicit rewriting of "array of array" to "pointer to array;" in the second < form the pointer declaration is explicit. The called function does < not care how big the array is, but it must know its shape, so the < "column" dimension XSIZE must be included. In both cases the number < of "rows" is irrelevant, and omitted. --- > the second form the pointer declaration is explicit. Since the > called function does not allocate space for the array, it does not > need to know the overall size, so the number of "rows," YSIZE, can > be omitted. The "shape" of the array is still important, so the > "column" dimension XSIZE (and, for 3- or more dimensional arrays, > the intervening ones) must be included. ========== The order of other embedded side effects is similarly undefined. < For example, the expression i + (i = 2) may or may not have the < value 4. --- > For example, the expression i + (i = 2) does not necessarily yield > 4. ========== > The Rationale, by itself, has been printed by Silicon Press, ISBN > 0-929306-07-4. ========== 26. Does anyone have a tool for converting old-style C programs to ANSI C, or for automatically generating prototypes? < A: There are several such programs, many in the public domain. Check < your nearest comp.sources archive. --- > A: Two programs, protoize and unprotoize, are being written to convert > back and forth between prototyped and "old style" function > definitions and declarations. (These programs are _not_ expected > to handle full-blown conversion between "Classic" C and ANSI C.) > When available, these programs will exist as patches to the FSF GNU > C compiler, gcc. > > Several prototype generators exist, many as modifications to lint. ========== > 32. 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); "char * const p" is a constant pointer to a > (variable) character (i.e. you can't change the pointer). (Read > these "inside out" to understand them. See question 69.) ========== Old C (and ANSI C, in the absence of prototypes) silently promotes floats to doubles when passing them as arguments, < and makes a corresponding silent change to formal parameter < declarations, so the old-style definition actually says that func < takes a double. --- > as arguments, and arranges that doubles being passed are coerced > back to floats if the formal parameters are declared that way. ========== (In this case, it would be clearest to change the old-style < definition to use double as well). --- > definition to use double as well, as long as the address of that > parameter is not taken.) ========== > 36. What was noalias and what ever happened to it? > > A: noalias was another type qualifier, in the same syntactic class as > const and volatile, which was intended to assert that the object > pointed to was not also pointed to ("aliased") by other pointers. > The primary application, which is an important one, would have been > for the formal parameters of subroutines designed to perform > computations on large arrays. A compiler can not usually take > advantage of vectorization or other parallelization hardware (on > supercomputers which have it) unless it can ensure that the source > and destination arrays do not overlap. > > The noalias keyword was not backed up by any "prior art," and it > was introduced late in the review and approval process. It was > phenomenally difficult to define precisely and explain coherently, > and sparked widespread, acrimonious debate, including a scathing > pan by Dennis Ritchie. It had far-ranging implications, > particularly on several standard library interfaces, for which easy > fixes were not readily apparent. > > Because of the criticism and the difficulty of defining noalias > well, the Committee wisely declined to adopt it, in spite of its > superficial attractions. (When writing a standard, features cannot > be introduced halfway; their full integration, and all > implications, must be understood.) The need for a mechanism to > support parallel implementation of non-overlapping operations > remains unfilled (although the C Numerical Extensions Working Group > is examining the problem). > > References: ANSI Sec. 3.9.6 . > > 37. What are #pragmas and what are they good for? > > A: The #pragma directive (based on a similar feature in Ada, of all > things) provides a single, well-defined "escape hatch" which can be > used for all sorts of implementation-specific controls and > extensions: source listing control, structure packing, warning > suppression (like the old lint /* NOTREACHED */ comments), etc. > > References: ANSI Sec. 3.8.6 . ========== If all of the statements in the intended macro are simple < expressions, with no declarations, another technique is to separate < them with commas and surround them with parentheses. --- > expressions, with no declarations, conditionals, or loops, another > technique is to write a single, parenthesized expression using one > or more comma operators. (This technique also allows a value to be > "returned.") ========== 34. How can I write a function that takes a variable number of arguments? < A: Use varargs or stdarg. --- > A: Use the header (or, if you must, the older ). ========== If you know how to access arguments "by hand," but have access to neither < nor , you could as easily implement one of < them yourself, leaving your code portable.) --- > nor , you could as easily implement > yourself, leaving your code portable.) ========== < To use varargs, instead of stdarg, change the function header to: --- > To use the older package, instead of , change > the function header to: ========== That the "other half," better error detection, was deferred to lint, was a fairly deliberate decision on the part of the earliest Unix C compiler authors, but is inexcusable (in the absence of a supplied, < consistent lint) in a modern compiler. --- > supplied, consistent lint, or equivalent error checking) in a > modern compiler. ========== > The System V release 4 lint is ANSI-compatible, and is available > separately (bundled with other C tools) from Unix Support Labs (a > subsidiary of AT&T), or from System V resellers. ========== 42. Don't ANSI function prototypes render lint obsolete? < A: No. First of all, prototypes work well only if the programmer works --- > A: Not really. First of all, prototypes work well only if the ========== A: Again, the problem is that space for the concatenated result is not < properly allocated. C does not provide a true string type. C < programmers use char *'s for strings, but must always keep < allocation in mind. The compiler will only allocate memory for < objects explicitly mentioned in the source code (in the case of < "strings," this includes character arrays and string literals). --- > properly allocated. C does not provide an automatically-managed > string type. C compilers only allocate memory for objects > explicitly mentioned in the source code (in the case of "strings," ========== < The simple strcat example could be fixed with something like --- > strcat performs no allocation; the second string is appended to the > first one, in place. Therefore, one fix would be to declare the > first string as an array with sufficient space: ========== < Note, however, that strcat appends the string pointed to by its < second argument to that pointed to by the first, and merely returns < its first argument, so the s3 variable is superfluous. --- > Since strcat returns its first argument, the s3 variable is > superfluous. ========== > 55. How does free() know how many bytes to free? > > A: The malloc/free package remembers the size of each block it > allocates and returns, so it is not necessary to remind it of the > size when freeing. > > 56. 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(..., 0), which > frees), but several earlier implementations do not support it, so > it is not widely portable. Passing an initially-null pointer to > realloc can make it easy to write a self-starting incremental > allocation algorithm. > > References: ANSI Sec. 4.10.3.4 . > > 57. 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, or do you > need a cfree? > > A: calloc(m, n) is essentially equivalent to > > p = malloc(m * n); > memset(p, 0, m * n); > > The zero fill is all-bits-zero, and does not therefore guarantee > useful zero values for pointers (see questions 1-16) or floating- > point values. free can (and should) be used to free the memory > allocated by calloc. > > References: ANSI Secs. 4.10.3 to 4.10.3.2 . ========== Structures are typically returned from functions in a location < pointed to by an extra, "hidden" argument to the function. Older --- > pointed to by an extra, compiler-supplied "hidden" argument to the ========== A: A missing semicolon causes the compiler to believe that main returns a struct list. (The connection is hard to see because of the < intervening comment.) When struct-valued functions are implemented < by adding a hidden return pointer, the generated code tries to store < a struct with respect to a pointer which was not actually passed (in < this case, by the C start-up code). Attempting to store a structure < into memory pointed to by the argc or argv value on the stack (where < the compiler expected to find the hidden return pointer) causes the < core dump. --- > the intervening comment.) Since struct-valued functions are > usually implemented by adding a hidden return pointer, the > generated code for main() actually expects three arguments, > although only two were passed (in this case, by the C start-up > code). See also question 103. ========== 53. How can I determine the byte offset of a field within a structure? A: ANSI C defines the offsetof macro, which should be used if < available. If you don't have it, a suggested implementation is --- > available; see . If you don't have it, a suggested ========== > 66. How do you decide which integer type to use? > > A: If you might need large values (above 32767 or below -32767), use > long. If space is very important (there are large arrays or many > structures), use short. Otherwise, use int. If well-defined > overflow characteristics are important and/or sign is not, use > unsigned. > > Similar arguments operate when deciding between float and double. > Exceptions apply if the address of a variable is taken and must > have a particular type. > > In general, don't try to use char or unsigned char as a "tiny" int > type; doing so is often more trouble than it's worth. ========== < Any good book on C should explain techniques for reading these < complicated C declarations "inside out" to understand them --- > Any good book on C should explain how to read these complicated C > declarations "inside out" to understand them ("declaration mimics ========== When the name of a function appears in an expression but is not being called (i.e. is not followed by a "("), it "decays" into a < pointer (i.e. its address is implicitly taken), analagously to the < implicit decay of an array into a pointer to its first element. --- > pointer (i.e. it has its address implicitly taken), much as an > array name does. ========== < The advantages of enums are that the numeric values are < automatically assigned, that a debugger may be able to display the < symbolic values when enum variables are examined, and that a < compiler may generate nonfatal warnings when enums and ints are < indiscriminately mixed (such mixing can still be considered bad < style even though it is not strictly illegal). --- > The primary advantages of enums are that the numeric values are > automatically assigned, and that a debugger may be able to display > the symbolic values when enum variables are examined. (A compiler > may also generate nonfatal warnings when enums and ints are > indiscriminately mixed, since doing so can still be considered bad > style even though it is not strictly illegal). A disadvantage is > that the programmer has little control over the size. ========== 66. How can my program discover the complete pathname to the executable file from which it was invoked? < A: Depending on the operating system, argv[0] may contain all or part < of the pathname. (It may also contain nothing.) 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 incomplete. < However, there is no guaranteed or portable solution. --- > A: argv[0] may contain all or part of the pathname, or it may contain > nothing. 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. However, there is no > guaranteed or portable solution. ========== 67. How can a process change an environment variable in its caller? Under Unix, a process can modify its own environment (some systems < provide setenv() or putenv() functions to do this), and the modified < environment is passed on to any child processes, but it is _not_ --- > provide setenv() and/or putenv() functions to do this), and the > modified environment is usually passed on to any child processes, ========== < A: It is best to use an explicit fflush(stdout) at any point within < your program at which output should definitely be visible. Several --- > A: It is best to use an explicit fflush(stdout) whenever output should > definitely be visible. Several mechanisms attempt to perform the ========== < The position of braces is less important; we have < chosen one of several popular styles. Pick a style < that suits you, then use it consistently. --- > The position of braces is less important, although > people hold passionate beliefs. We have chosen one > of several popular styles. Pick a style that suits > you, then use it consistently. > > Reference: K&R Sec. 1.2 p. 10. ========== > 89. What can I safely assume about the initial values of variables > which are not explicitly initialized? If global variables start > out as "zero," is that good enough for null pointers and floating- > point zeroes? > > A: Variables (and arrays) with "static" duration (that is, those > declared outside of functions, and those declared with the storage > class static), are guaranteed initialized to zero, as if the > programmer had typed "= 0". Therefore, such variables are > initialized to the null pointer (of the correct type) if they are > pointers, and to 0.0 if they are floating-point. This requirement > means that compilers and linkers on machines which use nonzero > internal representations for null pointers and/or floating-point > zeroes cannot necessarily make use of uninitialized, 0-filled > memory, but must emit explicit initializers for these values > (rather as if the programmer had). > > Variables with "automatic" duration (i.e. local variables without > the static storage class) start out containing garbage, unless they > are explicitly initialized. Nothing useful can be predicted about > the garbage. > > Dynamically-allocated memory obtained with malloc and realloc is > also likely to contain garbage, and must be initialized by the > calling program, as appropriate. Memory obtained with calloc > contains all-bits-0, but this is not necessarily useful for pointer > or floating-point values (see question 57). ========== printable string. How can I perform the inverse operations of converting a struct tm or a string into a time_t? Converting a string to a time_t is harder, because of the wide variety of date and time formats which should be parsed. Public- domain routines have been written for performing this function, as < well, but they are less likely to become standardized. --- > well (see, for example, the file partime.c, widely distributed with > the RCS package), but they are less likely to become standardized. ========== The usual approach is to use anonymous ftp and/or uucp from a < central, public-spirited site, such as uunet.uu.net. However, this --- > central, public-spirited site, such as uunet.uu.net (192.48.96.2). ========== > various items. The "archie" mailserver can tell you which > anonymous ftp sites have which packages; send the mail message > "help" to archie@quiche.cs.mcgill.ca for information. ========== > 99. How can I make this code more efficient? > > A: Efficiency, though a favorite comp.lang.c topic, is not important > nearly as often as people tend to think it is. Most of the code in > most programs is not time-critical. When code is not time- > critical, it is far more important that it be written clearly and > portably than that it be written maximally efficiently. (Remember > that computers are very, very fast, and that even "inefficient" > code can run without apparent delay.) > > It is notoriously difficult to predict what the "hot spots" in a > program will be. When efficiency is a concern, it is important to > use profiling software to determine which parts of the program > deserve attention. Often, actual computation time is swamped by > peripheral tasks such as I/O and memory allocation, which can be > sped up by using buffering and cacheing techniques. > > For the small fraction of code that is time-critical, it is vital > to pick a good algorithm; it is much less important to > "microoptimize" the coding details. Source-level optimizations > rarely make significant improvements, and often render code opaque. > Many of the "efficient coding tricks" which are frequently > suggested (e.g. substituting shift operators for multiplication by > powers of two) are performed automatically by even simpleminded > compilers. Heavyhanded "optimization" attempts can make code so > bulky that performance is degraded. If the performance of your > code is so important that you are willing to invest programming > time in source-level optimizations, you would be better served by > buying the best optimizing compiler you can afford (compilers can > perform optimizations that are impossible at the source level). > > It is not the intent here to suggest that efficiency can be > completely ignored. Most of the time, however, by simply paying > attention to good algorithm choices, implementing them clearly and > obviously, and avoiding obviously inefficient blunders (i.e. shun > O(n**3) implementations of O(n**2) algorithms), perfectly > acceptable results can be achieved. > > 100. 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. If you simply must know, you'll > have to time test programs carefully. (Often the differences are > so slight that hundreds of thousands of iterations are required > even to see them. Check the compiler's assembly language output, > if available, to see if two purported alternatives aren't compiled > identically.) > > It is "usually" faster to march through large arrays with pointers > rather than array subscripts, but for some processors the reverse > is true. > > Function calls, though obviously incrementally slower than in-line > code, contribute so much to modularity and code clarity that there > is rarely good reason to avoid them. (Actually, by reducing bulk, > functions can improve performance.) > > Before rearranging expressions such as i = i + 1, remember that you > are dealing with a C compiler, not a keystroke-programmable > calculator. A good compiler will generate identical code for i++, > i += 1, and i = i + 1. The reasons for using i++ or i += 1 over > i = i + 1 have to do with style, not efficiency. ========== 86. My floating-point calculations are acting strangely and giving me different answers on different machines. programming text should cover the basics. (Beware, though, that < subtle problems can occupy numerical analysts for years.) --- > subtle problems can occupy numerical analysts for years.) Do make > sure that you have #included , and correctly declared other > functions returning double. ========== > 103. This program crashes before it even runs! (When single-stepping > with a debugger, it dies before the first statement in main.) > > A: You probably have one or more very large (kilobyte or more) local > arrays. Many systems have fixed-size stacks, and those which > perform dynamic stack allocation automatically (e.g. Unix) are often > confused when the stack tries to grow by a huge chunk all at once. > > It is often better to declare large arrays with static duration > (unless of course you need a fresh set with each recursive call). ========== Trivia questions like these aren't any more pertinent for comp.lang.c than they are for any of the other groups they < frequently come up in. The "jargon file" (also published as _The < Hacker's Dictionary_) contains lots of tidbits like these, as does --- > frequently come up in. You can find lots of information in the > net.announce.newusers frequently-asked questions postings, the > "jargon file" (also published as _The Hacker's Dictionary_), and ========== 91. Where can I get extra copies of this list? What about back issues? < A: For now, just pull it off the net; it is normally posted on the < first of each month, with an Expiration: line which should keep it --- > A: For now, just pull it off the net; it is normally posted to > comp.lang.c on the first of each month, with an Expiration: line ========== > Thanks to Sudheer Apte, Joe Buehler, Raymond Chen, Christopher > Calabrese, James Davies, Norm Diamond, Ray Dunn, Stephen M. Dunn, Bjorn > Engsig, Ron Guilmette, Doug Gwyn, Tony Hansen, Joe Harrington, Guy > Harris, Blair Houghton, Kirk Johnson, Andrew Koenig, John Lauro, > Christopher Lott, Tim McDaniel, Evan Manning, Mark Moraes, Francois > Pinard, randall@virginia, Pat Rankin, Rich Salz, Chip Salzenberg, Paul > Sand, Doug Schmidt, Patricia Shanahan, Peter da Silva, Joshua Simons, > Henry Spencer, Erik Talvola, Clarke Thatcher, Chris Torek, Ed Vielmetti, > Larry Virden, Freek Wiedijk, and Dave Wolverton, who have contributed, > directly or indirectly, to this article. Special thanks to Karl Heuer, > and particularly to Mark Brader, who (to borrow a line from Steve > Johnson) have goaded me beyond my inclination, and frequently beyond my > endurance, in relentless pursuit of a better FAQ list. ========== < This article is Copyright 1988, 1990 by Steve Summit. --- > This article is Copyright 1988, 1990, 1991 by Steve Summit. ==========