1. What is a good reference book for C?
    Brian W. Kernighan, Dennis, M. Ritchie
    The C Programming Language, 2nd ed.
  2. How do I find a function by name in the C standard library?
    man 3 function
  3. How do I find functions in the C standard library without knowing the exact name?
    man -k keyword
  4. What if I can't use the Unix man command?
    Use the Web interface to the manuals at http://www.cse.unsw.edu.au/scripts/man.
  5. Where is the hash table in the C standard library?
    There isn't one. C is a much more low-level language than, say, Java. This is reflected in the standard libraries too, which tend to be limited to the essentials.

    Note that there are good reasons for this. A generic hash-table library is ok for someone who just quickly needs a hash table and doesn't really care about its implementation. However, if you build a system for which hash table lookup is a performance-critical operation, you don't want to rely on some generic (and, possibly, changing without notice) implementation. Instead you want to ensure that what you're using is optimised to your requirements.

    This, btw, is rather typical for the differences between C and Java.

  6. How do I use the debugger?
    Read the C Debugging Quickstart and gdb(1).
  7. How can I fix malloc-related errors?
    There a few automatic tools you can use to detect and identify these bugs. The most useful is gdb(1) (especially watchpoints). There is also a watchmalloc(3X) library in Solaris. For catching memory leaks, it is possible to count calls to malloc() and free() with a profiler. To do this, compile with gcc -pg, run the programme, and then view the statistics with gprof(1).
  8. What does #define NewTrain SignalBox1 mean?
    This is roughly equivalent to:
    static const int  NewTrain = SignalBox1;
    I highly recommend avoiding #define and using functions and const variables instead. Even though #define is standard C usage and results in slightly faster code from some compilers, it frequently leads to obscure bugs and errors.
  9. What can I put in a .h file? Can I define global variables there?
    Large C programmes are usually split into multiple .c files, and each is compiled separately. Declarations which must be visible in multiple C files are typically centralized in a header file rather than repeated at the top of every C file. Header files conventionally end in .h and are included with #include.

    Function definitions, initialized globals, and anything else that should only be compiled once do NOT belong in .h files. The only thing that should go in a .h file should be function prototypes, extern variable declarations, type definitions, and #defines (but see FAQ. 8).

  10. Why am I getting link errors involving memset()? I never call the function.
    Sometimes complex initialization of an automatic variable, like:
    int iob_flags[20] = { READ, WRITE, WRITE|UNBUF };
    results in the compiler generating a call to memset(). If your standard library is missing this function, linking may fail. You can fix this by making the variable static (and thus initialized at load time), initializing it with a loop, or defining your own memset() function.

    Note that too many large automatic variables will quickly overflow the stack, so allocate large arrays statically or dynamically if possible.

  11. I'm getting linking errors for functions from the C standard library. Why is that?
    Remember, if you are writing code inside Topsy, you're working in the kernel of the operating system. Many library functions (like I/O or malloc()) require the functionality of an operating system. This obviously means that they cannot be used inside the OS itself! Hence, kernel programmers can only rely on a subset of the C standard library.
  12. Why don't I get a warning for using an uninitialized automatic variable?
    Due to an acknowledged bug in gcc, -Wuninitialized (which is implied by -Wall) only works when optimizing, and even then only some of the time. Add -O to your compiler flags, either by
    export CFLAGS="-O -Wall"
    or by editing the Makefile. Read gcc(1) for more details.

    Note that if the behaviour of your programme changes after optimizations are enabled, this is usually due to a bug in your code turned up because of changed memory layout, and does not indicate a bug in the compiler.

  13. How is it possible to write code without malloc()?
    System code frequently has to go without dynamic memory allocation. Fortunately many data structures do NOT need to grow indefinitely, but can be statically allocated with a fixed size. For example, a frame table need only be as big as the number of frames in physical memory.

    Sometimes you need to impose a judicious limit on the size of your data structure, like the size of the process table in Unix. If you do this, then you MUST check the table for overflow, and handle this error appropriately.

    It is still possible to use linked data structures without malloc(). For example, a linked list (such as a free list or hash chain) can run through structures which have been allocated statically.

  14. How do I divide integers rounding up?
    Write (x - 1 + y) / y instead of x / y. Do NOT use floating point!
  15. The compiler is broken! Optimizing my programme changes its behaviour.

    If your programme has different behaviour with different optimization levels, then usually the bug is in your C code, not the compiler. Wild pointers for example will corrupt different variables depending on how the optimized code uses registers, etc.

    Systems code often needs to disable optimizations by forcing a real memory reference that looks redundant to the compiler. Examples are memory-mapped I/O, thread-shared variables, and virtual memory code. In these cases, add volatile to the variable declaration. Declare each volatile variable separately, do not use commas!

  16. What is a prototype and why do I want one?
    Prototypes are function declarations, allowing a function in one C file to call another in a different C source file. For example, if you have the function
    void *get_free_frame(void) { ... }
    add the prototype
    void *get_free_frame(void);
    to a header file which is #included by all C files which reference the function, even including the C file in which you define it.

    If you try to call this function without a proper prototype, you get the warning:

    warning: implicit declaration of function `get_free_frame'
    and your programme may not work correctly.
  17. How do I externalize data structures?

    First of all, it is generally better style to externalize functions using prototypes (see FAQ 15) than data structures. However, if you still want to, declare the external variable twice: once in a .h file with extern, and a second time in a .c file with no storage class. Do not declare the variable static.

  18. How do I find out whether I am freeing enough memory?
    The easiest way is to count the calls to malloc and free. There is a tool called gprof which can do this for your automatically. For example, in the following example I run gprof on my solution to the first C exercise. (-pg flag enables gprof support.)
    	% export CFLAGS="-Wall -g -pg"
    	% make spellcheck
    	gcc -Wall -g -pg -o spellcheck spellcheck.c
    	% ./spellcheck
    	Spell checker ready.  Type a word now.
    You must run the programme to produce the statistics, which are saved in a file called gmon.out. The gprof command uses these statistics to produce all sorts of interesting output, including:
    	% gprof spellcheck
    	  0.0       0.23     0.00    50287     0.00     0.00  malloc [12]
    	  0.0       0.23     0.00    50286     0.00     0.00  free [6]
    which shows that malloc was called 50287 times, free 50286 times. Searching the output for malloc [12] explains the difference of one.
    	        0.00        0.00       1/50287       _findbuf [23]
    	        0.00        0.01   25143/50287       addword [4]
    	        0.00        0.01   25143/50287       _strdup [7]

    malloc is called 25143 times by my function addword, 25143 times by strdup, and once by _findbuf, which is internal to the C standard library. While my code seems to be free of memory leaks, the standard library seems not to bother freeing its I/O buffers before the process exits.

    Showing that your code calls free as many times as malloc does not prove that your code has no bugs. However, if the numbers do not match at all, then your code probably leaks memory.

  19. How do I find the integer values of CAR_ARRIVE, CAR_LEAVE, etc., so I can use them in my code?

    DON'T hard-wire integer constants (‘magic numbers’) in your code! This coding style, popular in Java, is unacceptable in C because there are at least three good mechanisms for defining symbolic names for constants: #define, enum, and const. Also see the C style guide.