A pointer to a local struct becomes invalid when the block containing that struct ends. Returning or saving the pointer does not extend the struct’s lifetime, so later access has undefined behavior: it may crash, appear to work, or fail differently after other code runs. Passing a pointer is not inherently unsafe; the key is whether the pointed-to object remains alive for as long as it is used.
What makes a pointer to a local struct invalid?
Consider a function that creates a struct with automatic storage duration and returns its address:
As an Amazon Associate I earn from qualifying purchases.
struct Config {
int mode;
};
struct Config *make_config(void) {
struct Config config = { .mode = 1 };
return &config;
}
The object config exists only while execution is within its block. When make_config returns, that block ends and the object’s lifetime ends. The returned pointer still contains an address, but it no longer designates a live struct Config. CERT C Rule DCL30-C states: “The address of an object with automatic storage shall not be returned from a function.” CERT C Rule DCL30-C
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →C describes the object’s storage duration and lifetime; it does not require that every automatic object physically reside on a machine stack. The important issue is the lifetime rule, not where a particular compiler puts the bytes.
#1 Best Overall
Why it may not crash right away
Using a pointer after the target’s lifetime ends is invalid even if a test run prints the expected value. The old bytes may remain unchanged temporarily, then be reused by later calls or other activity. As a result, the behavior can vary with call sequence, optimization, and platform. A segmentation fault is one possible symptom, not a guaranteed outcome or the definition of the bug. CERT C Rule DCL30-C C storage duration reference
Do not try to fix this by guessing how long the address will remain usable or by relying on a particular stack layout. The object’s lifetime has ended; the correct fix is to choose storage whose lifetime matches how long the result is needed.
When passing a pointer is safe
A function may safely receive a pointer to a struct that its caller owns, provided the object stays alive throughout the function’s use of it:
Recommended Free Tools
struct Config {
int mode;
};
void initialize_config(struct Config *out) {
out->mode = 1;
}
int main(void) {
struct Config config;
initialize_config(&config);
/* config remains alive here */
return config.mode;
}
Here, config belongs to the caller and remains alive after initialize_config returns. The risk arises if a function stores or returns a pointer to its own local object and some code uses that pointer after the function exits. CERT’s recommended approach for persistent output is to declare the object in the scope that needs it and pass its address to the initializer. CERT C Rule DCL30-C CERT C Rule EXP35-C
Choose an ownership pattern that fits the result
Before choosing a repair, decide who owns the object, how long it must live, whether separate calls need independent results, and—if memory is allocated dynamically—who releases it.
Use caller-owned output storage
Have the caller create the struct and pass its address to a function that fills it. This is a straightforward choice when the caller needs the result to remain available in its own scope:
void make_config(struct Config *out) {
out->mode = 1;
}
int main(void) {
struct Config config;
make_config(&config);
return config.mode;
}
The caller controls the object’s lifetime, and each caller can provide a different object when independent results are needed. The function must not retain the pointer and use it after the caller’s object has ceased to exist.
Return a struct by value
If a function naturally produces one struct value, it can return that value instead of returning a pointer to a local:
struct Config make_config(void) {
struct Config config = { .mode = 1 };
return config;
}
Returning a struct value is a different operation from returning &config: the caller receives a value, not a pointer to the callee’s expired local object. Whether this interface is suitable depends on the program’s design and the struct’s use; there is no need to assume a particular machine-level implementation of the return. C return statement reference
Allocate when the object needs a dynamic lifetime
Dynamic allocation is appropriate when the object must outlive the function and its lifetime cannot conveniently be tied to a caller-owned local. Return the allocation’s pointer, document who owns it, and establish who frees it:
#include <stdlib.h>
struct Config *make_config(void) {
struct Config *config = malloc(sizeof *config);
if (config == NULL) {
return NULL;
}
config->mode = 1;
return config;
}
/* The receiving owner eventually calls free(config). */
Unlike an automatic local, allocated storage remains available until it is deallocated. The allocation must be checked for failure, and the program needs a clear ownership rule so that the object is freed exactly when it is no longer needed. C malloc reference
Free tools Windows power users keep installed
One-click scans. No signup required.
Use static storage only when sharing is intended
A static object lasts for the program’s execution, so returning its address does not create the same expired-local problem. But a function-local static is shared across calls: a later call can overwrite the value observed through an earlier returned pointer. That makes it unsuitable when callers need independent results and can complicate reentrant or concurrent use. Static storage is a design choice for intentionally shared state, not a universal lifetime fix. C storage duration reference
Best Value
How to find dangling-pointer mistakes
GCC 16.1 documents -Wdangling-pointer for diagnostics involving pointers to automatic objects used after their lifetime ends. Its documented cases include an address escaping through a pointer parameter. Enable the warning in builds where that GCC version is used, then investigate each diagnostic in context. A warning can help reveal a bug, but no warning does not prove that every pointer is valid. GCC 16.1 warning options
A separate temporary-struct lifetime edge case
Not every lifetime bug involves returning the address of a named local variable. CERT C Rule EXP35-C also discusses pointers to array members of temporary struct or union expressions: in the covered cases, using the array after the temporary’s lifetime expires is undefined behavior. This is a related lifetime issue, but it is distinct from the simpler case of returning the address of a named local struct. CERT C Rule EXP35-C
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




