First, please review the previous article that used the counter in 【C Language】 – What is a Function Callback, and How to Implement It? Have you ever thought about: How does the count value retain its previous value in the next cycle? After entering the next cycle, will the variable value still exist before the function is called again for initialization, or will it need to be reinitialized? This involves the lifecycle of variables.
1. What is Lifecycle
- 「Lifecycle of Variables」: The entire process a variable goes through from declaration(memory allocation) to initialization, invocation, and finally being destroyed(memory released).
2. Lifecycle of Different Types of Variables
- 「Lifecycle of Variables」: The entire process a variable goes through from declaration(memory allocation) to initialization, invocation, and finally being destroyed(memory released).
From the table, it can be seen that the lifecycle spans the entire duration of the program’s execution, and the two main types of variables that can retain values are: static variables and global variables.
| Variable Type | Keyword | Declaration Location | Lifecycle | Characteristics |
|---|---|---|---|---|
| Automatic Local Variable | auto (usually omitted) | Inside a function or block {} | From the start of the function/code block until exit | Recreated and initialized each time, value not retained |
| Static Local Variable | static | Inside a function | 🌟 Permanent – From program start to program end | Initialized only once, value retained |
| Global Variable | None | Outside all functions | 🌟 Permanent – From program start to program end | Hasexternal linkage, accessible by other files via extern |
| Static Global Variable | static | Outside all functions | 🌟 Permanent – From program start to program end | Hasinternal linkage, accessible only within this file |
| Dynamic Memory Allocation | malloc(), calloc(), realloc() | / | Frommalloc to free | Programmer has complete control |
Next, let’s illustrate the lifecycle of different variables with specific code examples.2.1「Automatic Local Variable」
#include <stdio.h>void Func() { int local_var = 10; // Automatic local variable, lifecycle starts local_var++; return local_var; // Function ends, local_var lifecycle ends, memory is reclaimed}int main() { Func(); // Output: 11 Func(); // Output: 11 (each call reinitializes to 10, then becomes 11) // Code block example { int block_var = 20; // Lifecycle starts printf("block_var = %d\n", block_var); // Output: block_var = 20 } // block_var lifecycle ends // printf("%d", block_var); // Error! block_var no longer exists return 0;}
2.2「Static Local Variable」
#include <stdio.h>void counter() { static int count = 0; // Static local variable, initialized only once count++; return count;}int main() { counter(); // Output: 1 counter(); // Output: 2 (value retained) counter(); // Output: 3 return 0;}
2.3「Global Variable (External Variable)」
#include <stdio.h>int global_var = 60; // Global variable, lifecycle starts (entire program)void func() { global_var++; return global_var;}int main() { printf("global_var: %d\n", global_var); // Output: 60, initial value func(); // Output: 61 printf("Global after func: %d\n", global_var); // Output: 61 (value modified and retained) func(); // Output: 62 return 0;} // Program ends, global_var lifecycle ends
2.4「Static Global Variable」Consider: What will be the output after executing the following code?
#include <stdio.h>// Explicitly initialized static global variablestatic int age_boy = 100;// Uninitialized static global variable (automatically initialized to 0)static int age_girl;// Static constantstatic const int MAX_AGE = 99;void check_ages() { printf("boy: %d\n", age_boy); printf("girl: %d\n", age_girl); printf("age: %d\n", MAX_AGE); // Modify non-const static global variable age_girl++; age_boy++; // MAX_SIZE = 99; // Error! const variable cannot be modified}int main() { check_ages(); check_ages(); check_ages(); return 0;}
2.5「Dynamically Allocated Variable」★★★ Key Points: 1 If dynamic memory is allocated but not freed, it will lead to memory leaks. 2 If accessed after being freed, it will lead to dangling pointer errors, and the solution is: Immediately set the pointer to NULL after freeing.
#include <stdio.h>#include <stdlib.h>int main() { // ptr is an automatic local variable, lifecycle within main function int *ptr = (int*)malloc(sizeof(int)); // Lifecycle of dynamic memory starts if (ptr == NULL) { // Handle allocation failure return 1; } *ptr = 100; free(ptr); // Lifecycle of dynamic memory ends! // ptr is now a dangling pointer, should not be used ptr = NULL; // Good practice: avoid dangling pointers!!! return 0;} // Automatic variable ptr's lifecycle ends
3. Lifecycle of Derived Data Types The members of derived data types (structures, unions, arrays) do not have independent lifecycles, their lifecycles are entirely determined by the storage class of their parent object. The lifecycle of derived data type members = the lifecycle of the parent objectLet’s illustrate the lifecycle of structure member variables with an example: 3.1「Automatic Local Structure」
- Declared inside a function, without using any storage class keywords, cannot retain values
//1 Count value cannot be retained, counting function cannot be implemented#include <stdio.h>typedef struct Struct_Counter { int count; int trigger;}STRUCT_COUNTER;// Automatic local structure counterint Incease_Counter(void) { // Automatic local structure - recreated and initialized each time STRUCT_COUNTER counter = {0, 80}; if (counter.count < my_counter.trigger) { counter.count++; } return counter.count; // No matter how many times called, count value remains 1 // counter is automatically destroyed at the end of the function}int main() { Incease_Counter(); }
3.2「Static Local Structure」
-
Declared inside a function, using the static keyword, retains values
#include <stdio.h>typedef struct Struct_Counter { int count; int trigger;}STRUCT_COUNTER;int Incease_Counter(void) { // Static local structure variable - lifecycle from program start to end static STRUCT_COUNTER counter = {0, 80}; if (counter.count < counter.trigger) { counter.count++; } return counter.count; // Value retained between function calls!}int main() { Incease_Counter(); // Final output: 80, counting stops }// counter is destroyed at the end of the program
3.3「Global Structure」
-
Declared outside all functions, retains values
#include <stdio.h>typedef struct Struct_Counter { int count; int trigger;}STRUCT_COUNTER;// Global structure, count lifecycle: program start → program endSTRUCT_COUNTER counter = {0, 80};// Global static structure (visible within this file), count lifecycle: program start → program end//static STRUCT_COUNTER counter = {0, 80};int Incease_Counter(void) { if (counter.count < counter.trigger) { counter.count++; } return counter.count; // Value retained between function calls!}int main() { Incease_Counter(); // Final output: 80, counting stops }// counter is destroyed at the end of the program
「Summary」
- The two main types of variables that can retain values are: static variables and global variables.
- The lifecycle of derived data type (structures, unions, arrays) members = the lifecycle of the parent object.
- Static variables and global variables are initialized only once during the entire program execution (first initialization, subsequent calls skip the initialization statement).
“ Your support is my greatest motivation ”
Every like you give, I take seriously as a sign of appreciation