In-depth Analysis and Resolution Strategies for free() Invalid Pointer Errors in C Programming

Nov 24, 2025 · Programming · 11 views · 7.8

Keywords: C Programming | Memory Management | free Error | Valgrind | strsep Function

Abstract: This article provides a comprehensive analysis of the common free() invalid pointer errors in C programming. Through practical case studies, it demonstrates the error messages detected by Valgrind and explains the fundamental differences between stack and heap memory. The paper systematically elaborates on the working principles of the strsep() function and its impact on memory management, offers corrected complete code examples, and discusses how to properly use debugging tools to locate memory issues. Finally, it summarizes best practices and common pitfalls in C language memory management to help developers fundamentally avoid such errors.

Fundamental Concepts of Memory Management

In C programming, memory management is a core concept that is prone to errors. Based on the memory organization of computer systems, we can categorize memory into two main types: stack memory and heap memory.

Stack memory is temporary storage space that is automatically allocated and released during function calls. When a program enters a function, the system allocates memory on the stack for the function's local variables; when the function completes execution and returns, this memory is automatically reclaimed. The allocation and deallocation of stack memory follow the Last-In-First-Out (LIFO) principle and are entirely managed by the compiler automatically, requiring no manual intervention from the programmer.

Heap memory, on the other hand, is manually managed storage area through explicit calls to memory allocation functions (such as malloc, calloc, realloc). The lifecycle of heap memory begins with a call to malloc and ends with a call to free, entirely controlled by the programmer. This flexibility brings greater responsibility—programmers must ensure that every memory block allocated via malloc is properly freed eventually; otherwise, memory leaks will occur.

Error Case Analysis

Consider the following query string parsing code:

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

int main() {
    char p[] = "t=quote";
    char* token;
    char* tk; 
    char* s;
    unsigned short int found;

    s = strdup(p);

    if (s != NULL) {
        while ((token = strsep(&s, "&")) != NULL) {
            found = 0;
            printf("TOKEN: %s\n\n", token);

            while ((tk = strsep(&token, "=")) != NULL) {
                printf("TK: %s\n\n", tk);
                free(tk);  // Error: Attempting to free non-heap memory
            }   

            free(token);  // Error: Double free or freeing invalid pointer
        }   
    }   

    free(s);
    return 0;
}

When running this program, Valgrind reports an "Invalid free()" error, with specific information showing:

==5411== Invalid free() / delete / delete[] / realloc()
==5411==    at 0x402AC38: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5411==    by 0x804857C: main (leak.c:28)
==5411==  Address 0x420a02a is 2 bytes inside a block of size 8 free'd

Working Principles of the strsep Function

The strsep function is an important tool in C for string splitting, with the prototype:

char *strsep(char **stringp, const char *delim);

This function searches for any delimiter in the delim string within the string pointed to by *stringp. If a delimiter is found, strsep replaces it with a null character ('\0') and returns a pointer to the first substring after splitting. Importantly, strsep modifies the original string pointer *stringp to point to the position after the delimiter.

In the example code, when calling strsep(&token, "="), the function returns a pointer to a specific position within the original string, not a newly allocated memory block. These pointers point to specific locations within the heap memory allocated via strdup or to string literals on the stack.

Root Cause Analysis of Errors

There are two main free errors in the code:

  1. Freeing Non-Heap Memory Pointers: The pointers returned by strsep point to locations within the original memory block, not newly allocated memory via malloc. Calling free on these pointers violates the basic principles of memory management.
  2. Freeing Internal Positions of Memory Blocks: The free function can only accept the exact pointer returned by malloc, calloc, or realloc. If an internal position of a memory block is passed (as shown in the example with "Address 0x420a02a is 2 bytes inside a block"), it leads to undefined behavior.
  3. Double Free Issues: In nested loops, the same memory block might be freed multiple times, which is also a serious programming error.

Corrected Solution

The correct approach is to only free pointers allocated via the malloc family of functions, and each allocated memory block should be freed exactly once. Here is the corrected code:

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

int main() {
    char p[] = "t=quote";
    char* token;
    char* tk; 
    char* s;
    char* original_s;  // Save the original pointer

    s = strdup(p);
    original_s = s;  // Save the original pointer returned by strdup

    if (s != NULL) {
        while ((token = strsep(&s, "&")) != NULL) {
            printf("TOKEN: %s\n", token);

            // Create a copy of token for internal parsing
            char* token_copy = strdup(token);
            char* token_ptr = token_copy;

            if (token_copy != NULL) {
                while ((tk = strsep(&token_ptr, "=")) != NULL) {
                    printf("TK: %s\n", tk);
                    // Note: Do not free tk here as it points inside token_copy
                }
                free(token_copy);  // Only free memory allocated via strdup
            }
        }   
    }   

    free(original_s);  // Free the original memory allocated by strdup
    return 0;
}

Usage Techniques for Debugging Tools

Valgrind is a powerful tool for detecting memory errors. When encountering a "free(): invalid pointer" error, you should:

  1. Check if all parameters to free calls are indeed pointers allocated via malloc, calloc, realloc, or strdup
  2. Ensure that free is not called on stack arrays or string literals
  3. Use Valgrind's detailed output to locate the specific error position
  4. Combine with GDB for deeper debugging, as shown in the reference article's debugging process

Best Practices for Memory Management

To avoid similar memory errors, it is recommended to follow these best practices:

  1. Clear Ownership: For each dynamically allocated memory block, clearly define which function or code segment is responsible for freeing it
  2. One-to-One Principle: Ensure that each malloc call has exactly one corresponding free call
  3. Avoid Modifying Original Pointers: When manipulating strings, prefer using copies rather than modifying original pointers
  4. Use Debugging Tools: Regularly use tools like Valgrind and AddressSanitizer during development to check for memory errors
  5. Code Review: Conduct strict peer reviews for code involving memory operations

Conclusion

C language memory management requires programmers to have rigorous thinking and meticulous operations. free() invalid pointer errors typically stem from misunderstandings about memory types and lifecycles. By understanding the fundamental differences between stack and heap memory, mastering the working principles of string handling functions, and following good programming practices, such errors can be effectively avoided. Debugging tools like Valgrind and GDB play an irreplaceable role in locating and resolving memory issues.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.