Tutorial :debugging c programs



Question:

Programming in a sense is easy. But bugs are something which always makes more trouble. Can anyone help me with good debugging tricks and softwares in c?


Solution:1

The following are popular debugging tools.

Some very simple Tricks/Suggestions

-> Always check that nowhere in your code you have dereferenced a wild/dangling pointer

Example 1)

int main()  {       int *p;       *p=10; //Undefined Behaviour (crash on most implementations)  }  

Example 2)

int main()  {         int *p=malloc(sizeof(int));       //do something with p         free p;       printf("%d", *p); ////Undefined Behaviour (crash on most implementations)  }  

-> Always initialize variables before using

 int main()    {        int k;        for(int i= k;i<10;++i)                ^^              Ouch        printf("%d",i");    }  


Solution:2

From "The Elements of Programming Style" Brian Kernighan, 2nd edition, chapter 2:

Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?

So from that; don't be "too clever"!

But apart from that and the answers already given; use a debugger! That is your starting point tool-wise. You'd be amazed how many programmers struggle along without the aid of a debugger, and they are fools to do so.

But before you even get to the debugger, get your compiler to help you as much as possible; set the warning level to high, and set warnings as errors. A static analysis tool such as lint, pclint, or QA-C would be even better.


Solution:3

Tools for debugging are all well and good and for some classes of error they will just point you straight to the problem. The best tip that I have for debugging is that you need to think about it in the right way. What works for me is the following:

  • The compiler probably isn't broken. I've been working with C for 25 years now and in all that time it's almost invariably something I'm doing wrong.
  • Read the error messages. Often I've looked back at the error message and in hindsight realized it was telling me exactly what was wrong.
  • Read the documentation. Make sure you aren't making assumptions about the language or library that aren't true.
  • Make a mental model of the problem. I ask myself what needs to be hapening in my code in order for the results I'm seeing to occur. Then add debug statements, assertions or just step through in the debugger (if you can) to see what is really happening.
  • Talk the problem through with someone else. Just describing it to a a third party often results in a revelation about what might be happening.

Other people will have other ways of approaching debugging, but I find if you have a structured approach to it rather than flailing around changing stuff at random you usually get there and when you do be prepared for the inevitable Why didn't I see that straight away!


Solution:4

Best debugger for C

  1. gdb

Best tools for memory leak checking:

  1. Valgrind


Solution:5

Unit testing. Makes getting your software correct a lot easier.


Solution:6

  1. gdb is a debugger to analyse your program.
  2. Other techinque is to use printf or logs
  3. Valgrind provides dynamic analysis of the executable
  4. Purify provides static and dynamic analysis. Sparrow and Prevent are some other tools in competition to Purify.


Solution:7

This can be separated into:

Prevention measures:

  1. Use strict coding styles, don't make a mess
  2. Use comments and code revisions
  3. Use static code analysis tools
  4. Use assertions where it's possible
  5. Don't over complicate

Post-factum

  1. Use debugger/tracer
  2. Use memory checking tools
  3. Use regression testing
  4. Use your brain


Solution:8

In addition to all the other suggestions (gdb, valgrind, all that), some simple rules when writing the code help a lot when debugging afterwards.

  • Always use types with the proper semantics. Unsigned types (best size_t) for array indices and numbers that represent a cardinal, ptrdiff_t for pointer differences, off_t for file offsets etc. enum types for tags and case distinctions.
  • There is almost no need for the builtin types int, long, char or whatever. Avoid them whenever possible.
  • In particular don't use char for arithmetic, the signedness problems with that are a plague. Use uint8_t or int8_t if you feel the need for such a thing.
  • Always initialize variables, all of them: integer, double, pointers, struct. It is not true that this is less efficient with a modern compiler. In most cases it will just be optimized away when not necessary. But especially pointer variables that are not properly initialized can produce spurious errors and make code hard to debug. If you have them initialized to NULL your program will fail early, and your debugger will show you the place.
  • Compile with all warnings on, and don't finish tidying your code until the compiler doesn't give a single warning. They are quite good at that nowadays, take advantage.
  • Compile with different optimization options on, or even better with different versions of your compiler, or still better with completely different compilers on different platforms.
  • Use the assert macro. This forces you to think of your assumptions and also make your code fail early if they are not fulfilled.


Solution:9

Off the top of my head, Valgrind.


Solution:10

You might also want to hone your debugging skills by reading the book Debugging by David Agans. Every programmer should read this early on in their career.


Solution:11

valgrind for memory problems if you're on linux. use gdb/ddd on linux as well. On windows a lot of windows programmers don't seem to be knowledgeable of windbg. It is very useful but has a learning curve like gdb; more powerful than the built in debugger in visual studio. learn to use assert, you will catch lots of stuff and you can turn it off in release code if you so choose. Use a unit testing framework like Check, cunit, etc . Always initialize your pointer, to NULL if nothing else. When you free a pointer set it to NULL. Better you to catch a segfault than your user. Pick a coding standard and stick to it, consistency will help you make fewer mistakes. Keep your functions small if at all possible, this will keep you from having 10 level deep braces which are logic nightmares. If compiling using gcc use -Wall and -Wextra . Use the strn* functions instead of str* functions. Well worth the extra thinking they force you to do.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »