一、内存的分区
1、内存分为:物理内存和虚拟内存。
- 物理内存︰实实在在存储设备。
- 虚拟内存:操作系统虚拟出来的内存。
操作系统会在物理内存和虚拟内存之间做映射;在32位系统下,咱们看到的都是虚拟地址。
2、在32位操作系统中,虚拟内存被分为两个部分,3G的用户空间和1G内核空间,其中用户空间是当前进程所私有的,内核空间,是一个系统中所有的进程所公有的。
二、虚拟内存分区
1、堆区:在动态内存申请的时候,在堆里开辟内存。
2、栈区:主要存放局部变量。
3、静态全局区:1:未初始化的静态全局区
静态变量(定义变量的时候,前面加static修饰),或全局变量﹐没有初始化的,存在此区2:初始化的静态全局区全局变量、静态变量,赋过初值的,存放在此区。
4、代码区:存放程序代码。
5、文字常量区:存放常量的。
三、变量作用域与静态变量
1、普通全局变量: 在函数外(main函数和子函数)定义的变量。
int num= 5;
void main()
{
}
(1)作用范围:程序的所有地方,在其他文件使用之前需要声明:extern int num;,在当前c文件的函数中可以直接修改它的值。
(2)注意:声明的时候不要给全局变量赋值;定义时默认值为0。
(3)生命周期:程序运行的整个过程中,一直存在,直到程序结束。
2、静态全局变量: 在定义全局变量的时候,加一个static进行修饰,则static int num= 5;
是一个静态全局变量。
(1)作用范围:静态全局变量被限定了作用范围,只能在其定义的c文件中进行调用,不能被 其他c文件引用。
(2)生命周期:与普通全局变量相同,存在于程序运行整个过程中。
3、普通局部变量: 在函数内(main或其他自定义函数)定义的,或者在复合语句中定义的变量。
void func()
{
int num= 3;
}
(1)作用范围:在函数中定义的,只在函数内有效。在复合语句内定义的,只在复合语句内有效。
(2)生命周期:随函数开始和结束,在函数调用之前,局部变量不占用空间;调用时,临时开辟一块空间;调用结束后,开辟的空间被释放。
4、静态局部变量: 定义局部变量的时候,前面加static修饰。
(1)作用范围:在它定义的函数或复合语句中有效。
(2)生命周期::第一次调用函数的时候,开辟空间赋值,函数结束后,不释放,以后再调用函数的时候,就不再为其开辟空间,也不赋初值,用的是以前的那个变量。
(3)注意:
-
普通局部变量不进行初始化,默认值是随机值;静态局部变量不进行初始化,默认值是0。
-
静态局部变量只会初始化一次,直到在函数内修改它的值,它都不会变。
四、外部函数与内部函数
1、外部函数:定义的普通函数,都是外部函数。
函数可以在程序的任何一个文件中调用。只需要将函数的实现过程写在指定的.c文件中,然后将其声明写在指定的.h文件中,其他文件只要包含了头文件,就可以使用外部函数。
2、内部函数:也叫静态函数,在定义函数返回值的时候(也就是定义的函数前),前面加上static。它被限制了作用范围,只能在定义的c文件中引用。
3、内部函数和外部函数的区别:
外部函数,在所有地方都可以调用;
内部函数,只能在所定义的.c中的函数调用。
4、注意:在同一作用范围内,不允许变量重名。作用范围不同的可以重名。
局部范围内,重名的全局变量不起作用。(就近原则)
例如:
int i= 520;
void main()
{
int i= 1314;
printf("%d",i);
}
此处就应该取最近的那个赋值,即1314,而不是远的那个520。
五、include与define选择性编译
1、C语言的编译过程:预处理——>编译——>汇编——>链接
(1)预编译
将.c中的头文件展开、宏展开生成的文件是.i文件
(2)编译
将预处理之后的.i文件生成.s 汇编文件
(3)汇编
将.s汇编文件生成.o目标文件
(4)链接
将.o 文件链接成目标文件
#includec<>:用尖括号包含头文件,在系统指定的路径下找头文件
#include"":用双引号包含头文件,先在当前目录下找头文件,找不到,再到系统指定的路径下找。
2、注意:
-
include常常是包含.h文件,不过也可以包含.c文件。但是最好不要包含.c,因为include包含的文件会在预编译被展开,如果一个c被包含多次,展开多次,会导致函数重复定义。
-
预处理只会对include包含的文件进行处理,并不会进行语法检查,在第二个阶段即编译阶段才进行语法检查。
3、选择性编译
注意:选择性编译都是在预编译阶段干的事情。
(1)#ifdef
#ifdef BB
代码段1
#else
代码段2
#endif
如果在当前c文件定义过BB,则编译代码段1,否则编译代码段2。
与if else选择语句的区别:if else中的所有语句都会被编译,通过条件选择来执行代码,而选择性编译只有一块代码会被编译。
测试代码:
#include <stdio.h>
#define BB
int main()
{
#ifdef BB
printf("存在宏定义BB");
#else
printf("不存在BB");
#endif
return 0;
}
(2)#ifndef
此外,还有个ifndef BB的用法,如果没有定义过BB的话则执行,与ifdef BB相反的用法。一般用于多文件编译。
(3)#if
另外还有:
#if 表达式
代码段1
#else
代码段2
#endif
return 0;
如果表达式为真,则编译第一段代码,否则编译第二段代码。一般用于注释多行代码,使用#if 0
#include <stdio.h>
int mian()
{
int a=1, b=3;
#if a>b
printf("这里可以放注释语句");
#else
printf("这这这");
#endif
return 0;
}