C AntiPatterns

This page collects some bad C code that may not look so obviously bad for beginners. It's only about C, not C++, but C++ programmers may benefit by reading the examples. They include programming errors (e.g. misunderstanding of what a variable is and where it resides) and design-in-C bad practices (e.g. use of malloc() where a constructor should be more suitable. Remember that plain C can use constructors, given that ctors are a design thing, not a C++-exclusive thing).

Naive local pointer update

This is not a bad practice but a rough programming error. I point it out here since I have seen it so many times, even on proprietary production code! And it's also a common source of frustration for beginners when handling structures passed by argument to functions.

1   #include <stdio.h>
2 
3   void setNull (int *p)
4   {
5       int x;  /* unused. only to make more clear the stack diagram below */
6       p = NULL;
7   }
8
9   int main (int argc, char *argv[])
10   {
11     int a = 1;
12     int *p = &a;
13     setNull(p);
14     if (p != NULL) {
15       puts ("It's correct! p contains the address of a");
16     }
17     return 0;
18  }

On line 14 p is not NULL, contrary to what a beginner may expect.

C support local variables. They are created upon entry to function and destroyed when function returns. Who creates or destroys them (the caller or the callee) depends on the calling convention used, but the same explanation applies: each invocation of a function has its own instantiation of local variables. The portion of the stack used for an invocation of a function is called the function's stack frame[1].

In the code above, there are 2 pointer variables:

  • 1 resides in main()'s stack of local variables
  • 1 resides in setNull()'s stack frame
The assignment on line 6 assigns a NULL value to the pointer variable in setNull's stack frame, but not to the pointer variable on main's stack of local variables.

Graphically, the call stack when setNull is invoked on line 13 is:

The assignment of NULL in line 6 occurs to the variable in setNull's stack frame (the variable shown with purple background in the stack memory diagram), and not to the p variable local to main.

That's why after the call to setNull on line 13 you cannot expect the p pointer to point to some other value than the address of a. The situation of the example is typical not only of setting NULL values, but appears in a more general scenario when you use output parameters to send output values from a function, e.g. the address of a newly created structure like a tree, linked list, error description structure or similar.

How to solve the problem? If you want to change main's p pointer from inside of setNull, you need to pass to setNull the address of that pointer. That is, a pointer to pointer. A solution to the above code may look like:
1   #include <stdio.h>
2 
3   void setNull (int **p)
4   {
5       int x;      /* unused */
6       *p = NULL;  /* Probably you should add a non-nullity check for p before this */
7   }
8
9   int main (int argc, char *argv[])
10   {
11     int a = 1;
12     int *p = &a;
13     setNull(&p);
14     if (p == NULL) {
15       puts ("Fine, p must be NULL at this point");
16       return 0;
17     } else {
18       return 1;
19     }
20  }

Now setNull can modify main's local pointer, since it has its address. With this new code, on invocation of setNull the call stack looks like:

call stack for the new code




Maintained by Duilio Protti