[comp.lang.c] Answers to Frequently Asked Questions on comp.lang.c

scs@adam.mit.edu (Steve Summit) (05/18/90)

Certain topics come up again and again on this newsgroup.  They are good
questions, and the answers may not be immediately obvious, but each time
they recur, much net bandwidth and reader time is wasted on repetitive
responses, and on tedious corrections to the incorrect answers which are
inevitably posted.

This article, which will be reposted periodically, attempts to answer
these common questions definitively and succinctly, so that net
discussion can move on to more constructive topics without continual
regression to first principles.

This article does not, and cannot, provide an exhaustive discussion of
all of the subtle points and counterarguments which could be mentioned
with respect to these topics.  Cross-references to standard C
publications have been provided, for further study by the interested and
dedicated reader.  A few of the more perplexing and pervasive topics are
further explored in some in-depth minitreatises which are periodically
posted in conjunction with this article.

No mere newsgroup article can substitute for thoughtful perusal of a
full-length language reference manual.  Anyone interested enough in C to
be following this newsgroup should also be interested enough to read and
study one or more such manuals, preferably several times.  Some vendor's
compiler manuals are unfortunately inadequate; a few even perpetuate
some of the myths which this article attempts to debunk.  Two invaluable
references, which are an excellent addition to any serious programmer's
library, are:

     The C Programming Language, by Brian W. Kernighan and Dennis M.
     Ritchie.

     C: A Reference Manual, by Samuel P. Harbison and Guy L. Steele, Jr.

Both exist in several editions.

If you have a question about C which is not answered in this article,
please try to answer it by referring to these or other books, or to
knowledgable colleagues, before posing your question to the net at
large.  There are many people on the net who are happy to answer
questions, but the volume of repetitive answers posted to one question,
as well as the growing numbers of questions as the net attracts more
readers, can become oppressive.  If you have questions or comments
prompted by this article, please reply by mail rather than following up
-- this article is meant to decrease net traffic, not increase it.

This article is still under development.  Your input is welcomed.  In
particular, I am soliciting:

1.  cross-referencing suggestions, particularly to the ANSI C standard,
    a copy of which I don't yet have;

2.  additions to the Pascal-to-C translators list (question 40; I know
    there are some commercial programs out there) and to any other
    product lists, since I don't want to imply disfavor by not
    mentioning one; and

3.  answers to the questions at the end which, though frequent, have not
    been of enough interest to me that I've paid attention to them.

Send your comments to scs@adam.mit.edu, disregarding the From: line in
this article's header, which may be incorrect.

Herewith, some frequently-asked questions and their answers:

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 -- "null" -- 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 "return" null, nor will malloc.
    Note that there is a null pointer for each pointer type, and that
    different pointer types (e.g. char * and int *) may have _different_
    null pointers.

    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.

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 assignment or comparison when one side is a variable of
    pointer type, the compiler can tell that a constant 0 on the other
    side is really a null pointer, and take appropriate action.
    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-
    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," so 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:

         0 or NULL okay:          cast required:

         assignments              function call,
                                  no prototype in scope
         comparisons
                                  variable argument to
         function call,           varargs function
         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.

3.  But aren't pointers the same as ints?

A:  Not since the early days.  It is now merely guaranteed that a
    pointer to an object may be cast to a "suitably capacious" integral
    type, and back, without change, but how large the type is is not
    specified (it may be larger than a long int) and the rule does _not_
    apply to pointers to functions.

    References: K&R I Sec. 5.6 pp. 102-3.

4.  What is NULL and how is it #defined?

A:  As a stylistic convention, many people prefer not to have unadorned
    0's scattered throughout their programs.  For this reason, the
    preprocessor macro NULL is #defined (by stdio.h or stddef.h), 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.

    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.  In particular, do not
    use NULL when the ASCII nul character is desired.  Provide your own
    definition

        #define NUL '\0'

    if you must.

    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.

5.  How should NULL be #defined on a machine which uses a nonzero bit
    pattern as the internal representation of the null pointer?

A:  Until now, no mention has been made of the internal representation
    of the null pointer.  Programmers should never need to know the
    details of this representation, because it is 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.

6.  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 kinds of pointers for 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.

    Nevertheless, ANSI C allows the alternate

        #define NULL (void *)0

    definition for NULL.  Besides helping incorrect programs to work
    (but only on machines with all pointers the same, thus questionably
    valid assistance) this definition may catch programs which use NULL
    incorrectly (e.g. when the ASCII nul character was really intended).

7.  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,
    while, for, and do statements, and with the &&, ||, !, and ?:
    operators), a false value is produced when the expression is equal
    to zero, and a true value otherwise.  That is, whenever one writes

        if(expr)

    where "expr" is any expression at all, the compiler essentially acts
    as if it had been written as

        if(expr != 0)

    Substituting the trivial pointer expression "p" for "expr," we have

         if(p)     is equivalent to              if(p != 0)

    and this is a comparison context, so the compiler can tell that the
    (implicit) 0 is a null pointer, and use the correct value.  There is
    no trickery involved here; compilers do work this way, and generate
    identical code for both statements.  The internal representation of
    a pointer does not matter.

    The boolean negation operator, !, 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)

    References: K&R II Sec. A7.4.7 p. 204; H&S Sec. 5.3 p. 91.

8.  If "NULL" and "0" are equivalent, which should I use?

