那么,内存中发生了什么事情呢?
当程序开始执行时,最初将调用main函数,栈中的部分内存被分配用于执行函数。
所有局部变量以及该函数的执行状态都保存在这个特定的区域,我们也将其称为函数的栈帧。
在此main函数中,我们尚未声明任何局部变量,然后我们将对函数insert进行调用。
因此,机器将设置main的执行状态为暂停,并继续执行insert的调用。
进入insert的栈,insert函数有两个局部变量,数据和变量n。
这个栈帧会更大一些,因为我们有几个局部变量。
现在我们创建另一个本地变量,它是指向节点的指针temp1,
然后我们用new运算符在堆中创建一个内存块,temp1最初是指向该储存块的起始地址。
假设此内存块位于地址150,因此temp1储存的地址是150。
当我们使用new或者malloc来请求一些堆上的内存时,
我们并不是通过获取变量名,唯一的访问方法是通过指针变量。
因此head现在指向了这里,因为它像temp1一样储存了地址150在第一个插入请求中,
此后我们将Return,insert的执行将完成,现在控制将返回到main函数。
随后我们将用不同的参数再次调用insert,把数字3插入位置2过程中,
我们将再次为特定的insert调用分配栈帧中的内存,栈帧分配对应于特定的调用。
因此每次函数执行完成的时候,所有局部变量都会从栈内存释放。
现在在此调用中,我们再次创建一个新节点,我们最初将地址保存在此临时变量temp1中,
假设我们这次在地址100处获得此node。
现在n不等于1,我们将继续创建另一个临时变量temp2。
但是我们不再创建新节点,并将地址储存在temp2中,
temp2最初等于head,所以我们储存地址150。
因此,我们最初让他指向头节点,现在我们要运行此循环,并希望继续前进到下一个节点,
直到到达第n- 1个节点,在这种情况下n=2,因此此循环一次也不会执行该语句,
第n- 1个节点是第一个节点本身。现在我们执行下面这两行,
temp1 ->next = temp2 ->next;重置后为零
temp2 ->next = temp1;建立链接
现在对insert的调用将完成,因此我们回到main函数。
这也是其他调用也会发生的方式,插入所有内容后,
main函数到达Print函数,执行print,然后再次在print函数中使用临时变量,最后结束。
//任意位置插入一个节点
#include<stdlib.h>
#include<stdio.h>
struct Node{
int data;
struct Node* next;
};
struct Node* head;
void Insert(int data,int n){
Node* temp1=new Node();
//等同于struct Node* temp1=(struct Node*)malloc(sizeof(struct Node*));
temp1->data =data;
temp1->next =NULL;
if(n==1){
temp1->next =head;
head=temp1;
//不管现在头部是什么 调整此变量以指向新的头部
return;
}
//对于其他情况,我们首先要转到第n-1个节点
Node* temp2= head;//创建一个指向节点的指针 命名为temp2
//从头开始 运行一个循环并到达第n-1个节点
for(int i=0;i<n-2;i++){
temp2=temp2->next;
}
temp1->next =temp2->next;//把新节点的链接字段设置为 n-1个节点的链接字段
temp2->next =temp1;//调整第n-1个节点指向新创建的节点
}
void Print(){
Node* temp=head;
while(temp !=NULL){
printf("%d ",temp->data );
temp=temp->next ;
}
printf("\n");
}
int main(){
head=NULL;//空链表
Insert(2,1);//list:2
Insert(3,2);//list:2,3
Insert(4,1);//list:4,2,3
Insert(5,2);//list:4,5,2,3
Print();
}