C Tips and Tricks
This page contains a running list of common patterns frequently used by C programmers.
Reading from command line
The following program prints out all command-line arguments.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
for (int i = 0; i < argc; i++) {
printf("argv[%d]: %s\n", i, argv[i]);
}
return EXIT_SUCCESS;
}
The last command prints
A common usage of command-line arguments is to specify files. This following
idiom, adapted from K&R, page 162, processes each file specified
in command line, and if no files is specified, uses stdin
instead.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void do_stuff(FILE *fp);
int main(int argc, char *argv[])
{
if (argc == 1) { /* no args; use standard input */
do_stuff(stdin);
} else {
for (int i = 1; i < argc; i++) {
FILE *fp = fopen(argv[i], "r");
if (fp == NULL) {
int rc = errno;
fprintf(stderr,
"%s: could not open %s (%s)\n",
argv[i],
stderror(errno));
exit(rc);
}
do_stuff(fp);
fclose(fp);
}
}
return EXIT_SUCCESS;
}
malloc
DO NOT calculate the size by hand, such as . There are many
things wrong with this code; for examples,
1. If malloc(32)
SomeType
is a struct
, adding a field in SomeType
requires changes
all allocation code of this struct
;
2. Most primitive types in C are platform-dependent;
3. One may fail to consider struct
padding.
DO NOT repeat the type name in sizeof
, such as
.
This is much better than the previous example, but consider a change in the type
of malloc(sizeof(struct SomeType))
x
to SomeOtherType
.
A change in the type of x
means a change in two places:
.SomeOtherType x = malloc(sizeof(struct SomeOtherType))
Zero initialization of compound types
struct SomeStruct node = { 0 }; /* zero-initialize all fields */
double array[32] = { 0 }; /* zero-initialize all elements */
This saves programmer from looping over the array or writing an assignment statement for each field.
If the value one wants to zero-initialize is in the heap, use calloc
struct SomeStruct *node = calloc(/* count */ 1, sizeof *node);
double *array = calloc(/* count */ 32, sizeof *array);
Assertion context
Unlike Python, C's assertion does not have a place to write a message.
Fortunately, we can use the fact that string literals, which are non-zero
pointers (of type const char *
), evaluate to true
when used as a boolean
value.
In other words, x == y && "x is equal to y"
evaluates to true
if and only if
x == y
is true, but the entire condition is displayed when the assertion fails.
Silencing unused variables
In this class, C programs are built with -Werror
, which turns warnings into
errors. This trick will come in handy when you want to test-run an incomplete
solution.