Fundamentals 13 min read

5 Sneaky C Bugs Every Programmer Should Avoid

This article lists five common C programming mistakes—uninitialized variables, array out‑of‑bounds access, string overflow, double free, and invalid file pointers—explains why they occur, shows concrete code examples with typical output, and offers practical ways to prevent each bug.

Liangxu Linux
Liangxu Linux
Liangxu Linux
5 Sneaky C Bugs Every Programmer Should Avoid

1. Uninitialized Variables

When a variable is defined without an explicit initializer, its value is indeterminate. The content may appear as zero on some systems, but portable C code must initialize all automatic variables to avoid random values that can cause logic errors or crashes.

#include <stdio.h>
#include <stdlib.h>

int main() {
    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 platforms yields different garbage values, demonstrating why every automatic variable, array element, and dynamically allocated memory should be explicitly initialized (e.g., using memset or assigning zero).

2. Array Out‑of‑Bounds Access

In C, arrays are zero‑based. Accessing an index equal to or greater than the array length reads or writes memory outside the allocated region, which leads to undefined behavior, possible data corruption, or crashes.

#include <stdio.h>
#include <stdlib.h>

int main() {
    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++) {  // out‑of‑bounds read
        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++) {  // out‑of‑bounds read
            printf("  array[%d] = %d
", i, array[i]);
        }
        free(array);
    }
    puts("Ok");
    return 0;
}

The first five reads are valid; the remaining indices produce unpredictable values. Writing beyond the bounds would typically cause an immediate segmentation fault.

3. String Overflow

In C, a string is an array of char. Using unsafe input functions such as gets allows the user to write more characters than the buffer can hold, overwriting adjacent variables and potentially crashing the program.

#include <stdio.h>
#include <string.h>

int main() {
    char name[10];               /* buffer 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 – does not limit input length */
    printf("<%s> is length %zu
", name, strlen(name));
    printf("var1 = %d; var2 = %d
", var1, var2);
    puts("Ok");
    return 0;
}

Providing a short input (e.g., "Beijing") works, but a long input such as the 58‑character town name "Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch" overwrites var1 and var2, changes their values, and may trigger a segmentation fault. Safer alternatives include fgets with a size limit or getline, which allocates sufficient memory automatically.

4. Double Free (Repeated Memory Release)

Memory allocated with malloc must be released exactly once with free. Calling free on the same pointer a second time results in undefined behavior, often detected as a "double free" error and causing program termination.

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *array;
    puts("malloc an array ...");
    array = malloc(sizeof(int) * 5);
    if (array) {
        puts("malloc succeeded");
        free(array);               /* first free */
    }
    puts("Free the array again ...");
    free(array);                   /* second free – error */
    puts("Ok");
    return 0;
}

Typical mitigation strategies are:

Set the pointer to NULL immediately after freeing, so a subsequent free becomes a no‑op.

Encapsulate allocation and deallocation in the same function or module to keep ownership clear.

Use tools such as Valgrind or AddressSanitizer to detect double‑free bugs during development.

5. Using an Invalid File Pointer

The fopen function returns NULL when the requested file cannot be opened (e.g., it does not exist or permission is denied). Dereferencing a null file pointer leads to a segmentation fault.

#include <stdio.h>

int main() {
    FILE *pfile;
    int ch;

    puts("Open the FILE.TXT file ...");
    pfile = fopen("FILE.TXT", "r");
    if (pfile == NULL) {
        perror("fopen failed");
        return 1;
    }

    puts("Now display the contents of FILE.TXT ...");
    while ((ch = fgetc(pfile)) != EOF) {
        printf("<%c>", ch);
    }
    fclose(pfile);
    puts("Ok");
    return 0;
}

Always check the return value of fopen before using the pointer. If the check fails, handle the error gracefully (e.g., print a diagnostic message and exit or fall back to a default configuration).

Conclusion

These five classic C pitfalls—uninitialized variables, out‑of‑bounds array access, string overflow, double free, and invalid file pointers—are common sources of undefined behavior and crashes. By habitually initializing data, respecting array bounds, using safe input functions, freeing memory exactly once, and validating file pointers, developers can write more robust and portable C programs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Memory ManagementC programmingInitializationfile-handlingcommon bugsdouble freearray boundsstring overflow
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.