5 Common C Bugs Every Programmer Should Avoid
This article outlines five typical C programming mistakes—uninitialized variables, array out‑of‑bounds access, string overflow, double free, and invalid file pointers—explaining why they occur, showing concrete code examples with varied outputs, and offering practical safeguards to prevent them.
1. Uninitialized Variables
When a program starts, the operating system allocates memory that may contain arbitrary data. Declaring variables without an explicit initializer leaves them with indeterminate values, which can differ between runs and platforms. Initializing every variable (including automatic arrays) eliminates this source of nondeterminism.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i, j, k;
int numbers[5];
int *array;
puts("These variables are not initialized:");
printf(" i = %d
", i);
printf(" j = %d
", j);
printf(" k = %d
", k);
puts("This array is not initialized:");
for (i = 0; i < 5; i++) {
printf(" numbers[%d] = %d
", i, numbers[i]);
}
puts("malloc an array ...");
array = malloc(sizeof(int) * 5);
if (array) {
puts("This malloc'ed array is not initialized:");
for (i = 0; i < 5; i++) {
printf(" array[%d] = %d
", i, array[i]);
}
free(array);
}
puts("Ok");
return 0;
}Running the program on different operating systems (e.g., Windows, FreeDOS) shows different garbage values, demonstrating the need for explicit initialization.
2. Array Out‑of‑Bounds Access
Arrays in C are zero‑based. Accessing an index equal to or greater than the declared size reads or writes memory outside the array, producing undefined values and often causing crashes.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i;
int numbers[5];
int *array;
puts("This array has five elements (0 to 4)");
for (i = 0; i < 5; i++) {
numbers[i] = i;
}
for (i = 0; i < 10; i++) {
printf(" numbers[%d] = %d
", i, numbers[i]);
}
puts("malloc an array ...");
array = malloc(sizeof(int) * 5);
if (array) {
puts("This malloc'ed array also has five elements (0 to 4)");
for (i = 0; i < 5; i++) {
array[i] = i;
}
for (i = 0; i < 10; i++) {
printf(" array[%d] = %d
", i, array[i]);
}
free(array);
}
puts("Ok");
return 0;
}The first five reads are correct; the remaining reads produce random numbers. Writing beyond the bounds would typically trigger a segmentation fault.
3. String Overflow
In C, a string is a char array. Using unsafe input functions such as gets reads without any length check, allowing the user to overwrite adjacent memory.
#include <stdio.h>
#include <string.h>
int main(void) {
char name[10]; /* space for up to 9 characters + '\0' */
int var1 = 1, var2 = 2;
printf("var1 = %d; var2 = %d
", var1, var2);
puts("Where do you live?");
gets(name); /* unsafe – no bounds checking */
printf("<%s> is length %zu
", name, strlen(name));
printf("var1 = %d; var2 = %d
", var1, var2);
puts("Ok");
return 0;
}When the input fits (e.g., "Beijing"), the program behaves correctly. Supplying a longer string such as the 58‑character Welsh town name overwrites var1 and var2, producing incorrect values and often a segmentation fault. Safer alternatives include fgets with an explicit buffer size or getline, which allocates sufficient memory automatically.
4. Double Free
Memory allocated with malloc must be released exactly once. Calling free on the same pointer a second time results in undefined behavior, typically detected as a double‑free error and program abort.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *array;
puts("malloc an array ...");
array = malloc(sizeof(int) * 5);
if (array) {
puts("malloc succeeded");
puts("Free the array...");
free(array);
}
puts("Free the array again...");
free(array); /* double free – undefined */
puts("Ok");
return 0;
}Running this program typically prints a double‑free detection message and aborts.
5. Using an Invalid File Pointer
Opening a non‑existent file with fopen returns NULL. Using the returned pointer without checking leads to an immediate segmentation fault.
#include <stdio.h>
int main(void) {
FILE *pfile;
int ch;
puts("Open the FILE.TXT file ...");
pfile = fopen("FILE.TXT", "r");
/* Guard against failure */
if (pfile == NULL) {
puts("Failed to open FILE.TXT");
return 1;
}
puts("Now display the contents of FILE.TXT ...");
while ((ch = fgetc(pfile)) != EOF) {
printf("<%c>", ch);
}
fclose(pfile);
puts("Ok");
return 0;
}The added if (pfile != NULL) check prevents a crash when the file is missing.
Conclusion
Even experienced C programmers can fall into these five common pitfalls: uninitialized variables, out‑of‑bounds array access, unsafe string input, double freeing of heap memory, and neglecting to validate file pointers. Consistently initializing data, respecting array bounds, using bounded input functions, freeing memory exactly once, and checking the result of fopen are simple practices that dramatically reduce undefined behavior and improve program reliability.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
