作用域
-
全局变量与局部变量
-
局部变量
auto一般可以省略,一般需要先初始值,否则为垃圾值;作用域:创建的函数内;生命周期:从创建到函数结束。
int main() { auto unsigned int age = 10; return EXIT_SUCCESS; } -
全局变量
- 声明且定义全局变量,默认值为0。作用域:整个项目文件中;生命周期:整个程序运行期间。
unsigned int age; int main(){ return EXIT_SUCCESS; }- 只声明一个全局变量,不会分配内存空间,定义可写到外部C文件中
extern unsigned int age1; int main(){ return EXIT_SUCCESS; }
-
-
静态全局变量与静态局部变量
-
静态局部变量: 只能被初始化一次
void func0() { static int a = 1; a++; printf("a = %d\t", a); int b = 1; b++; printf("b = %d\n", b); } int main() { for (int i = 0; i < 3; ++i) { func0(); } return EXIT_SUCCESS; }
-

-
静态全局变量
只能在当前文件中使用;静态函数也一样,非静态函数的作用域为整个项目中。
static unsigned int age2;
内存布局
- 内存分区
C代码经过预处理、编对、汇编、链接四步后生成一个可执行程序。在Linux下,程序是一个普通的可执行文件,以下列出一个二进制可执行文件的基本情况。

-
内存四区模型
简单来说,C语言的内存可以分为四块。
-
代码区
该区主要存放一些程序指令
-
数据区(静态区和全局区)
- 初始化/未初始化的数据: 全局变量、静态全局变量、静态局部变量,默认值都为0
- 字符串常量
- define定义的的常量
-
栈区
在不同的操作系统中分配给每一个程序的栈区空间大小不同,Windows一般是1~8M之间,Linux是1~16M之间,所以至少有1M的空间大小。
- 局部变量
- 数组
- 结构体
- 指针
- 枚举
- 函数形参
- 常量
-
堆区
主要存放一些大的数据,如音频、视频、图像、文本文件等。
-
内存空间操作库函数
-
malloc#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { // 在堆内存中申请一片空间,大小为40个byte int *p = malloc(sizeof(int) * 10); //创建随机数种子 srand((unsigned int) time(NULL)); for (int i = 0; i < 5; ++i) { // 随机生成小于50的数 *(p + i) = rand() % 50; } for (int j = 0; j < 5; ++j) { printf("%d\n", p[j]); } // 申请的堆内存空间一定要释放 if (p) { free(p); } return EXIT_SUCCESS; }注意事项
-
申请0空间
// 其实是一个野指针 char *p = malloc(0); // 为野指针赋值会报错 *p = 100; -
多次释放空间会报错
int main() { char *p = malloc(10); *p = 100; if (p) { free(p); } free(p); return EXIT_SUCCESS; } -
置为空后再释放空间不会报错
int main() { char *p = malloc(10); *p = 100; if (p) { free(p); } p = NULL; free(p); return EXIT_SUCCESS; } -
字符串操作
int main() { char *p = malloc(10); // 不要直接这样操作,因为这是改变了p指向的地址 // 压根就没有用到malloc申请到的内存,需要用到 // 字符串的拷贝 // p = "Hello"; // 操作多大的堆内存,就需要申请多大的空间 strcpy(p, "Hello"); printf("%s\n", p); if (p) { free(p); } return EXIT_SUCCESS; }
-
-
memset通过
malloc申请到的内存空间,里面的值都是垃圾值,可以通过memset函数来进行初始化int main() { int *p = malloc(sizeof(int) * 4); // 将全部值初始化为0 memset(p, 0, 40); for (int i = 0; i < 4; ++i) { printf("%d\n", p[i]); } if (p) { free(p); } return EXIT_SUCCESS; }假如把初始化值设为1,那初始化值是为1吗?**答安不是,值为16843009。**因为初始是按照字节来处理的,
int的大小为4个字节,所以每个字节的二进制为01,组合成十六进就是0x1010101,转换成十进制就是16843009。 -
memcpyint main() { char ch[] = {'H', 'e', 'l', 'l', 'o'}; char *ch2 = "Hello"; char *str = malloc(sizeof(ch) * 6); // 将ch2拷贝到str中,4为拷贝的个数 //strcpy只拷贝字符串,memcpy拷贝一块内存 memcpy(str, ch2, 4); // 源地址与目标地址不要出现重叠,可能会出现问题 // memcpy(&ch[2],ch,4); printf("%s\n", str); if (str) { free(str); } return EXIT_SUCCESS; } -
memmoveint main() { int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 源地址与目标地址不要出现重叠,可能会出现问题 // memcpy(&arr[2], arr, 20); // 但可以使用memmove, 拷贝重叠内存地址不会出现问题, // 但效率比较低,如果内存地址没有重叠的话,与memcpy一样。 memmove(&arr[2], arr, 20); for (int i = 0; i < 10; ++i) { printf("%d\n", arr[i]); } return EXIT_SUCCESS; } -
memcmpint main() { int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int arr1[] = {1, 2, 3, 4, 5}; // 比较两块内存中前n个字节 printf(!memcmp(arr, arr1, 20) ? "相同" : "不相同"); // 相同 return EXIT_SUCCESS; }