Tutorial by Examples

It is usually not a good idea to mix signed and unsigned integers in arithmetic operations. For example, what will be output of following example? #include <stdio.h> int main(void) { unsigned int a = 1000; signed int b = -1; if (a > b) puts("a is more than b&quot...
The = operator is used for assignment. The == operator is used for comparison. One should be careful not to mix the two. Sometimes one mistakenly writes /* assign y to x */ if (x = y) { /* logic */ } when what was really wanted is: /* compare if x is equal to y */ if (x == y) { ...
Be careful with semicolons. Following example if (x > a); a = x; actually means: if (x > a) {} a = x; which means x will be assigned to a in any case, which might not be what you wanted originally. Sometimes, missing a semicolon will also cause an unnoticeable problem: if (i &lt...
When you are copying a string into a malloced buffer, always remember to add 1 to strlen. char *dest = malloc(strlen(src)); /* WRONG */ char *dest = malloc(strlen(src) + 1); /* RIGHT */ strcpy(dest, src); This is because strlen does not include the trailing \0 in the length. If you take the ...
A programming best practice is to free any memory that has been allocated directly by your own code, or implicitly by calling an internal or external function, such as a library API like strdup(). Failing to free memory can introduce a memory leak, which could accumulate into a substantial amount of...
char buf[8]; /* tiny buffer, easy to overflow */ printf("What is your name?\n"); scanf("%s", buf); /* WRONG */ scanf("%7s", buf); /* RIGHT */ If the user enters a string longer than 7 characters (- 1 for the null terminator), memory behind the buffer buf will be...
If realloc fails, it returns NULL. If you assign the value of the original buffer to realloc's return value, and if it returns NULL, then the original buffer (the old pointer) is lost, resulting in a memory leak. The solution is to copy into a temporary pointer, and if that temporary is not NULL, th...
Floating point types (float, double and long double) cannot precisely represent some numbers because they have finite precision and represent the values in a binary format. Just like we have repeating decimals in base 10 for fractions such as 1/3, there are fractions that cannot be represented fini...
In pointer arithmetic, the integer to be added or subtracted to pointer is interpreted not as change of address but as number of elements to move. #include <stdio.h> int main(void) { int array[] = {1, 2, 3, 4, 5}; int *ptr = &array[0]; int *ptr2 = ptr + sizeof(int) * 2; ...
Macros are simple string replacements. (Strictly speaking, they work with preprocessing tokens, not arbitrary strings.) #include <stdio.h> #define SQUARE(x) x*x int main(void) { printf("%d\n", SQUARE(1+2)); return 0; } You may expect this code to print 9 (3*3), ...
One of the most common errors in compilation happens during the linking stage. The error looks similar to this: $ gcc undefined_reference.c /tmp/ccoXhwF0.o: In function `main': undefined_reference.c:(.text+0x15): undefined reference to `foo' collect2: error: ld returned 1 exit status $ So l...
A common problem in code that uses multidimensional arrays, arrays of pointers, etc. is the fact that Type** and Type[M][N] are fundamentally different types: #include <stdio.h> void print_strings(char **strings, size_t n) { size_t i; for (i = 0; i < n; i++) puts(str...
When allocating multidimensional arrays with malloc, calloc, and realloc, a common pattern is to allocate the inner arrays with multiple calls (even if the call only appears once, it may be in a loop): /* Could also be `int **` with malloc used to allocate outer array. */ int *array[4]; int i; ...
In C, character constants and string literals are different things. A character surrounded by single quotes like 'a' is a character constant. A character constant is an integer whose value is the character code that stands for the character. How to interpret character constants with multiple charac...
Almost every function in C standard library returns something on success, and something else on error. For example, malloc will return a pointer to the memory block allocated by the function on success, and, if the function failed to allocate the requested block of memory, a null pointer. So you sho...
When this program #include <stdio.h> #include <string.h> int main(void) { int num = 0; char str[128], *lf; scanf("%d", &num); fgets(str, sizeof(str), stdin); if ((lf = strchr(str, '\n')) != NULL) *lf = '\0'; printf("%d \"%s\&...
It is easy to get confused in the C preprocessor, and treat it as part of C itself, but that is a mistake because the preprocessor is just a text substitution mechanism. For example, if you write /* WRONG */ #define MAX 100; int arr[MAX]; the code expands to int arr[100;]; which is a synta...
In C, multi-line comments, /* and */, do not nest. If you annotate a block of code or function using this style of comment: /* * max(): Finds the largest integer in an array and returns it. * If the array length is less than 1, the result is undefined. * arr: The array of integers to search....
Arrays are zero-based, that is the index always starts at 0 and ends with index array length minus 1. Thus the following code will not output the first element of the array and will output garbage for the final value that it prints. #include <stdio.h> int main(void) { int x = 0; ...
Calculating the factorial of a number is a classic example of a recursive function. Missing the Base Condition: #include <stdio.h> int factorial(int n) { return n * factorial(n - 1); } int main() { printf("Factorial %d = %d\n", 3, factorial(3)); return 0;...

Page 1 of 2