A:  Many programmers believe that "NULL" should be used in all pointer
    contexts, as a reminder that the value is to be thought of as a
    pointer.  Others feel that the confusion surrounding "NULL" and "0"
    is only compounded by hiding "0" behind a #definition, and prefer to
    use unadorned "0" instead.  There is no one right answer.  C
    programmers must understand that "NULL" and "0" are interchangeable
    and that an uncast "0" is perfectly acceptable in assignment and
    comparison contexts.  Any usage of "NULL" (as opposed to "0") should
    be considered a gentle reminder; programmers should not depend on it
    (either for their own understanding or the compiler's) for
    distinguishing pointer 0's from integer 0's.  Again, NULL should not
    be used for other than pointers.

    References: K&R II Sec. 5.4 p. 102.

9.  But wouldn't it be better to use NULL (rather than 0) in case the
    value of NULL changes, perhaps on a machine with nonzero null
    pointers?

A:  No.  NULL is _not_ defined as a preprocessor macro because its value
    might change.  That source-code 0's generate null pointers is
    guaranteed by the language.  NULL is used only as a stylistic
    convention.

10. I'm confused.  NULL is guaranteed to be 0, but the null pointer is
    not?

A:  A "null pointer" (written in lower case in this article) is a
    language concept whose particular internal value does not matter.
    (On some machines the internal value is 0; on others it is not.)  A
    "null pointer" is requested in source code with the character '0'.
    "NULL" (always in capital letters) is a preprocessor macro, which is
    always #defined as 0 (or (void *)0).

11. 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.  The fact that null
    pointers are represented both in source code, and internally to most
    machines, as zero invites unwarranted assumptions.  The fact that a
    preprocessor macro (NULL) is often used suggests that this is done
    so because the value might change, or on some weird machine.

    One good way to wade out of the confusion is to imagine that C had a
    keyword (perhaps "nil", like Pascal) with which null pointers were
    requested.  The compiler could either turn "nil" into the correct
    type of null pointer when it could determine the type from the
    source code (as it does with 0's in reality) or complain when it
    could not.  Now, in fact, in C the keyword for a null pointer is not
    "nil" but '0', which works almost as well, except that an uncast '0'
    in a non-pointer context generates an integer zero.  If null were
    "nil" the compiler could emit an error message for an ambiguous
    usage, but since it is '0' the compiler may end up emitting
    incorrect code.

Arrays and Pointers

12. I had the declaration char a[5] in one source file, and in another I
    declared extern char *a.  Why didn't it work?

A:  The declaration extern char *a simply does not match the actual
    definition.  The type "pointer-to-type-T" is not the same as
    "array-of-type-T."  Use extern char a[].

13. But I heard that char a[] was identical to char *a.

A:  This identity (that a pointer declaration is interchangeable with an
    array, usually unsized) holds _only_ for formal arguments to
    functions.  This identity falls out of the fact that arrays "turn
    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.  Since functions can never receive arrays as
    arguments, any argument 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 argument declarations, nowhere else.

    References: K&R I Sec. 5.3 p. 95, Sec. A10.1 p. 205; K&R II Sec. 5.3
    p. 100, Sec. A8.6.3 p. 218, Sec. A10.1 p. 226; H&S Sec. 5.4.3 p. 96.

14. So what is meant by the "equivalence of pointers and arrays" in C?

A:  Perhaps no aspect of C is more confusing than pointers, and no
    statement has compounded this confusion more than the one above.
    Saying that arrays and pointers are "equivalent" does not by any
    means imply that they are interchangeable.  (The fact that, as
    formal arguments 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 "turn
    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;
        int i;

    we can refer to a[i] and p[i].  (That pointers can be subscripted
    like arrays is hardly surprising, since arrays are also pointers by
    the time they are subscripted.)

    References: K&R I Sec. 5.3 pp. 93-6; K&R II Sec. 5.3 p. 99; H&S Sec.
    5.4.1 p. 93.

Order of Evaluation

15. Under my compiler, the program

         int i = 7;
         printf("%d\n", i++ * i++);

    prints 49.  Regardless of the order of evaluation, shouldn't it
    print 56?

A:  Although the postincrement and postdecrement operators ++ and --
    perform the operations after yielding the former value, many people
    misunderstand the implication of "after." 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.  It
    is merely guaranteed that the update will be performed sometime
    before the expression is considered "finished" (before the next
    "sequence point," in ANSI C's terminology).

    In the example, the compiler chose to multiply the previous value by
    itself and to perform both increments afterwards.

    References: K&R I Sec. 2.12 p. 50; K&R II Sec. 2.12 p. 54.

ANSI C

16. What is the "ANSI C Standard?"

A:  In 1983, the American National Standards Institute commissioned a
    committee, X3J11, to standardize the C language.  After a long and
    arduous process, this C standard was finally ratified as an American
    National Standard, X3.159-1989, in the spring of 1990.  For the most
    part, ANSI C standardizes existing practice, with a few additions
    from C++ (most notably function prototypes) and support for
    multinational character sets (including the much-lambasted trigraph
    sequences for transfer of source code between machines with
    deficient or multinational character sets).  The ANSI C standard
    also formalizes the C run-time library support routines, an
    unprecedented effort.

17. How can I get a copy of the ANSI C standard?

A:  Copies are available from

        American National Standards Institute
        1430 Broadway
        New York, NY  10018
        (212) 642-4900

    or

        Global Engineering Documents
        2805 McGaw Avenue
        Irvine, CA  92714
        (714) 261-1455

    The cost is approximately $50.00, plus $6.00 shipping.

C Preprocessor

18. How can I write a macro to swap two values?

A:  There is no good answer to this question.  If the values are
    integers, a well-known trick using exclusive-OR can be used, but it
    will not work for floating-point values or pointers.  If the macro
    is intended to be used on values of arbitrary type (the usual goal),
    it cannot use a temporary, since it doesn't know what type of
    temporary it needs, and standard C does not provide a typeof
    operator.  (GNU C does.)

    The best all-around solution is probably to forget about using a
    macro.  If you're worried about the use of an ugly temporary, and
    know that your machine provides an exchange instruction, convince
    your compiler vendor to recognize the standard three-assignment swap
    idiom in the optimization phase.  Alternatively, use a language
    which supports multiple, parallel assignment (a,b := b,a).

19. How can I write a cpp macro which takes a variable number of
    arguments?

    One popular trick is to define the macro with a single argument, and
    call it with a double set of parentheses, which appear to the
    compiler to indicate a single argument:

        #define DEBUG(args) {printf("DEBUG: ");printf args;}

        if(n != 0) DEBUG(("n is %d\n", n));

    The obvious disadvantage to this trick is that the caller must
    always remember to use the extra parentheses.  (It is often best to
    use a bona-fide function, which can take a variable number of
    arguments in a well-defined way, rather than a macro.  See question
    20 below.)

Variable-Length Argument Lists

20. How can I write a function that takes a variable number of
    arguments?

A:  Use varargs or stdarg.

    Here is a function which concatenates an arbitrary number of strings
    into malloc'ed memory, using stdarg:

         #include <stddef.h>
         #include <stdarg.h>
         #include <string.h>

         extern char *malloc();

         /* VARARGS1 */

         char *
         vstrcat(first, ...)
         char *first;
         {
         int len = 0;
         char *retbuf;
         va_list argp;
         char *p;

         if(first == NULL)
                 return NULL;

         len = strlen(first);

         va_start(argp, first);

         while((p = va_arg(argp, char *)) != NULL)
                 len += strlen(p);

         va_end(argp);

         retbuf = malloc(len + 1);               /* +1 for trailing \0 */

         if(retbuf == NULL)
                 return NULL;

         (void)strcpy(retbuf, first);

         va_start(argp, first);

         while((p = va_arg(argp, char *)) != NULL)
                 (void)strcat(retbuf, p);

         va_end(argp);

         return retbuf;
         }

    Usage is something like

        char *str = vstrcat("Hello, ", "world!", (char *)NULL);

    Note the cast on the last argument.

    Using varargs, rather than stdarg, requires a few changes which are
    not discussed here, in the interests of brevity.  See the next
    question for hints.

    References: K&R II Sec. 7.3 p. 155, Sec. B7 p. 254; H&S Sec. 13.4
    pp. 286-9.

21. How can I write a function that takes a format string and a variable
    number of arguments, like printf, and passes them to printf so it
    can do most of the work?

A:  Use v*printf.

    Here is an "error" routine which prints an error message, preceded
    by the string "error: " and terminated with a newline:

         #include <stdio.h>
         #include <stdarg.h>

         void
         error(fmt, ...)
         char *fmt;
         {
         va_list argp;

         fprintf(stderr, "error: ");

         va_start(argp, fmt);

         vfprintf(stderr, fmt, argp);

         va_end(argp);

         fprintf(stderr, "\n");
         }

    To use varargs, instead of stdarg, change the function header to:

         void error(va_alist)
         va_dcl
         {
         char *fmt;

    and add the line

         fmt = va_arg(argp, char *);

    between the calls to va_start and vfprintf.

    References: K&R II Sec. 8.3 p. 174, Sec. B1.2 p. 245; H&S Sec. 17.12
    p. 337.

22. How can I discover how many arguments a function was actually called
    with?

A:  This information is not available to a portable program.  Some
    systems have a nonstandard nargs() function available, but even this
    is questionable, since it typically returns the number of words
    pushed, not the number of arguments.  (Floating point values and
    structures are usually passed as several words.)

    Any function which takes a variable number of arguments must be able
    to determine from the arguments themselves how many of them there
    are.  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).  Another common technique (useful when the arguments
    are all of the same type) is to use a sentinel value (often 0, -1,
    or an appropriately-cast null pointer) at the end of the list (see
    the vstrcat and execl examples under questions 20 and 2 above).

23. How can I write a function which takes a variable number of
    arguments and passes them to some other function (which takes a
    variable number of arguments)?

A:  In general, you cannot.  You must provide a version of that other
    function which accepts a va_list pointer, like vfprintf in the
    example above.  If the arguments must be passed as arguments (not
    indirectly through a va_list pointer) to another function which is
    itself varargs (for which you do not have the option of creating an
    alternate, va_list-accepting version) no portable solution is
    possible.  (The problem can be solved by resorting to machine-
    specific assembly language.)

Memory Allocation

24. Why doesn't this program work?

        main()
        {
        char *answer;
        printf("Type something: ");
        gets(answer);
        printf("You typed \"%s\"\n", answer);
        }

A:  The pointer variable "answer," which is handed to the gets function
    as the location into which the response should be stored, has not
    been set to point to any valid storage.  It is an uninitialized
    variable, just as is the variable i in this example:

        main()
        {
        int i;
        printf("i = %d\n", i);
        }

    That is, we cannot say where the pointer "answer" points.  (Since
    local variables are not initialized, and typically contain garbage,
    it is not even guaranteed that "answer" starts out as a null
    pointer.)

    The simplest way to correct the question-asking program is to use a
    local array, instead of a pointer, and let the compiler worry about
    allocation:

        #include <stdio.h>
        main()
        {
        char answer[100];
        printf("Type something: ");
        fgets(answer, 100, stdin);
        printf("You typed \"%s\"\n", answer);
        }

    Note that this example also uses fgets instead of gets (always a
    good idea), so that the size of the array can be specified, so that
    fgets will not overwrite the end of the array if the user types an
    overly-long line.  (Unfortunately, gets and fgets differ in their
    treatment of the trailing \n.)

Struct Assignment

25. I heard on a street corner that structures could be assigned to
    variables and passed to and from functions, but K&R I says no.

A:  What K&R I said was that the restrictions on struct operations would
    be lifted in a forthcoming version of the compiler, and in fact
    struct assignment and passing were fully functional in Ritchie's
    compiler even as K&R I was being published.  Although a few early C
    compilers lacked struct assignment, all modern compilers support it,
    and it is part of the ANSI C standard, so there should be no
    reluctance to use it.

    References: K&R I Sec. 6.2 p. 121; K&R II Sec. 6.2 p. 129; H&S Sec.
    5.6.2 p. 103.

26. How does struct passing and returning work?

A:  When structures are passed as arguments to functions, the entire
    struct is pushed on the stack, which may involve significant
    overhead for large structures.  It may be preferable in such cases
    to pass a pointer to the structure instead.

    Structures are returned from functions either in a special, static
    place (which may make struct-valued functions nonreentrant) or in a
    buffer pointed to by an extra, "hidden" argument to the function.

27. The following program works correctly, but it dumps core after it
    finishes.  Why?

         struct list
                 {
                 char *item;
                 struct list *next;
                 }

         /* Here is the main program. */

         main(argc, argv)
         ...

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).  Storing 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.

28. Why can't you compare structs?

A:  There is no reasonable way for a compiler to implement struct
    comparison which is consistent with C's low-level flavor.  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).  A field-by-field comparison
    would require unacceptable amounts of repetitive, in-line code for
    large structures.  Either method would not necessarily "do the right
    thing" with pointer fields: oftentimes, equality should be judged by
    equality of the things pointed to rather than strict equality of the
    pointers themselves.

    If you want to compare two structures, you must write your own
    function to do so.  C++ (among other languages) would let you
    arrange for the == operator to map to your function.

    References: K&R II Sec. 6.2 p. 129; H&S Sec. 5.6.2 p. 103.

Declarations

29. I can't seem to define a linked list node which contains a pointer
    to itself.  I tried

         typedef struct
                 {
                 char *item;
                 NODEPTR next;
                 } NODE, *NODEPTR;

    but the compiler gave me errors.  Can't a struct in C contain a
    pointer to itself?

    Structs in C can certainly contain pointers to themselves; the
    discussion and example in section 6.5 of K&R make this clear.  The
    problem is that the example above attempts to hide the struct
    pointer behind a typedef, which is not complete at the time it is
    used.  First, rewrite it without a typedef:

         struct node
                 {
                 char *item;
                 struct node *next;
                 };

    Then, if you feel you must use typedefs, define them after the fact:

         typedef struct node NODE, *NODEPTR;

    References: K&R I Sec. 6.5 p. 101; K&R II Sec. 6.5 p. 139; H&S Sec.
    5.6.1 p. 102.

30. How can I define a pair of mutually referential structures?  I tried

         typedef struct
                 {
                 int structafield;
                 STRUCTB *bpointer;
                 } STRUCTA;

         typedef struct
                 {
                 int structbfield;
                 STRUCTA *apointer;
                 } STRUCTB;

    but the compiler doesn't know about structb when it is used in
    struct a.

A:  Again, the problem is not the pointers but the typedefs.  First,
    define the two structures without using typedefs:

         struct a
                 {
                 int structafield;
                 struct b *bpointer;
                 };

         struct b
                 {
                 int structbfield;
                 struct a *apointer;
                 };

    The compiler can accept the field declaration struct b *bpointer
    within struct a, even though it has not yet heard of struct b.
    Occasionally it is necessary to precede this couplet with the
    tentative declaration

         struct b;

    to mask the declaration (if in an inner scope) from a different
    struct b in an outer scope.

    References: H&S Sec. 5.6.1 p. 102.

31. How do I declare a pointer to a function returning a pointer to a
    double?

A:  There are three answers to this question:

    1.   double *(*p)();

    2.   Build it up in stages, using typedefs:

              typedef double *pd;      /* pointer to double */
              typedef pd fpd();        /* func returning ptr to double */
              typedef fpd *pfpd;       /* ptr to func ret ptr to double */
              pfpd p;

    3.   Use the cdecl program, which turns English into C and vice
         versa:

              $ cdecl
              cdecl> define p as pointer to function returning pointer to double
              double *(*p)();
              cdecl>

         cdecl can also explain complicated declarations, help with
         casts, and indicate which set of parentheses the arguments go
         in (for complicated function definitions).

    References: H&S Sec. 5.10.1 p. 116.

32. So where can I get cdecl?

A:  Several public-domain versions are available.  A file called
    "cdecl.shar" is available for anonymous ftp from mimsy.umd.edu
    (128.8.128.8), or check your local archive.  (Commercial versions
    may also be available, at least one of which was shamelessly lifted
    from the public domain copy submitted by Graham Ross, one of cdecl's
    originators.)

Boolean Expressions and Variables

33. 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 because picking one
    involves a space/time tradeoff which is best decided by the
    programmer.  (Using an int for a boolean may be faster, while using
    char will probably save space.)

    The choice between #defines and enums is arbitrary and not terribly
    interesting.  Use any of

        #define TRUE  1             #define YES 1
        #define FALSE 0             #define NO  0

        enum bool {false, true};    enum bool {no, yes};

    as long as you are consistent within one program or project.  (The
    enum may be preferable if your debugger expands enum values when
    examining variables.)

    Some people prefer variants like

        #define TRUE (1==1)
        #define FALSE (!TRUE)

    These don't really buy much (see below).

34. Isn't #defining TRUE to be 1 dangerous, 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, but
    this applies only "on input", i.e. where a boolean value is
    expected.  When a boolean value is generated by a built-in operator,
    it is guaranteed to be 1 or 0.  Therefore, code like

        if((a == b) == TRUE)

    is guaranteed to work (if TRUE is 1), but this code is obviously
    silly.

    Preprocessor macros like TRUE and FALSE (and, in fact, NULL) are
    used for code readability, not because the underlying values might
    ever change.  That "true" is 1 and "false" (and null) 0 is
    guaranteed by the language.

    References: K&R I Sec. 2.7 p. 41; K&R II Sec. 2.6 p. 42, Sec. A7.4.7
    p. 204, Sec. A7.9 p. 206.

35. What is the difference between an enum and a series of preprocessor
    #defines?

A:  At the present time, there is essentially no difference.  Although
    many people might have wished otherwise, the ANSI standard says that
    enums may be freely intermixed with integral types, without
    warnings.  (If such intermixing were disallowed without explicit
    casts, judicious use of enums could catch certain programming
    errors.)  For now, the only advantage of an enum (other than that
    the numeric values are automatically assigned) is that a debugger
    may be able to display the symbolic value when enum variables are
    examined.

    References: K&R II Sec. 2.3 p. 39, Sec. A4.2 p. 196; H&S Sec. 5.5
    p. 100.

Operating System Dependencies

36. How can I read a single character from the keyboard without waiting
    for a newline?

A:  Contrary to popular belief and many people's wishes, this is not a
    C-related question.  The delivery of characters from a "keyboard" to
    a C program is a function of the operating system, and cannot be
    standardized by the C language.  Under UNIX, use ioctl to play with
    the CBREAK or RAW bits.  Under MS-DOS, use getch().  Under other
    operating systems, you're on your own.  Beware that some operating
    systems make this sort of thing impossible, because character
    collection into input lines is done by peripheral processors not
    under direct control of the CPU running your program.

37. How can I find out if there are characters available for reading
    (and if so, how many)?  Alternatively, how can I do a read that will
    not block if there are no characters available?

A:  These, too, are entirely operating-system-specific.  Depending on
    your operating system, you may be able to use "nonblocking I/O", or
    a system call named "select", or the FIONREAD ioctl.

Miscellaneous

38. Why does errno contain ENOTTY after a call to printf?

A:  Many implementations of the stdio package adjust their behavior
    slightly depending on whether stdout is a terminal or not.  To make
    this determination, these implementations perform an operation which
    fails (with ENOTTY) if stdout is not a terminal.  Although the
    output operation goes on to complete successfully, errno still
    contains ENOTTY.  This behavior can be mildly confusing, but it is
    not strictly incorrect, because it is only meaningful for a program
    to inspect the contents of errno after an error has occurred (that
    is, after a library function has returned an error code).

39. I know that the library routine localtime will convert a time_t into
    a broken-down struct tm, and that ctime will convert a time_t to a
    printable string.  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, mktime, which converts a
    struct tm to a time_t.  Several public-domain versions of this
    routine are available if your compiler does not support it yet.

    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.

    References: K&R II Sec. B10 p. 256; H&S Sec. 20.4 p. 361.

40. Does anyone know of a program for converting Pascal (Fortran, lisp,
    ...) to C?

A:  Several public-domain programs are available:

    p2c  written by Dave Gillespie, and posted to comp.sources.unix in
         March, 1990.

    f2c  jointly developed by people from Bell Labs, Bellcore, and
         Carnegie Mellon.  To find about f2c, send the message "send
         index from f2c" to netlib@research.att.com or research!netlib.

    A number of companies, not listed here yet, sell various language
    translation tools, both to and from C.

41. I'm having trouble with a Turbo C program which crashes and says
    something like "floating point not loaded."

A:  Some compilers for small machines, including Turbo C and Ritchie's
    original pdp11 compiler, attempt to leave out floating point support
    if it looks like it will not be needed.  In particular, the non-
    floating-point versions of printf and scanf don't handle %e, %f, and
    %g.  Occasionally the heuristics for "is the program using floating
    point?" are insufficient, and the programmer must insert one dummy
    explicit floating-point operation to force loading of floating-point
    support.  Unfortunately, an apparently common sort of program (thus
    the frequency of the question) uses scanf to read, and/or printf to
    print, floating-point values upon which no arithmetic is done, which
    elicits the problem under Turbo C.

    In general, questions about a particular compiler are inappropriate
    for comp.lang.c .  Problems with PC compilers, for instance, will
    find a more receptive audience in a PC newsgroup.

42. Does anyone have a C compiler test suite I can use?

A:  Plum Hall, among others, sells one.

43. I need a sort of an "approximate" strcmp routine, for comparing two
    strings for close, but not necessarily exact, equality.

A:  The classic routine for doing this sort of thing is the "soundex"
    algorithm, which maps similar-sounding words to the same numeric
    codes.  Soundex is described in the Searching and Sorting volume of
    Donald Knuth's classic The Art of Computer Programming.


The following frequent question(s) have answers which I haven't paid
attention to.  Please send answers you might have to scs@adam.mit.edu,
for inclusions in future updates to this list.

44. Can anyone send me a YACC grammar for C?


Thanks to Mark Brader, Stephen M. Dunn, Christopher Lott, Rich Salz, and
Joshua Simons, from whose comp.lang.c articles portions of this list
have been lifted.  (Indirect thanks too to Chris Torek, Doug Gwyn, Guy
Harris, Karl Heuer, and others who have so patiently been answering
these questions for so long, and better so than here, and especially to
Guy, who set me straight back in 1984 when I was the one asking a stupid
question about NULL.)

                                             Steve Summit
                                             scs@adam.mit.edu

This article is Copyright 1988, 1990 by Steve Summit.
It may be freely redistributed so long as the author's name, and this
notice, are retained.

scs@adam.mit.edu (Steve Summit) (05/18/90)

This article contains minimal answers to the comp.lang.c frequently
asked questions list.  Please see the long version for more detailed
explanations.

1.  What is this infamous null pointer, anyway?

A:  For each pointer type, there is a special value -- "null" -- which
    is distinguishable from all other pointer values and which is not
    the address of any object.

    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.

2.  How do I "get" a null pointer in my programs?

A:  A constant 0 in a pointer context is converted into a null pointer
    at compile time.  A "pointer context" is an assignment or comparison
    with one side a variable of pointer type, and (in ANSI standard C) a
    function argument which has a prototype in scope declaring a certain
    argument as being of pointer type.  In other contexts (function
    arguments without prototypes, or in the variable part of variadic
    functions) a constant 0 with an appropriate explicit cast is
    required.

    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.

3.  But aren't pointers the same as ints?

A:  Not since the early days.

    References: K&R I Sec. 5.6 pp. 102-3.

4.  What is NULL and how is it #defined?

A:  NULL is simply a preprocessor macro, #defined as 0 (or (void *)0)
    which is used in favor of an unadorned 0 as a stylistic convention.

    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.

5.  How should NULL be #defined on a machine which uses a nonzero bit
    pattern as the internal representation of the null pointer?

A:  The same as any other machine: as 0 (or (void *)0).  (The compiler
    makes the translation, upon seeing a 0, not the preprocessor.)

6.  If NULL were defined as "(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 kinds of pointers for different types of data.  A cast is
    still required to tell the compiler which kind of null pointer is
    required, since it may be different from (char *)0.

7.  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:  The construction "if(p)" works, regardless of the internal
    representation of null pointers, because the compiler essentially
    rewrites it as if(p != 0) and goes on to convert 0 into the correct
    null pointer.

    References: K&R II Sec. A7.4.7 p. 204; H&S Sec. 5.3 p. 91.

8.  If "NULL" and "0" are equivalent, which should I use?

A:  Either; the distinction is entirely stylistic.

    References: K&R II Sec. 5.4 p. 102.

9.  But wouldn't it be better to use NULL (rather than 0) in case the
    value of NULL changes, perhaps on a machine with nonzero null
    pointers?

A:  No.  NULL is, and will always be, 0.

10. I'm confused.  NULL is guaranteed to be 0, but the null pointer is
    not?

A:  A "null pointer" (written in lower case in this article) is a
    language concept whose particular internal value does not matter.  A
    "null pointer" is requested in source code with the character '0'.
    "NULL" (always in capital letters) is a preprocessor macro, which is
    always #defined as 0 (or (void *)0).

11. Why is there so much confusion surrounding null pointers?  Why do
    these questions come up so often?

A:  The fact that null pointers are represented both in source code, and
    internally to most machines, as zero invites unwarranted
    assumptions.  The fact that a preprocessor macro (NULL) is often
    used suggests that this is done so because the value might change,
    or on some weird machine.

12. I had the declaration char a[5] in one source file, and in another I
    declared extern char *a.  Why didn't it work?

A:  The declaration extern char *a simply does not match the actual
    definition.   Use extern char a[].

13. But I heard that char a[] was identical to char *a.

A:  This identity (that a pointer declaration is interchangeable with an
    array, usually unsized) holds _only_ for formal arguments to
    functions.

    References: K&R I Sec. 5.3 p. 95, Sec. A10.1 p. 205; K&R II Sec. 5.3
    p. 100, Sec. A8.6.3 p. 218, Sec. A10.1 p. 226; H&S Sec. 5.4.3 p. 96.

14. So what is meant by the "equivalence of pointers and arrays" in C?

A:  Saying that arrays and pointers are "equivalent" does not by any
    means imply that they are interchangeable.  "Equivalence" refers to
    the fact that arrays "turn into" pointers within expressions, and
    that pointers and arrays can both be dereferenced using array-like
    subscript notation.

    References: K&R I Sec. 5.3 pp. 93-6; K&R II Sec. 5.3 p. 99; H&S Sec.
    5.4.1 p. 93.

15. Under my compiler, the program "int i = 7;
    printf("%d\n", i++ * i++); " prints 49.  Regardless of the order of
    evaluation, shouldn't it print 56?

A:  The operations implied by the postincrement and postdecrement
    operators ++ and -- are performed at some time after the operand's
    former values are yielded and before the end of the expression, but
    not necessarily immediately after, or before other parts of the
    expression are evaluated.

    References: K&R I Sec. 2.12 p. 50; K&R II Sec. 2.12 p. 54.

16. What is the "ANSI C Standard?"

A:  In 1983, the American National Standards Institute commissioned a
    committee, X3J11, to standardize the C language.  After a long and
    arduous process, this C standard was finally ratified as an American
    National Standard, X3.159-1989, in the spring of 1990.

17. How can I get a copy of the ANSI C standard?

A:  Copies are available from the American National Standards Institute
    in New York, or from Global Engineering Documents in Irvine, CA.
    See the unabridged list for full addresses.

18. How can I write a macro to swap two values?

A:  There is no good answer to this question.  The best all-around
    solution is probably to forget about using a macro.

19. How can I write a cpp macro which takes a variable number of
    arguments?

    One popular trick is to define the macro with a single argument, and
    call it with a double set of parentheses, which appear to the
    compiler to indicate a single argument:

        #define DEBUG(args) {printf("DEBUG: ");printf args;}

        if(n != 0) DEBUG(("n is %d\n", n));

20. How can I write a function that takes a variable number of
    arguments?

A:  Use varargs or stdarg.

    References: K&R II Sec. 7.3 p. 155, Sec. B7 p. 254; H&S Sec. 13.4
    pp. 286-9.

21. How can I write a function that takes a format string and a variable
    number of arguments, like printf, and passes them to printf so it
    can do most of the work?

A:  Use v*printf.

    References: K&R II Sec. 8.3 p. 174, Sec. B1.2 p. 245; H&S Sec. 17.12
    p. 337.

22. How can I discover how many arguments a function was actually called
    with?

A:  This information is not available to a portable program.  Any
    function which takes a variable number of arguments must be able to
    determine from the arguments themselves how many of them there are.

23. How can I write a function which takes a variable number of
    arguments and passes them to some other function (which takes a
    variable number of arguments)?

A:  In general, you cannot.

24. Why doesn't the code "char *answer; gets(answer);" work?

A:  The pointer variable "answer" has not been set to point to any valid
    storage.  The simplest way to correct this fragment is to use a
    local array, instead of a pointer.

25. I heard that structures could be assigned to variables and passed to
    and from functions, but K&R I says no.

A:  These operations are supported by all modern compilers.

    References: K&R I Sec. 6.2 p. 121; K&R II Sec. 6.2 p. 129; H&S Sec.
    5.6.2 p. 103.

26. How does struct passing and returning work?

A:  If you really need to know, see the unabridged list.

27. I have a program which works correctly, but it dumps core after it
    finishes.  Why?

A:  Check to see if a structure declaration just before main is missing
    its trailing semicolon, causing the compiler to think that main
    returns a struct.

28. Why can't you compare structs?

A:  There is no reasonable way for a compiler to implement struct
    comparison which is consistent with C's low-level flavor.

    References: K&R II Sec. 6.2 p. 129; H&S Sec. 5.6.2 p. 103.

29. I can't seem to define a linked list node which contains a pointer
    to itself.

    Structs in C can certainly contain pointers to themselves; the
    discussion and example in section 6.5 of K&R make this clear.
    Problems arise when an attempt is made to define (and use) a typedef
    in the midst of such a declaration; avoid this.

    References: K&R I Sec. 6.5 p. 101; K&R II Sec. 6.5 p. 139; H&S Sec.
    5.6.1 p. 102.

30. How can I define a pair of mutually referential structures?

A:  The obvious technique works as long as any typedef synonyms are done
    later.

    References: H&S Sec. 5.6.1 p. 102.

31. How do I declare a pointer to a function returning a pointer to a
    double?

A:  double *(*p)();
    Using a chain of typedefs, or the cdecl program, makes these
    declarations easier.

    References: H&S Sec. 5.10.1 p. 116.

32. So where can I get cdecl?

A:  Several public-domain versions are available.

33. 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 because picking one
    involves a space/time tradeoff which is best decided by the
    programmer.  The choice between #defines and enums is arbitrary and
    not terribly interesting.

34. Isn't #defining TRUE to be 1 dangerous, 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, but
    this applies only "on input", i.e. where a boolean value is
    expected.  When a boolean value is generated by a built-in operator,
    it is guaranteed to be 1 or 0.

    References: K&R I Sec. 2.7 p. 41; K&R II Sec. 2.6 p. 42, Sec. A7.4.7
    p. 204, Sec. A7.9 p. 206.

35. What is the difference between an enum and a series of preprocessor
    #defines?

A:  At the present time, there is essentially no difference.

    References: K&R II Sec. 2.3 p. 39, Sec. A4.2 p. 196; H&S Sec. 5.5
    p. 100.

36. How can I read a single character from the keyboard without waiting
    for a newline?

A:  Contrary to popular belief and many people's wishes, this is not a
    C-related question.  How to do so is a function of the operating
    system in use.

37. How can I find out if there are characters available for reading
    (and if so, how many)?  Alternatively, how can I do a read that will
    not block if there are no characters available?

A:  These, too, are entirely operating-system-specific.

38. Why does errno contain ENOTTY after a call to printf?

A:  Don't worry about it.  It is only meaningful for a program to
    inspect the contents of errno after an error has occurred.

39. I know that the library routine localtime will convert a time_t into
    a broken-down struct tm, and that ctime will convert a time_t to a
    printable string.  How can I perform the inverse operations of
    converting a struct tm or a string into a time_t?

A:  The ANSI mktime routine converts a struct tm to a time_t.  No
    standard routine exists to convert strings.

    References: K&R II Sec. B10 p. 256; H&S Sec. 20.4 p. 361.

40. Does anyone know of a program for converting Pascal (Fortran, lisp,
    ...) to C?

A:  Several public-domain programs are available, namely p2c and f2c.  A
    number of companies, not listed here yet, sell various language
    translation tools, both to and from C.

41. I'm having trouble with a Turbo C program which crashes and says
    something like "floating point not loaded."

A:  Some compilers for small machines, including Turbo C and Ritchie's
    original pdp11 compiler, attempt to leave out floating point support
    if it looks like it will not be needed.  The programmer must
    occasionally insert one dummy explicit floating-point operation to
    force loading of floating-point support.

42. Does anyone have a C compiler test suite I can use?

A:  Plum Hall, among others, sells one.

43. I need a sort of an "approximate" strcmp routine, for comparing two
    strings for close, but not necessarily exact, equality.

A:  The classic routine for doing this sort of thing is the "soundex"
    algorithm.

                                             Steve Summit
                                             scs@adam.mit.edu

This article is Copyright 1988, 1990 by Steve Summit.
It may be freely redistributed so long as the author's name, and this
notice, are retained.

scs@adam.mit.edu (Steve Summit) (06/01/90)

Certain topics come up again and again on this newsgroup.  They are good
questions, and the answers may not be immediately obvious, but each time
they recur, much net bandwidth and reader time is wasted on repetitive
responses, and on tedious corrections to the incorrect answers which are
inevitably posted.

This article, which will be reposted periodically, attempts to answer
these common questions definitively and succinctly, so that net
discussion can move on to more constructive topics without continual
regression to first principles.

This article does not, and cannot, provide an exhaustive discussion of
all of the subtle points and counterarguments which could be mentioned
with respect to these topics.  Cross-references to standard C
publications have been provided, for further study by the interested and
dedicated reader.  A few of the more perplexing and pervasive topics may
be further explored in some in-depth minitreatises posted in conjunction
with this article.

No mere newsgroup article can substitute for thoughtful perusal of a
full-length language reference manual.  Anyone interested enough in C to
be following this newsgroup should also be interested enough to read and
study one or more such manuals, preferably several times.  Some vendor's
compiler manuals are unfortunately inadequate; a few even perpetuate
some of the myths which this article attempts to debunk.  Two invaluable
references, which are an excellent addition to any serious programmer's
library, are:

     The C Programming Language, by Brian W. Kernighan and Dennis M.
     Ritchie.

     C: A Reference Manual, by Samuel P. Harbison and Guy L. Steele, Jr.

Both exist in several editions.  Andrew Koenig's book _C Traps and
Pitfalls_ also covers many of the difficulties frequently discussed
here.

If you have a question about C which is not answered in this article,
please try to answer it by referring to these or other books, or to
knowledgeable colleagues, before posing your question to the net at
large.  There are many people on the net who are happy to answer
questions, but the volume of repetitive answers posted to one question,
as well as the growing numbers of questions as the net attracts more
readers, can become oppressive.  If you have questions or comments
prompted by this article, please reply by mail rather than following up
-- this article is meant to decrease net traffic, not increase it.

This article is under development.  Your input is welcomed.  In
particular, I am soliciting:

1.  cross-referencing suggestions, particularly to the ANSI C standard,
    a copy of which I don't yet have;

2.  additions to the Pascal-to-C translators list (question 51; I know
    there are some commercial programs out there) and to any other
    product lists, since I don't want to imply disfavor by not
    mentioning one; and

3.  answers to the questions at the end which, though frequent, have not
    been of enough interest to me that I've paid attention to them.

Send your comments to scs@adam.mit.edu and/or scs%adam.mit.edu@mit.edu;
this article's From: line may be incorrect.

Herewith, some frequently-asked questions and their answers:

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 "return" 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.")

    Although a null pointer does not "point anywhere," it is different
    from an uninitialized pointer, about which we cannot say where it
    points.  A null pointer points explicitly nowhere (i.e. not at any
    object); an uninitialized pointer might point anywhere (at some
    random object, or at a garbage or unallocated address).  See also
    question 29.

    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
    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.

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 assignment or comparison when one side is a variable 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," so 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:

         assignments              function call,
                                  no prototype in scope
         comparisons
                                  variable argument to
         function call,           varargs function
         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.

3.  But aren't pointers the same as ints?

A:  Not since the early days.  It is now merely guaranteed that a
    pointer to an object may be cast to a "suitably capacious" integral
    type, and back, without change, but how large the type is is not
    specified (it may be larger than a long int) and the rule does _not_
    apply to pointers to functions.  (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.)

    References: K&R I Sec. 5.6 pp. 102-3.

4.  What is NULL and how is it #defined?

A:  As a stylistic convention, many people prefer not to have unadorned
    0's scattered throughout their programs.  For this reason, the
    preprocessor macro NULL is #defined (by stdio.h or stddef.h), 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.  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.  (The ANSI #definition
    of NULL is allowed to be (void *)0, which will not work in non-
    pointer contexts.)  In particular, do not use NULL when the ASCII
    nul character is desired.  Provide your own definition

        #define NUL '\0'

    if you must.

    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 X3.159-1989 Sec. 4.1.5 p. 99, Sec. 3.2.2.3
    p. 38, Rationale Sec. 4.1.5 p. 74.

5.  How should NULL be #defined on a machine which uses a nonzero bit
    pattern as the internal representation of the 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.

6.  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 kinds of pointers for 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.

    Nevertheless, ANSI C allows the alternate

        #define NULL (void *)0

    definition for NULL.  Besides helping incorrect programs to work
    (but only on machines with all pointers the same, thus questionably
    valid assistance) this definition may catch programs which use NULL
    incorrectly (e.g. when the ASCII nul character was really intended).

7.  My vendor provides header files that #define NULL as 0L.  Why?

A:  This definition, like (void *)0, helps incorrect programs work on
    some common architectures.

8.  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,
    while, for, and do statements, and with the &&, ||, !, and ?:
    operators), a false value is produced when the expression is equal
    to zero, and a true value otherwise.  That is, whenever one writes

        if(expr)

    where "expr" is any expression at all, the compiler essentially acts
    as if it had been written as

        if(expr != 0)

    Substituting the trivial pointer expression "p" for "expr," we have

         if(p)      is equivalent to                 if(p != 0)

    and this is a comparison context, so the compiler can tell that the
    (implicit) 0 is a null pointer, and use the correct value.  There is
    no trickery involved here; compilers do work this way, and generate
    identical code for both statements.  The internal representation of
    a pointer does not matter.

    The boolean negation operator, !, 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)

    References: K&R II Sec. A7.4.7 p. 204; H&S Sec. 5.3 p. 91.

9.  If "NULL" and "0" are equivalent, which should I use?

A:  Many programmers believe that "NULL" should be used in all pointer
    contexts, as a reminder that the value is to be thought of as a
    pointer.  Others feel that the confusion surrounding "NULL" and "0"
    is only compounded by hiding "0" behind a #definition, and prefer to
    use unadorned "0" instead.  There is no one right answer.  C
    programmers must understand that "NULL" and "0" are interchangeable
    and that an uncast "0" is perfectly acceptable in assignment and
    comparison contexts.  Any usage of "NULL" (as opposed to "0") should
    be considered a gentle reminder; programmers should not depend on it
    (either for their own understanding or the compiler's) for
    distinguishing pointer 0's from integer 0's.  Again, NULL should not
    be used for other than pointers.

    References: K&R II Sec. 5.4 p. 102.

10. But wouldn't it be better to use NULL (rather than 0) in case the
    value of NULL changes, perhaps on a machine with nonzero null
    pointers?

A:  No.  NULL is defined as a preprocessor macro _not_ because its value
    might change.  That source-code 0's generate null pointers is
    guaranteed by the language.  NULL is used only as a stylistic
    convention.

11. I'm confused.  NULL is guaranteed to be 0, but the null pointer is
    not?

A:  A "null pointer" (written in lower case in this article) is a
    language concept whose particular internal value does not matter.
    (On some machines the internal value is 0; on others it is not.)  A
    "null pointer" is requested in source code with the character '0'.
    "NULL" (always in capital letters) is a preprocessor macro, which is
    always #defined as 0 (or (void *)0).

    When the phrase "null pointer" is casually used, one of three things
    may be meant:

    1.   The internal (or run-time) representation of null pointers,
         which may be different for different pointer types.  The actual
         values should be of concern only to compiler writers.  Authors
         of C programs never see them, since they use...

    2.   The source code syntax for null pointers, which is the single
         character '0'.  It is often hidden behind...

    3.   The NULL macro, which is #defined to be "0" or "(void *)0".

    This article always uses the phrase "null pointer" for sense 1, the
    character '0' for sense 2, and the capitalized word "NULL" for
    sense 3.

12. 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.  The fact that null
    pointers are represented both in source code, and internally to most
    machines, as zero invites unwarranted assumptions.  The fact that a
    preprocessor macro (NULL) is often used suggests that this is done
    because the value might change later, or on some weird machine.
    Furthermore, the distinction between the three uses of the term
    "null" (listed above) is often overlooked.

    One good way to wade out of the confusion is to imagine that C had a
    keyword (perhaps "nil", like Pascal) with which null pointers were
    requested.  The compiler could either turn "nil" into the correct
    type of null pointer when it could determine the type from the
    source code (as it does with 0's in reality) or complain when it
    could not.  Now, in fact, in C the keyword for a null pointer is not
    "nil" but '0', which works almost as well, except that an uncast '0'
    in a non-pointer context generates an integer zero.  If the null
    pointer keyword were "nil" the compiler could emit an error message
    for an ambiguous usage, but since it is '0' the compiler may end up
    emitting incorrect code.

13. I'm still confused.  I just can't understand all this null pointer
    stuff.

A:  Follow these two simple rules:

    1.   When you want to refer to a null pointer in source code, use
         "0" or "NULL".

    2.   If the usage of "0" or "NULL" is in a function call, cast it to
         the pointer type expected by the function being called.

    Everything else has to do with other people's confusion, or with the
    internal representation of null pointers, which you shouldn't need
    to know.

Arrays and Pointers

14. I had the declaration char a[5] in one source file, and in another I
    declared extern char *a.  Why didn't it work?

A:  The declaration extern char *a simply does not match the actual
    definition.  The type "pointer-to-type-T" is not the same as
    "array-of-type-T."  Use extern char a[].

15. But I heard that char a[] was identical to char *a.

A:  This identity (that a pointer declaration is interchangeable with an
    array, usually unsized) holds _only_ for formal arguments to
    functions.  This identity falls out of the fact that arrays "turn
    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.  Since functions can never receive arrays as
    arguments, any argument 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 argument declarations, nowhere else.

    References: K&R I Sec. 5.3 p. 95, Sec. A10.1 p. 205; K&R II Sec. 5.3
    p. 100, Sec. A8.6.3 p. 218, Sec. A10.1 p. 226; H&S Sec. 5.4.3 p. 96.

16. So what is meant by the "equivalence of pointers and arrays" in C?

A:  Perhaps no aspect of C is more confusing than pointers, and no
    statement has compounded this confusion more than the one above.
    Saying that arrays and pointers are "equivalent" does not by any
    means imply that they are interchangeable.  (The fact that, as
    formal arguments 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 "turn
    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;
        int i;

    we can refer to a[i] and p[i].  (That pointers can be subscripted
    like arrays is hardly surprising, since arrays are also pointers by
    the time they are subscripted.)

    References: K&R I Sec. 5.3 pp. 93-6; K&R II Sec. 5.3 p. 99; H&S Sec.
    5.4.1 p. 93.

Order of Evaluation

17. Under my compiler, the program

         int i = 7;
         printf("%d\n", i++ * i++);

    prints 49.  Regardless of the order of evaluation, shouldn't it
    print 56?

A:  Although the postincrement and postdecrement operators ++ and --
    perform the operations after yielding the former value, many people
    misunderstand the implication of "after." 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.  It is merely guaranteed that the update will be
    performed sometime before the expression is considered "finished"
    (before the next "sequence point," in ANSI C's terminology).

    In the example, the compiler chose to multiply the previous value by
    itself and to perform both increments afterwards.

    References: K&R I Sec. 2.12 p. 50; K&R II Sec. 2.12 p. 54.

ANSI C

18. What is the "ANSI C Standard?"

A:  In 1983, the American National Standards Institute commissioned a
    committee, X3J11, to standardize the C language.  After a long and
    arduous process, this C standard was finally ratified as an American
    National Standard, X3.159-1989, on December 14, 1989, and published
    in the spring of 1990.  For the most part, ANSI C standardizes
    existing practice, with a few additions from C++ (most notably
    function prototypes) and support for multinational character sets
    (including the much-lambasted trigraph sequences for transfer of
    source code between machines with deficient or multinational
    character sets).  The ANSI C standard also formalizes the C run-time
    library support routines, an unprecedented effort.

19. How can I get a copy of the ANSI C standard?

A:  Copies are available from

        American National Standards Institute
        1430 Broadway
        New York, NY  10018
        (212) 642-4900

    or

        Global Engineering Documents
        2805 McGaw Avenue
        Irvine, CA  92714
        (714) 261-1455

    The cost is approximately $50.00, plus $6.00 shipping.

20. 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.  (See also question 51.)

21. My ANSI compiler complains about a mismatch when it sees

         extern int blort(float);
         int blort(x)
         float x;
         {...

A:  You have mixed the new-style declaration "extern int blort(float);"
    with the old-style definition "int blort(x) float x;".  Old C
    silently promoted doubles to floats when passing them as arguments,
    and made a corresponding silent change to formal argument
    declarations, so the old-style definition actually says that blort
    takes a double.

    The problem can be fixed either by using new-style syntax
    consistently in the definition:

         int blort(float x) { ... }

    or by changing the new-style declaration to match the old-style
    definition:

         extern int blort(double);

C Preprocessor

22. How can I write a macro to swap two values?

A:  There is no good answer to this question.  If the values are
    integers, a well-known trick using exclusive-OR can be used, but it
    will not work for floating-point values or pointers.  If the macro
    is intended to be used on values of arbitrary type (the usual goal),
    it cannot use a temporary, since it doesn't know what type of
    temporary it needs, and standard C does not provide a typeof
    operator.  (GNU C does.)

    The best all-around solution is probably to forget about using a
    macro.  If you're worried about the use of an ugly temporary, and
    know that your machine provides an exchange instruction, convince
    your compiler vendor to recognize the standard three-assignment swap
    idiom in the optimization phase.  Alternatively, use a language
    which supports multiple, parallel assignment (a,b := b,a).

23. I'm getting strange syntax errors inside code which I've #ifdeffed
    out.

A:  Under ANSI C, the text inside a "turned off" #if, #ifdef, or #ifndef
    must still consist of "valid preprocessing tokens."  This means that
    there must be no unterminated comments or quotes (note particularly
    that an apostrophe within a contracted word looks like the beginning
    of a character constant) and no newlines inside quotes.

24. How can I write a cpp macro which takes a variable number of
    arguments?

    One popular trick is to define the macro with a single argument, and
    call it with a double set of parentheses, which appear to the
    compiler to indicate a single argument:

        #define DEBUG(args) {printf("DEBUG: ");printf args;}

        if(n != 0) DEBUG(("n is %d\n", n));

    The obvious disadvantage to this trick is that the caller must
    always remember to use the extra parentheses.  (It is often best to
    use a bona-fide function, which can take a variable number of
    arguments in a well-defined way, rather than a macro.  See question
    25 below.)

Variable-Length Argument Lists

25. How can I write a function that takes a variable number of
    arguments?

A:  Use varargs or stdarg.

    Here is a function which concatenates an arbitrary number of strings
    into malloc'ed memory, using stdarg:

         #include <stddef.h>
         #include <stdarg.h>
         #include <string.h>

         extern char *malloc();

         /* VARARGS1 */

         char *
         vstrcat(char *first, ...)
         {
                 int len = 0;
                 char *retbuf;
                 va_list argp;
                 char *p;

                 if(first == NULL)
                         return NULL;

                 len = strlen(first);

                 va_start(argp, first);

                 while((p = va_arg(argp, char *)) != NULL)
                         len += strlen(p);

                 va_end(argp);

                 retbuf = malloc(len + 1);       /* +1 for trailing \0 */

                 if(retbuf == NULL)
                         return NULL;

                 (void)strcpy(retbuf, first);

                 va_start(argp, first);

                 while((p = va_arg(argp, char *)) != NULL)
                         (void)strcat(retbuf, p);

                 va_end(argp);

                 return retbuf;
         }

    Usage is something like

        char *str = vstrcat("Hello, ", "world!", (char *)NULL);

    Note the cast on the last argument.

    Using varargs, rather than stdarg, requires a few changes which are
    not discussed here, in the interests of brevity.  See the next
    question for hints.

    References: K&R II Sec. 7.3 p. 155, Sec. B7 p. 254; H&S Sec. 13.4
    pp. 286-9.

26. How can I write a function that takes a format string and a variable
    number of arguments, like printf, and passes them to printf to do
    most of the work?

A:  Use v*printf.

    Here is an "error" routine which prints an error message, preceded
    by the string "error: " and terminated with a newline:

         #include <stdio.h>
         #include <stdarg.h>

         void
         error(char *fmt, ...)
         {
                 va_list argp;

                 fprintf(stderr, "error: ");

                 va_start(argp, fmt);

                 vfprintf(stderr, fmt, argp);

                 va_end(argp);

                 fprintf(stderr, "\n");
         }

    To use varargs, instead of stdarg, change the function header to:

         void error(va_alist)
         va_dcl
         {
              char *fmt;

    change the va_start line to

         va_start(argp);

    and add the line

         fmt = va_arg(argp, char *);

    between the calls to va_start and vfprintf.

    References: K&R II Sec. 8.3 p. 174, Sec. B1.2 p. 245; H&S Sec. 17.12
    p. 337.

27. How can I discover how many arguments a function was actually called
    with?

A:  This information is not available to a portable program.  Some
    systems have a nonstandard nargs() function available, but even this
    is questionable, since it typically returns the number of words
    pushed, not the number of arguments.  (Floating point values and
    structures are usually passed as several words.)

    Any function which takes a variable number of arguments must be able
    to determine from the arguments themselves how many of them there
    are.  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).  Another common technique (useful when the arguments
    are all of the same type) is to use a sentinel value (often 0, -1,
    or an appropriately-cast null pointer) at the end of the list (see
    the vstrcat and execl examples under questions 25 and 2 above).

28. How can I write a function which takes a variable number of
    arguments and passes them to some other function (which takes a
    variable number of arguments)?

A:  In general, you cannot.  You must provide a version of that other
    function which accepts a va_list pointer, like vfprintf in the
    example above.  If the arguments must be passed as arguments (not
    indirectly through a va_list pointer) to another function which is
    itself varargs (for which you do not have the option of creating an
    alternate, va_list-accepting version) no portable solution is
    possible.  (The problem can be solved by resorting to machine-
    specific assembly language.)

Memory Allocation

29. Why doesn't this program work?

         main()
         {
                 char *answer;
                 printf("Type something: ");
                 gets(answer);
                 printf("You typed \"%s\"\n", answer);
         }

A:  The pointer variable "answer," which is handed to the gets function
    as the location into which the response should be stored, has not
    been set to point to any valid storage.  It is an uninitialized
    variable, just as is the variable i in this example:

         main()
         {
                 int i;
                 printf("i = %d\n", i);
         }

    That is, we cannot say where the pointer "answer" points.  (Since
    local variables are not initialized, and typically contain garbage,
    it is not even guaranteed that "answer" starts out as a null
    pointer.)

    The simplest way to correct the question-asking program is to use a
    local array, instead of a pointer, and let the compiler worry about
    allocation:

         #include <stdio.h>
         main()
         {
                 char answer[100];
                 printf("Type something: ");
                 fgets(answer, 100, stdin);
                 printf("You typed \"%s\"\n", answer);
         }

    Note that this example also uses fgets instead of gets (always a
    good idea), so that the size of the array can be specified, so that
    fgets will not overwrite the end of the array if the user types an
    overly-long line.  (Unfortunately, gets and fgets differ in their
    treatment of the trailing \n.)

Structures

30. I heard that structures could be assigned to variables and passed to
    and from functions, but K&R I says no.

A:  What K&R I said was that the restrictions on struct operations would
    be lifted in a forthcoming version of the compiler, and in fact
    struct assignment and passing were fully functional in Ritchie's
    compiler even as K&R I was being published.  Although a few early C
    compilers lacked struct assignment, all modern compilers support it,
    and it is part of the ANSI C standard, so there should be no
    reluctance to use it.

    References: K&R I Sec. 6.2 p. 121; K&R II Sec. 6.2 p. 129; H&S Sec.
    5.6.2 p. 103.

31. How does struct passing and returning work?

A:  When structures are passed as arguments to functions, the entire
    struct is pushed on the stack, which may involve significant
    overhead for large structures.  It may be preferable in such cases
    to pass a pointer to the structure instead.

    Structures are returned from functions either in a special, static
    place (which may make struct-valued functions nonreentrant) or in a
    location pointed to by an extra, "hidden" argument to the function.

32. The following program works correctly, but it dumps core after it
    finishes.  Why?

         struct list
                 {
                 char *item;
                 struct list *next;
                 }

         /* Here is the main program. */

         main(argc, argv)
         ...

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).  Storing 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.

33. Why can't you compare structs?

A:  There is no reasonable way for a compiler to implement struct
    comparison which is consistent with C's low-level flavor.  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).  A field-by-field comparison
    would require unacceptable amounts of repetitive, in-line code for
    large structures.  Either method would not necessarily "do the right
    thing" with pointer fields: oftentimes, equality should be judged by
    equality of the things pointed to rather than strict equality of the
    pointers themselves.

    If you want to compare two structures, you must write your own
    function to do so.  C++ (among other languages) would let you
    arrange for the == operator to map to your function.

    References: K&R II Sec. 6.2 p. 129; H&S Sec. 5.6.2 p. 103.

34. 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

         #define offset(type, mem) ((size_t)(char *)&(((type *)0)->mem))

    This implementation's use of the null pointer, however, is said not
    to be completely portable.

    See the next question for a usage hint.

35. How can I access structure fields by name at run time?

A:  Build a table of names and offsets, using the offsetof() macro.  The
    offset of field b in struct a is

         offsetof(struct a, b)

    If structp is a pointer to an instance of this structure, and b is
    an int field with offset as computed above, b's value can be set
    indirectly with

         *(int *)((char *)structp + offset) = value;

Declarations

36. I can't seem to define a linked list node which contains a pointer
    to itself.  I tried

         typedef struct
                 {
                 char *item;
                 NODEPTR next;
                 } NODE, *NODEPTR;

    but the compiler gave me errors.  Can't a struct in C contain a
    pointer to itself?

    Structs in C can certainly contain pointers to themselves; the
    discussion and example in section 6.5 of K&R make this clear.  The
    problem is that the example above attempts to hide the struct
    pointer behind a typedef, which is not complete at the time it is
    used.  First, rewrite it without a typedef:

         struct node
                 {
                 char *item;
                 struct node *next;
                 };

    Then, if you feel you must use typedefs, define them after the fact:

         typedef struct node NODE, *NODEPTR;

    Alternatively, define the typedefs first (using the line just above)
    and follow it with the full definition of struct node, which can
    then use the NODEPTR typedef for the "next" field.

    References: K&R I Sec. 6.5 p. 101; K&R II Sec. 6.5 p. 139; H&S Sec.
    5.6.1 p. 102.

37. How can I define a pair of mutually referential structures?  I tried

         typedef struct
                 {
                 int structafield;
                 STRUCTB *bpointer;
                 } STRUCTA;

         typedef struct
                 {
                 int structbfield;
                 STRUCTA *apointer;
                 } STRUCTB;

    but the compiler doesn't know about STRUCTB when it is used in
    struct a.

A:  Again, the problem is not the pointers but the typedefs.  First,
    define the two structures without using typedefs:

         struct a
                 {
                 int structafield;
                 struct b *bpointer;
                 };

         struct b
                 {
                 int structbfield;
                 struct a *apointer;
                 };

    The compiler can accept the field declaration struct b *bpointer
    within struct a, even though it has not yet heard of struct b.
    Occasionally it is necessary to precede this couplet with the empty
    declaration

         struct b;

    to mask the declaration (if in an inner scope) from a different
    struct b in an outer scope.

    Again, the typedefs could also be defined before, and then used
    within, the definitions for struct a and struct b.  The problem
    arises when an attempt is made to define and use a typedef within
    the same declaration.

    References: H&S Sec. 5.6.1 p. 102.

38. How do I declare a pointer to a function returning a pointer to a
    double?

A:  There are at least three answers to this question:

    1.   double *(*p)();

    2.   Build it up in stages, using typedefs:

              typedef double *pd;      /* pointer to double */
              typedef pd fpd();        /* func returning ptr to double */
              typedef fpd *pfpd;       /* ptr to func ret ptr to double */
              pfpd p;

    3.   Use the cdecl program, which turns English into C and vice
         versa:

              $ cdecl
              cdecl> declare p as pointer to function returning pointer to double
              double *(*p)();
              cdecl>

         cdecl can also explain complicated declarations, help with
         casts, and indicate which set of parentheses the arguments go
         in (for complicated function definitions).

    References: H&S Sec. 5.10.1 p. 116.

39. So where can I get cdecl?

A:  Several public-domain versions are available.  A file called
    "cdecl.shar" is available for anonymous ftp from mimsy.umd.edu
    (128.8.128.8), or check your local archive.  (Commercial versions
    may also be available, at least one of which was shamelessly lifted
    from the public domain copy submitted by Graham Ross, one of cdecl's
    originators.)

Boolean Expressions and Variables

40. 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 because picking one
    involves a space/time tradeoff which is best decided by the
    programmer.  (Using an int for a boolean may be faster, while using
    char will probably save data space.)

    The choice between #defines and enums is arbitrary and not terribly
    interesting.  Use any of

        #define TRUE  1             #define YES 1
        #define FALSE 0             #define NO  0

        enum bool {false, true};    enum bool {no, yes};

    as long as you are consistent within one program or project.  (The
    enum may be preferable if your debugger expands enum values when
    examining variables.)

    Some people prefer variants like

        #define TRUE (1==1)
        #define FALSE (!TRUE)

    These don't really buy much (see below).

41. Isn't #defining TRUE to be 1 dangerous, 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, but
    this applies only "on input", i.e. where a boolean value is
    expected.  When a boolean value is generated by a built-in operator,
    it is guaranteed to be 1 or 0.  Therefore, the test

        if((a == b) == TRUE)

    will succeed (if a, in fact, equals b and TRUE is one), but this
    code is obviously silly.  In general, explicit tests against TRUE
    and FALSE are undesirable, because some library functions (notably
    isupper, isalpha, etc.) return, on success, a nonzero value which is
    _not_ necessarily 1.

    Preprocessor macros like TRUE and FALSE (and, in fact, NULL) are
    used for code readability, not because the underlying values might
    ever change.  That "true" is 1 and "false" (and source-code null
    pointers) 0 is guaranteed by the language.

    References: K&R I Sec. 2.7 p. 41; K&R II Sec. 2.6 p. 42, Sec. A7.4.7
    p. 204, Sec. A7.9 p. 206.

42. What is the difference between an enum and a series of preprocessor
    #defines?

A:  At the present time, there is little difference.  Although many
    people might have wished otherwise, the ANSI standard says that
    enums may be freely intermixed with integral types, without errors.
    (If such intermixing were disallowed without explicit casts,
    judicious use of enums could catch certain programming errors.)

    For now, the advantages of enums (other than that the numeric values
    are automatically assigned) are 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) or when enum cases are left out of switch
    statements; and that a debugger may be able to display the symbolic
    values when enum variables are examined.

    References: K&R II Sec. 2.3 p. 39, Sec. A4.2 p. 196; H&S Sec. 5.5
    p. 100.

Operating System Dependencies

43. How can I read a single character from the keyboard without waiting
    for a newline?

A:  Contrary to popular belief and many people's wishes, this is not a
    C-related question.  The delivery of characters from a "keyboard" to
    a C program is a function of the operating system, and cannot be
    standardized by the C language.  Under UNIX, use ioctl to play with
    the terminal driver modes.  Under MS-DOS, use getch().  Under other
    operating systems, you're on your own.  Beware that some operating
    systems make this sort of thing impossible, because character
    collection into input lines is done by peripheral processors not
    under direct control of the CPU running your program.

44. How can I find out if there are characters available for reading
    (and if so, how many)?  Alternatively, how can I do a read that will
    not block if there are no characters available?

A:  These, too, are entirely operating-system-specific.  Depending on
    your operating system, you may be able to use "nonblocking I/O", or
    a system call named "select", or the FIONREAD ioctl.

45. 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.

46. How can a process change an environment variable in its caller?

A:  In general, it cannot.  If the calling process is prepared to listen
    explicitly for some indication that its environment should be
    changed, a special-case scheme can be set up.

Miscellaneous

47. Why does errno contain ENOTTY after a call to printf?

A:  Many implementations of the stdio package adjust their behavior
    slightly depending on whether stdout is a terminal or not.  To make
    this determination, these implementations perform an operation which
    fails (with ENOTTY) if stdout is not a terminal.  Although the
    output operation goes on to complete successfully, errno still
    contains ENOTTY.  This behavior can be mildly confusing, but it is
    not strictly incorrect, because it is only meaningful for a program
    to inspect the contents of errno after an error has occurred (that
    is, after a library function that sets errno on error has returned
    an error code).

48. My program's prompts and intermediate output don't always show up on
    my screen, especially when I pipe the output through another
    program.

A:  It is best to use an explicit fflush(stdout) at any point within
    your program at which output should definitely be visible.  Several
    mechanisms attempt to perform the fflush for you, at the "right
    time," but they do not always work, particularly when stdout is a
    pipe rather than a terminal.

49. I know that the library routine localtime will convert a time_t into
    a broken-down struct tm, and that ctime will convert a time_t to a
    printable string.  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, mktime, which converts a
    struct tm to a time_t.  Several public-domain versions of this
    routine are available if your compiler does not support it yet.

    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.

    References: K&R II Sec. B10 p. 256; H&S Sec. 20.4 p. 361.

50. I seem to be missing the system header file <sgtty.h>.  Can someone
    send me a copy?

A:  Standard headers exist in part so that definitions appropriate to
    your compiler, operating system, and processer can be supplied.  You
    cannot just pick up a copy of someone else's header file and expect
    it to work, unless that person uses exactly the same environment.
    Ask your vendor why the file was not provided (or to send another
    copy, if you've merely lost it).

51. Does anyone know of a program for converting Pascal (Fortran, lisp,
    "Old" C, ...) to C?

A:  Several public-domain programs are available:

    p2c  written by Dave Gillespie, and posted to comp.sources.unix in
         March, 1990.

    ptoc another comp.sources.unix contribution, this one written in
         Pascal.

    f2c  jointly developed by people from Bell Labs, Bellcore, and
         Carnegie Mellon.  To find about f2c, send the message "send
         index from f2c" to netlib@research.att.com or research!netlib.

    The comp.sources.unix archives also contain converters between
    "K&R" C and ANSI C.

    A number of companies, not listed here yet, sell various language
    translation tools, both to and from C.

52. Why don't C comments nest?  Are they legal inside quoted strings?

A:  C comments do not nest.  For this reason, it is usually better to
    "comment out" large sections of code, which might contain comments,
    with #ifdef.

    The character sequences /* and */ are not special within double-
    quoted strings, and do not therefore introduce comments, because a
    program (particularly one which is generating C code as output)
    might want to print them.

53. I'm having trouble with a Turbo C program which crashes and says
    something like "floating point not loaded."

A:  Some compilers for small machines, including Turbo C and Ritchie's
    original pdp11 compiler, attempt to leave out floating point support
    if it looks like it will not be needed.  In particular, the non-
    floating-point versions of printf and scanf do not handle %e, %f,
    and %g.  Occasionally the heuristics for "is the program using
    floating point?" are insufficient, and the programmer must insert
    one dummy explicit floating-point operation to force loading of
    floating-point support.  Unfortunately, an apparently common sort of
    program (thus the frequency of the question) uses scanf to read,
    and/or printf to print, floating-point values upon which no
    arithmetic is done, which elicits the problem under Turbo C.

    In general, questions about a particular compiler are inappropriate
    for comp.lang.c .  Problems with PC compilers, for instance, will
    find a more receptive audience in a PC newsgroup.

54. Does anyone have a C compiler test suite I can use?

A:  Plum Hall, among others, sells one.

55. I need a sort of an "approximate" strcmp routine, for comparing two
    strings for close, but not necessarily exact, equality.

A:  The classic routine for doing this sort of thing is the "soundex"
    algorithm, which maps similar-sounding words to the same numeric
    codes.  Soundex is described in the Searching and Sorting volume of
    Donald Knuth's classic The Art of Computer Programming.

The following frequent question(s) have answers which I haven't paid
attention to.  Please send answers you might have to scs@adam.mit.edu
and/or scs%adam.mit.edu@mit.edu, for inclusion in future updates to this
list.

56. Can anyone send me a YACC grammar for C?

    (Preliminary answers are net.sources/ansi.c.grammar.Z on
    uunet.uu.net, FSF's GNU C compiler grammar, and the appendix to
    K&R II.)

57. Where can I get the "Indian Hills Style Guide" and other coding
    standards?

    (I know that several of these are available at utzoo, but I don't
    have the details.)


Other questions to be added, once I write up the answers (suggestions
for more are welcome):

58. How can I get these public-domain programs?

    (The answer is mostly to see the periodic postings in the
    comp.sources groups.)

59. How can I find the day of the week given the date?

60. What is alloca and why is its use discouraged?


Thanks to Mark Brader, Joe Buehler, Christopher Calabrese, Stephen M.
Dunn, Tony Hansen, Blair Houghton, Kirk Johnson, Andrew Koenig, John
Lauro, Christopher Lott, Rich Salz, and Joshua Simons, who have
contributed, directly or indirectly, to this article.

                                             Steve Summit
                                             scs@adam.mit.edu
                                             scs%adam.mit.edu@mit.edu

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

scs@adam.mit.edu (Steve Summit) (06/01/90)

This article contains minimal answers to the comp.lang.c frequently
asked questions list.  Please see the long version for more detailed
explanations.

Null Pointers

1.  What is this infamous null pointer, anyway?

A:  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.

    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.

2.  How do I "get" a null pointer in my programs?

A:  A constant 0 in a pointer context is converted into a null pointer
    at compile time.  A "pointer context" is an assignment or comparison
    with one side a variable of pointer type, and (in ANSI standard C) a
    function argument which has a prototype in scope declaring a certain
    argument as being of pointer type.  In other contexts (function
    arguments without prototypes, or in the variable part of variadic
    functions) a constant 0 with an appropriate explicit cast is
    required.

    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.

3.  But aren't pointers the same as ints?

A:  Not since the early days.

    References: K&R I Sec. 5.6 pp. 102-3.

4.  What is NULL and how is it #defined?

A:  NULL is simply a preprocessor macro, #defined as 0 (or (void *)0)
    which is used (as a stylistic convention, in favor of unadorned 0's)
    to generate null pointers,

    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 X3.159-1989 Sec. 4.1.5 p. 99, Sec. 3.2.2.3
    p. 38, Rationale Sec. 4.1.5 p. 74.

5.  How should NULL be #defined on a machine which uses a nonzero bit
    pattern as the internal representation of the null pointer?

A:  The same as any other machine: as 0 (or (void *)0).  (The compiler
    makes the translation, upon seeing a 0, not the preprocessor.)

6.  If NULL were defined as "(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 kinds of pointers for different types of data.  A cast is
    still required to tell the compiler which kind of null pointer is
    required, since it may be different from (char *)0.

7.  My vendor provides header files that #define NULL as 0L.  Why?

A:  This definition, like (void *)0, helps incorrect programs work on
    some common architectures.

8.  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:  The construction "if(p)" works, regardless of the internal
    representation of null pointers, because the compiler essentially
    rewrites it as "if(p != 0)" and goes on to convert 0 into the
    correct null pointer.

    References: K&R II Sec. A7.4.7 p. 204; H&S Sec. 5.3 p. 91.

9.  If "NULL" and "0" are equivalent, which should I use?

A:  Either; the distinction is entirely stylistic.

    References: K&R II Sec. 5.4 p. 102.

10. But wouldn't it be better to use NULL (rather than 0) in case the
    value of NULL changes, perhaps on a machine with nonzero null
    pointers?

A:  No.  NULL is, and will always be, 0.

11. I'm confused.  NULL is guaranteed to be 0, but the null pointer is
    not?

A:  A "null pointer" (written in lower case in this article) is a
    language concept whose particular internal value does not matter.  A
    "null pointer" is requested in source code with the character '0'.
    "NULL" (always in capital letters) is a preprocessor macro, which is
    always #defined as 0 (or (void *)0).

12. Why is there so much confusion surrounding null pointers?  Why do
    these questions come up so often?

A:  The fact that null pointers are represented both in source code, and
    internally to most machines, as zero invites unwarranted
    assumptions.  The fact that a preprocessor macro (NULL) is often
    used suggests that this is done because the value might change
    later, or on some weird machine.

13. I'm still confused.  I just can't understand all this null pointer
    stuff.

A:  A simple rule is, "Always use `0' or `NULL' for null pointers, and
    always cast them when they are used in function calls."

Arrays and Pointers

14. I had the declaration char a[5] in one source file, and in another I
    declared extern char *a.  Why didn't it work?

A:  The declaration extern char *a simply does not match the actual
    definition.   Use extern char a[].

15. But I heard that char a[] was identical to char *a.

A:  This identity (that a pointer declaration is interchangeable with an
    array, usually unsized) holds _only_ for formal arguments to
    functions.

    References: K&R I Sec. 5.3 p. 95, Sec. A10.1 p. 205; K&R II Sec. 5.3
    p. 100, Sec. A8.6.3 p. 218, Sec. A10.1 p. 226; H&S Sec. 5.4.3 p. 96.

16. So what is meant by the "equivalence of pointers and arrays" in C?

A:  Saying that arrays and pointers are "equivalent" does not by any
    means imply that they are interchangeable.  "Equivalence" refers to
    the fact that arrays "turn into" pointers within expressions, and
    that pointers and arrays can both be dereferenced using array-like
    subscript notation.

    References: K&R I Sec. 5.3 pp. 93-6; K&R II Sec. 5.3 p. 99; H&S Sec.
    5.4.1 p. 93.

Order of Evaluation

17. Under my compiler, the program "int i = 7;
    printf("%d\n", i++ * i++); " prints 49.  Regardless of the order of
    evaluation, shouldn't it print 56?

A:  The operations implied by the postincrement and postdecrement
    operators ++ and -- are performed at some time after the operand's
    former values are yielded and before the end of the expression, but
    not necessarily immediately after, or before other parts of the
    expression are evaluated.

    References: K&R I Sec. 2.12 p. 50; K&R II Sec. 2.12 p. 54.

ANSI C

18. What is the "ANSI C Standard?"

A:  In 1983, the American National Standards Institute commissioned a
    committee, X3J11, to standardize the C language.  After a long and
    arduous process, this C standard was finally ratified as an American
    National Standard, X3.159-1989, on December 14, 1989, and published
    in the spring of 1990.

19. How can I get a copy of the ANSI C standard?

A:  Copies are available from the American National Standards Institute
    in New York, or from Global Engineering Documents in Irvine, CA.
    See the unabridged list for full addresses.

20. 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.

21. My ANSI compiler complains about a mismatch when it sees

         extern int blort(float);
         int blort(x)
         float x;
         {...

A:  You have mixed the new-style declaration "extern int blort(float);"
    with the old-style definition "int blort(x) float x;".  The problem
    can be fixed either by using new-style syntax consistently, or by
    changing the new-style declaration to match the old-style
    definition.

C Preprocessor

22. How can I write a macro to swap two values?

A:  There is no good answer to this question.  The best all-around
    solution is probably to forget about using a macro.

23. I'm getting strange syntax errors inside code which I've #ifdeffed
    out.

A:  Under ANSI C, #ifdeffed-out text must still consist of "valid
    preprocessing tokens."  This means that there must be no
    unterminated comments or quotes and no newlines inside quotes.

24. How can I write a cpp macro which takes a variable number of
    arguments?

    One popular trick is to define the macro with a single argument, and
    call it with a double set of parentheses, which appear to the
    compiler to indicate a single argument:

        #define DEBUG(args) {printf("DEBUG: ");printf args;}

        if(n != 0) DEBUG(("n is %d\n", n));

Variable-Length Argument Lists

25. How can I write a function that takes a variable number of
    arguments?

A:  Use varargs or stdarg.

    References: K&R II Sec. 7.3 p. 155, Sec. B7 p. 254; H&S Sec. 13.4
    pp. 286-9.

26. How can I write a function that takes a format string and a variable
    number of arguments, like printf, and passes them to printf to do
    most of the work?

A:  Use v*printf.

    References: K&R II Sec. 8.3 p. 174, Sec. B1.2 p. 245; H&S Sec. 17.12
    p. 337.

27. How can I discover how many arguments a function was actually called
    with?

A:  This information is not available to a portable program.  Any
    function which takes a variable number of arguments must be able to
    determine from the arguments themselves how many of them there are.

28. How can I write a function which takes a variable number of
    arguments and passes them to some other function (which takes a
    variable number of arguments)?

A:  In general, you cannot.

Memory Allocation

29. Why doesn't the code "char *answer; gets(answer);" work?

A:  The pointer variable "answer" has not been set to point to any valid
    storage.  The simplest way to correct this fragment is to use a
    local array, instead of a pointer.

Structures

30. I heard that structures could be assigned to variables and passed to
    and from functions, but K&R I says no.

A:  These operations are supported by all modern compilers.

    References: K&R I Sec. 6.2 p. 121; K&R II Sec. 6.2 p. 129; H&S Sec.
    5.6.2 p. 103.

31. How does struct passing and returning work?

A:  If you really need to know, see the unabridged list.

32. I have a program which works correctly, but it dumps core after it
    finishes.  Why?

A:  Check to see if a structure declaration just before main is missing
    its trailing semicolon, causing the compiler to think that main
    returns a struct.

33. Why can't you compare structs?

A:  There is no reasonable way for a compiler to implement struct
    comparison which is consistent with C's low-level flavor.

    References: K&R II Sec. 6.2 p. 129; H&S Sec. 5.6.2 p. 103.

34. 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.

35. How can I access structure fields by name at run time?

A:  Build a table of names and offsets, using the offsetof() macro.

Declarations

36. I can't seem to define a linked list node which contains a pointer
    to itself.

    Structs in C can certainly contain pointers to themselves; the
    discussion and example in section 6.5 of K&R make this clear.
    Problems arise when an attempt is made to define (and use) a typedef
    in the midst of such a declaration; avoid this.

    References: K&R I Sec. 6.5 p. 101; K&R II Sec. 6.5 p. 139; H&S Sec.
    5.6.1 p. 102.

37. How can I define a pair of mutually referential structures?

A:  The obvious technique works as long as any typedef synonyms are
    defined outside of the struct declarations.

    References: H&S Sec. 5.6.1 p. 102.

38. How do I declare a pointer to a function returning a pointer to a
    double?

A:  double *(*p)();
    Using a chain of typedefs, or the cdecl program, makes these
    declarations easier.

    References: H&S Sec. 5.10.1 p. 116.

39. So where can I get cdecl?

A:  Several public-domain versions are available.

Boolean Expressions and Variables

40. 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 because picking one
    involves a space/time tradeoff which is best decided by the
    programmer.  The choice between #defines and enums is arbitrary and
    not terribly interesting.

41. Isn't #defining TRUE to be 1 dangerous, 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, but
    this applies only "on input", i.e. where a boolean value is
    expected.  When a boolean value is generated by a built-in operator,
    it is guaranteed to be 1 or 0.

    References: K&R I Sec. 2.7 p. 41; K&R II Sec. 2.6 p. 42, Sec. A7.4.7
    p. 204, Sec. A7.9 p. 206.

42. What is the difference between an enum and a series of preprocessor
    #defines?

A:  At the present time, there is little difference.

    References: K&R II Sec. 2.3 p. 39, Sec. A4.2 p. 196; H&S Sec. 5.5
    p. 100.

Operating System Dependencies

43. How can I read a single character from the keyboard without waiting
    for a newline?

A:  Contrary to popular belief and many people's wishes, this is not a
    C-related question.  How to do so is a function of the operating
    system in use.

44. How can I find out if there are characters available for reading
    (and if so, how many)?  Alternatively, how can I do a read that will
    not block if there are no characters available?

A:  These, too, are entirely operating-system-specific.

45. 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.  You may be able to
    duplicate the command language interpreter's search path logic to
    locate the executable.

46. How can a process change an environment variable in its caller?

A:  In general, it cannot.

Miscellaneous

47. Why does errno contain ENOTTY after a call to printf?

A:  Don't worry about it.  It is only meaningful for a program to
    inspect the contents of errno after an error has occurred.

48. My program's prompts and intermediate output don't always show up on
    my screen, especially when I pipe the output through another
    program.

A:  It is best to use an explicit fflush(stdout) at any point within
    your program at which output should definitely be visible.

49. I know that the library routine localtime will convert a time_t into
    a broken-down struct tm, and that ctime will convert a time_t to a
    printable string.  How can I perform the inverse operations of
    converting a struct tm or a string into a time_t?

A:  The ANSI mktime routine converts a struct tm to a time_t.  No
    standard routine exists to convert strings.

    References: K&R II Sec. B10 p. 256; H&S Sec. 20.4 p. 361.

50. I seem to be missing the system header file <sgtty.h>.  Can someone
    send me a copy?

A:  You cannot just pick up a copy of someone else's header file and
    expect it to work, since the definitions within the file are
    frequently system-dependent.  Contact your vendor.

51. Does anyone know of a program for converting Pascal (Fortran, lisp,
    "Old" C, ...) to C?

A:  Several public-domain programs are available, namely ptoc, p2c, and
    f2c.  A number of companies, not listed here yet, sell various
    language translation tools, both to and from C.

52. Why don't C comments nest?  Are they legal inside quoted strings?

A:  C comments do not nest.  The character sequences /* and */ are not
    special within double-quoted strings.

53. I'm having trouble with a Turbo C program which crashes and says
    something like "floating point not loaded."

A:  Some compilers for small machines, including Turbo C and Ritchie's
    original pdp11 compiler, attempt to leave out floating point support
    if it looks like it will not be needed.  The programmer must
    occasionally insert one dummy explicit floating-point operation to
    force loading of floating-point support.

54. Does anyone have a C compiler test suite I can use?

A:  Plum Hall, among others, sells one.

55. I need a sort of an "approximate" strcmp routine, for comparing two
    strings for close, but not necessarily exact, equality.

A:  The classic routine for doing this sort of thing is the "soundex"
    algorithm.

                                             Steve Summit
                                             scs@adam.mit.edu
                                             scs%adam.mit.edu@mit.edu

This article is Copyright 1988, 1990 by Steve Summit.
It may be freely redistributed so long as the author's name, and this
notice, are retained.

scs@adam.mit.edu (Steve Summit) (06/01/90)

Thanks for all of the feedback and support on the frequently-
asked questions posting.  Most of the suggestions have been
incorporated.  (Unfortunately, these plus a few new questions
leave it 20% longer.)

It has been suggested that the posting be broken up into chunks
posted weekly, on a rotating basis.  This seems like a good idea,
and I plan to work on it, but first I need to set up mechanisms
by which people can request the part they need (as opposed to the
part they just saw).  Raymond Chen at Berkeley has such a system,
which I may grab and use intact.  I'd be interested in having the
articles available at the standard archive sites as well, if the
administrators are amenable.

A weekly posting, even if partial, should heighten visibility.
I've been distressed to see something like five of the questions
on the first list being asked in the past few days...

I think I'll continue to post the full list, with its longer
introduction, monthly.  I'm also wondering if a periodic "Welcome
to comp.lang.c" posting, containing among other things a pointer
to the frequently asked questions postings, is appropriate.  I'm
sure it's been discussed before.

Keep the feedback coming.  I do appreciate it.  (The first post
was deliberately a bit rough, to get something out the door,
since it's always easier to criticize and work incrementally from
something that exists.)

Apparently some people are having trouble sending mail to
adam.mit.edu .  If it bounces, try scs%adam.mit.edu@mit.edu, and
let me know that the preferred address didn't work, especially if
your mailer uses named, which is (I believe) what the MIT mailers
are set up for.  (If you're still using /etc/hosts, it's not
likely that yours knows about adam, which is a tiny, backwater
machine.)  uucp paths through mit-eddie should also work
(mit-eddie!adam!scs), but I haven't tested this lately.

                                         Steve Summit
                                         scs@adam.mit.edu
                                         scs%adam.mit.edu@mit.edu

scs@adam.mit.edu (Steve Summit) (06/02/90)

In article <1990Jun1.110510.4814@athena.mit.edu> I carelessly wrote:
>    Old C
>    silently promoted doubles to floats when passing them as arguments...

Oops.  That should, of course, say that Old C promotes floats to
doubles.  Thanks to Erik Talvola for pointing this out.

                                            Steve Summit
                                            scs@adam.mit.edu