|
|
C AntiPatternsThis 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 updateThis 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.
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:
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:
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:
|
|||
|
|