| 存储区域 | 存储内容 | 生命周期 | 特点 |
|---|---|---|---|
| 栈区 | 局部变量、函数参数 | 函数调用期间 | 自动分配和释放,速度快 |
| 堆区 | 动态分配的内存 | 手动控制 | 需要手动管理,使用malloc/free |
| 数据段 | 全局变量、静态变量 | 整个程序运行期间 | 自动初始化为0 |
| 代码段 | 程序的可执行代码 | 整个程序运行期间 | 只读 |
全局变量:在所有函数外部定义的变量,其作用域从定义位置开始到文件结尾,存储于数据段中。
#include <stdio.h>
int globalVar = 100; // 全局变量
void function() {
printf("在function中,globalVar = %d\n", globalVar);
globalVar = 200; // 修改全局变量
}
int main() {
printf("程序开始,globalVar = %d\n", globalVar);
function();
printf("调用function后,globalVar = %d\n", globalVar); // 输出200
return 0;
}
局部变量:在函数内部或代码块内声明的变量,默认具有auto存储类别。它们在函数调用时创建,在函数返回后自动销毁。
#include <stdio.h>
int x = 30; //全局变量
void function() {
int x = 10; // 局部变量,必须要先初始化
printf("函数内部 x = %d\n", x);
{
int y = 20; // 代码块内的局部变量
printf("代码块内部 y = %d\n", y);
}
// printf("y = %d\n", y); // 错误:y在这里不可见
}
int main() {
int x = 5; // main函数的局部变量
printf("main函数内 x = %d\n", x);
function();
printf("调用function后,main函数内 x = %d\n", x); // x仍然是5
return 0;
}
auto:用于声明自动变量,即局部变量。由于这是默认行为,因此通常无需显式写出。
void function() {
auto int x = 10; // 等同于 int x = 10;
// ...
}
static:
#include <stdio.h>
void counter() {
static int count = 0; // 静态局部变量
count++;
printf("函数被调用了 %d 次\n", count);
}
int main() {
counter(); // 输出:函数被调用了 1 次
counter(); // 输出:函数被调用了 2 次
counter(); // 输出:函数被调用了 3 次
return 0;
}
//仅限于定义它的源文件内,内部链接,其他源文件不能访问
// file1.c
static int staticGlobalVar = 100; // 静态全局变量
void function1() {
printf("staticGlobalVar = %d\n", staticGlobalVar);
}
// file2.c
extern int staticGlobalVar; // 错误:无法访问file1.c中的静态全局变量
void function2() {
// 无法访问staticGlobalVar
}
static用于函数:改变函数的链接属性为内部链接,使其只能在本文件中被调用,其他源文件无法访问。
// file1.c
static void privateFunction() { // 静态函数
printf("这是一个私有函数\n");
}
void publicFunction() { // 普通函数
privateFunction(); // 可以在同一文件中调用
}
// file2.c
extern void privateFunction(); // 错误:无法访问file1.c中的静态函数
void anotherFunction() {
// privateFunction(); // 错误:无法调用
}
extern:用来声明一个在其他源文件中已经定义的变量或函数。
// file1.c
int globalVar = 100; // 定义全局变量
// file2.c
extern int globalVar; // 声明外部变量
void function() {
printf("globalVar = %d\n", globalVar);
globalVar = 200; // 修改全局变量
}
extern函数的作用:
// file1.c
void utilityFunction() {
printf("这是一个实用函数\n");
}
// file2.c
extern void utilityFunction(); // 声明外部函数(可以省略extern)
void anotherFunction() {
utilityFunction(); // 调用在file1.c中定义的函数
}
register:建议编译器将变量存入CPU寄存器以加快访问速度。尽管现代编译器已具备智能优化能力,此关键字的实际影响较小,但在嵌入式开发(如单片机)中仍有应用价值。
void function() {
register int counter; // 建议将counter存储在寄存器中
for(counter = 0; counter < 1000; counter++) {
// 频繁访问counter
}
}//单片机里会遇到
const(重点):用于声明不可修改的常量。一旦初始化,其值不能被更改。
const int MAX_SIZE = 100;
// MAX_SIZE = 200; // 错误:不能修改const变量
const int* p 或 int const* p。const int *p;
int* const p。int * const p;
const int* const p。//内存和地址都不能修改
const int * const p;
const用于函数参数:表示函数不会修改传入的实际参数,常用于传递指针或引用类型,提高程序安全性和清晰度。
void printArray(const int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
// arr[i] = 0; // 错误:不能修改const数组元素
}
printf("\n");
}
const用于函数返回值:当函数返回一个对象或指针时,加上const可防止返回值被修改。
const char* getVersion() {
return "v1.0.0"; // 返回一个不应被修改的字符串
}
C99标准引入了inline关键字,旨在通过将函数体直接插入调用点来消除函数调用开销。
#include <stdio.h>
// 定义内联函数
static inline int max(int a, int b) { //根据C99标准,需要使用static inline组合
return a > b ? a : b;
}
int main() {
int x = 10, y = 20;
// 调用内联函数
int result = max(x, y);
printf("最大值是: %d\n", result);
return 0;
}
malloc - 分配内存
size_t size —— 请求的字节数;void *malloc(size_t size);
size
realloc - 调整内存大小
void* ptr —— 原内存块指针(若为NULL,等价于malloc);size_t new_size —— 新的大小(若为0且ptr非空,等价于free);void *realloc(void *ptr, size_t size);
ptr
#include <stdio.h>
#include <stdlib.h>
int main() {
// 初始分配5个整数的空间
int *numbers = (int *)malloc(5 * sizeof(int));
if (numbers == NULL) {
printf("内存分配失败\n");
return 1;
}
// 初始化数组
for (int i = 0; i < 5; i++) {
numbers[i] = i * 10;
}
// 重新分配为10个整数的空间
int *new_numbers = (int *)realloc(numbers, 10 * sizeof(int));
if (new_numbers == NULL) {
printf("内存重新分配失败\n");
free(numbers);
return 1;
}
numbers = new_numbers;
// 初始化新增的元素
for (int i = 5; i < 10; i++) {
numbers[i] = i * 10;
}
// 使用扩展后的数组
printf("重新分配后的数组: ");
for (int i = 0; i < 10; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
// 释放内存
free(numbers);
return 0;
}
free - 释放内存
void* ptr —— 待释放内存的指针(若为NULL,函数无操作);void free(void *ptr);
堆区:用于动态内存分配,由程序员通过malloc/free手动管理,内存向高地址方向扩展。
栈区:存放局部变量、函数参数及返回地址,系统自动管理,生长方向为低地址。
图示展示了C语言程序典型的内存分区结构,理解各区域特性对掌握程序运行机制至关重要。

只能释放通过 malloc、calloc 或 realloc 分配的内存空间。
释放后的内存区域将不再有效,任何后续访问行为都是非法的。
同一块内存不允许被重复释放,否则会导致“双重释放”错误,可能引发程序崩溃或安全漏洞。
void memoryLeak() {
int *p = (int *)malloc(sizeof(int));
*p = 10;
// 函数结束时没有调用free(p),导致内存泄漏
}
//解决方法:确保每次malloc、calloc或realloc都有对应的free。
int *p = (int *)malloc(sizeof(int));
*p = 10;
free(p);
*p = 20; // 错误:使用已释放的内存
//解决方法:释放内存后将指针设置为NULL。
int *p = (int *)malloc(sizeof(int));
*p = 10;
free(p);
p = NULL; // 防止使用已释放的内存
char *str = (char *)malloc(5);
strcpy(str, "Hello, World!"); // 错误:写入超过分配大小的数据
//解决方法:分配足够大的内存空间
char *str = (char *)malloc(15);
strcpy(str, "Hello, World!"); // 正确:分配了足够的空间
常见的内存操作问题包括:非法访问已释放内存、重复释放内存块,以及释放非动态分配的内存等。
扫码加好友,拉您进群



收藏
