C语言基本知识点复习-3
typedef & define
typedef 是一个C语言中的关键字 用来为一个数据类型取别名 以增加代码的可读性 用typedef定义数组、指针、结构等类型会带来很大的方便 不仅使程序书写简单 也使意义明确 增强可读性。
define 是一个C语言中的指令 不紧可以为类型取别名 还可以用于常量 变量 和开关编译等
typedef和define的区别
- typedef是关键字 在编译的时候起作用 会检查数据类型
define是一个预处理指令 在预处理阶段对代码进行替换 所以宏定义不占用编译时间 - define没有作用域 而 type有自己的作用域
- 在对指针使用时有区别
比如:
先定义
#define int * INT1
typedef int * INT2
INT1 a,b;=====>int *a,b; 表示创建了一个int型指针a和一个int 型变量b
INT2 a,b; =====>int *a,*b; 表示创建了两个int指针a和b
用INT1和INT2定义的a,b结果会不一样 由此可见define仅仅是做一个文字上的简单替换 而typedef不仅替换文字 同时还兼顾了替换的类型的功能
当用typedef 为结构体取别名时
正常我们定义结构体一般都是 struct + structName {…}; 这样既没有很好的可读性 而且每次创建新的结构体变量时都要写 struct +structName + structA 就很麻烦
所以用typedef为结构体取别名就很方便 例如:
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
这样就可以直接用book来代表struct Books 这一串 既简便又增加了可读性
当然还有进阶版本 直接定义结构体+结构体指针升级套餐
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book,*bookPtr;
这个代码的意思就是为struct Books取别名为book 为struct Books *取别名为bookPtr
进程内存分布和内存管理
一般我们讲的进程内存 比如说计算机当前运行了三个进程 则对于每一个进程都会将physical memory物理内存的一部分映射成一块完整的虚拟内存 让每个进程都以为自己拥有了完整的内存空间 这样子可以极大的方便了数据和代码的组织
一个进程所映射的虚拟地址如下(virtual memory 虚拟内存)
上边的图中 大致把VM分成了六个大块 内核 、栈、堆、数据段、代码段、不可访问的空间 但其中内核和不可访问段是用户无法访问的
一般我们无法直接查看一个exe可执行文件的内容 但是在linux下可以使用" readelf 文件名 -s " 指令来查看一个可执行文件的section段信息
这里的一些 像11.13 .15等都对应着上图VM中不同的段位置
栈
栈的全称为(run-time stack)运行时栈 意味着在运行时栈的大小是变化的 一般栈中保存的是局部变量 一旦一个函数被调用 则会创建一帧新的栈用来存放该程序的局部变量和形参 当然在实现函数的嵌套调用时 还要保存当下的代码地址和相关寄存器的值 以便于保护现场和恢复现场 但是栈的空间很小 一般只有8M
如果超出了这个界限则会产生 “栈溢出” 导致程序崩溃 所以一边进程用不宜调用太深的嵌套函数 和太多的局部变量
堆
堆的全称为(run-time heap)运行时栈 所以堆也是大小变化的 主要用来存储用户自定的数据空间 一般有以下几个函数创建和释放
malloc() //创建一个连续的自定义空间
calloc(n,m)//创建n个每个m大小的自定义空间
realloc()//为已有的自定义空间更改大小
free()//释放自定义空间
!!! 创建动态内存空间后记得要用free释放
数据段
用来存放全局变量 静态变量 其中又分三段
.bss 用来存放未初始化静态数据 比如a[100] 这个数组没初始化 因为系统会对为初始化的静态数据自动初始化为0 但是如果直接存100个0在a[100]里有点浪费空间 所以在.bss这一段中就可以标记一下 说这个数组是未初始化的 就不用记100个0
.data 用来存放已初始化的静态变量
.rodata 顾名思义就是只读(read only data)用来存放常量
代码段
用来存放用户代码和系统代码
用户代码好理解
系统代码就是系统给可执行文件自动添加的一个“初始化代码”包括环境变量的准备 命令行参数的组织和传递 这部分数据在栈底 紧挨着内核的那里
一些细节点
- 栈底的那部分环境变量开始运行后就不会更改 运行过程中更改的环境变量会保存在堆中
- 栈和堆都是动态变化的 运行过程中 栈从上往下增长 堆从下往上增长(上边的图也可以看出来)
- 静态数据包括:全局变量和static修饰的局部变量
- 应尽量避免滥用静态变量 first 因为静态变量在整个程序运行期间都生存的 会占空间 second 例如全局变量属于共享资源 在多线程中容易产生竞争 需要小心的互斥以保护
文件I/O
I/O可以使用系统IO和标准IO
系统IO是操作系统访问文件的API 接口 例如Linux里面的open()close()
标准IO是C语言标准库中提供的结构 例如fopen()fclose()
当使用fopen时系统会返回文件指针int *File
open()会返回一个文件描述符 int file
一遍文件描述符会从3开始 因为0.1.2已经分别被标准输入(键盘)标准输出(显示器 )和标准出错所占据
使用文件指针或文件描述符就可以对文件进行操作了
小结
C语言基础就告一段落了 其实还有好多深入的知识点还没有复习到 比如链表结构 指针的详细 等等… 后面会继续学习计组计网 数据结构算法 和操作系统 到时候再对进阶的一些C语言知识点做进一步专门的总结归纳吧
嗜好太多 能力太小~