近段复习C语言,感觉C语言相对于C++、Java等高级语言最大的特点就是:简洁紧凑、灵活方便。C语言特征不多,带有面向硬件思维,小巧而精炼。
C语言非常贴近底层,要真正理解指针的本质,还需要些微机原理、计算机组成与原理、操作系统和编译原理等背景知识。- 物理地址是外部连接使用的、唯一的,它是“与地址总线相对应”;
- 逻辑地址是内部和编程使用的、并不唯一。逻辑地址就是逻辑段管理内存而形成的。
- 在Windows中, 对于一个地址的转换要经过段式和页式, 逻辑地址先通过段式变换转换成线性地址, 再通过页式转换变换成物理地址。
- 在Linux中, 由于其段式变换其实并没有真正使用,线性地址和逻辑地址相等。
- 8086体系的CPU一开始是20根地址线,寻址寄存器是16位,16位的寄存器可以访问64K的地址空间, 如果程序要想访问大于64K的内存, 就要把内存分段,每段64K,用段地址+偏移量的方法来访问 。
- 386CPU出来之后,,采用了32条地址线,地址寄存器也扩为32位,这样就可以不用分段了,直接用一个地址寄存器来线性访问4G的内存了, 这就叫平面模式。
- 变量可以理解为分配的一块存储单元,编译后就变成了对应内存的地址,大小由这个变量类型决定。但是,int类型长度通常由CPU+OS+Compiler共同决定,这也是编写跨平台软件需要注意的地方。
- 指针也是一种变量,存放的是地址,32位程序就是占4B,不妨理解为无符号int,这个还是由CPU+OS+Compiler共同决定。
变量声明后,相当于和一块存储区的绑定,即把这块存储区暂时(变量生命周期内)叫做这个名字(变量),编译后就变成了对应内存的地址。这块存储区有其编址(编译器和操作系统)决定,对变量赋值,即往这块存储区写数据。
指针是这样一种变量,存放的是指定数据类型的首字节地址(例如32位程序可理解为4B无符号int)。通过指针可以对其指向的变量(指针存放了其指向变量的地址)进行操作。既然指针也是一种变量,那么其也有所占用的存储区,这快存储区地址也可以存放在指向其的指针中,这就是指向指针的指针。
一个典型的C程序中:
- 栈:系统自动分配自动回收,分配局部变量空间,速度较快,但无法人工控制。在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域,即栈顶的地址和栈的最大容量是系统预先规定的,是编译时就确定的常数,Windows预留栈空间是2M。如果申请的空间超过栈的剩余空间时,将提示overflow。所以,能从栈获得的空间较小。 栈空间可以通过设置来改变(具体根据相应的OS)来进行。详见:Stack的三种含义。
- 堆:是向上增长的用于分配程序员申请的内存空间,用起来方便,但易产生碎片。堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存,获得的空间比较灵活,也比较大。
C语言中结构体和指针就可以描述很多经典数据结构,下面通过一个链表的例子来总结:
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct Node {
ElemType data;
struct Node *next;
} Node;
//c语言中的定义,c语言的一些语法细节和c++区别还较大
//data属性是用来存放数据的,其他的都是载体而已,从设计的角度出发
typedef Node *LinkList; //定义LinkList,自定义链表的指针变量,指向链表的地址
//typedef struct Node *LinkList; //这句也正确,上面的typedef定义了Node
/* typedef 对已经存在的类型加一个别名
e.g. {typedef int NUM[100]; NUM n;} <=> int n[100];
*/
// 初始化一个Node,开辟地址
int initList(LinkList *L) { //这里的传递的参数是指向指针(结构体指针)的指针
//c语言不可以传递引用,c++才可以,严蔚敏数据结构传递的是c++的引用,使用&符号
//在主函数中,实参可以是:要传递的地址,一个本类型的指针变量,本质都是拷贝地址到调用函数的指针变量中
*L = (LinkList) malloc(sizeof(Node)); //*L就是指针L指向的数据
if (!(*L))
return 0; //内存不足是就会FALSE
(*L)->data = 0;
(*L)->next = NULL; // 这里的 *L 后就是取得 指向结构体 的指针
return 1;
}
//结构体指针:结构体变量.成员名;(*p).成员名;p->成员名 [p为结构体指针变量]
int creatList(LinkList *L, int n) {
LinkList p;
int i;
*L = (LinkList) malloc(sizeof(Node)); //数据存放在变量中,变量存放在地址中
(*L)->next = NULL;
for (i = 0; i < n; i++) {
p = (LinkList) malloc(sizeof(Node)); //创建一个节点
p->data = rand() % 100 + 1; //来自库 stdlib.h
p->next = (*L)->next;
(*L)->next = p;
}
printf("Creat LinkList succeed.");
return 1;
}
int visitList(LinkList L) {
printf("\nVisit LinkList: ");
L = L->next;
while (L != NULL) {
printf("%d ", L->data);
L = L->next;
}
return 1;
}
int insertList(LinkList L, ElemType e, int n) {
int i; //由于L是头,不算是第一个节点,不存放元素
LinkList node;
node = (LinkList) malloc(sizeof(Node)); //面向对象中的new,开辟在堆中
node->data = e;
for (i = 0; i < n - 1 && L != NULL; i++) { //查到 n-1号节点的后面
L = L->next; //L初始是头结点,不存放数据,查到n循环n-1次
}
if (n < 1) {
printf("\nInsert index must >0");
return 0;
}<span style="font-family: Arial, Helvetica, sans-serif;">//判断边界条件</span>
if (L == NULL) {
printf("\nInsert index is out of length");
return 0;
}
node->next = L->next;
L->next = node;
printf("\nInsert into index: %d, value is:%d", n, node->data);
return 1;
}
int main() {
LinkList L; //L是一个指针变量,指向结构体
printf("&L is %d, L is %d\n", &L, L);
printf("size of int is %d\n", sizeof(int));
printf("size of char is %d\n", sizeof(char));
printf("size of int* is %d\n", sizeof(int*));
printf("size of LinkList is %d\n", sizeof(LinkList));
printf("size of LinkList* is %d\n", sizeof(LinkList*));
ElemType e;
e = 99;
creatList(&L, 10); //创造一个链表
printf("\n&L is %d,L is %d, &(L->data) is %d", &L, L, &(L->data));
printf("\n&L is %d,L is %d, &(L->next) is %d", &L, L, &(L->next));
visitList(L); //遍历每个元素
insertList(L, e, 3); // 这里的ElemType传递了复制(也可以传递地址通过指针)
visitList(L); //遍历每个元素
return 0;
}
输出的结果:
&L is 2686696, L is 0 size of int is 4 size of char is 1 size of int* is 4 size of LinkList is 4 size of LinkList* is 4 Creat LinkList succeed. &L is 2686696,L is 7614288, &(L->data) is 7614288 &L is 2686696,L is 7614288, &(L->next) is 7614292 Visit LinkList: 65 63 59 79 25 70 1 35 68 42 Insert into index: 3, value is:99 Visit LinkList: 65 63 99 59 79 25 70 1 35 68 42