200920:391voidexchange(inta,intb){intt;t=a;a=b;b=t}Main(){inta=1,b=2;exchange(a,b);printf(“a=%d,b=%d”,a,b);}200920:392…...内存2000200120022005020032004…...…...…...1、内存地址──内存中存储单元的编号101102201202301302401402501502601602教学楼教室号码存储地址教室存储单元教室有容量存储单元有大小(字节单元、字单元)50存储数据注意:内存单元的地址与内存单元中的数据是两个完全不同的概念。200920:393“指针就是地址”!!!地址值(也就是内存单元的编址)。是什么类型的数据的地址。(这就存在着一个跨度也就是存储空间大小的问题)。200920:394明白指针就是地址,这一点十分重要。多数情况下,这个地址是指内存中一个变量的起始位置。如果一个变量包含了另一个变量的地址,那么第1个变量就是个指针变量,而且说它是“指向”第2个变量的,“指针”由此而得其名。例如,如果在地址为1000的变量指向地址为1004的变量,那么也就是说地址为1000的这个变量的值是1004。200920:395为什么要表达为“指向”呢?我们将会看到如果变量p的值是变量a的地址,则可以利用变量p来访问和操作变量a(其实这是很自然的事情,有了某变量的地址当然就可以访问该变量)。图1解释了这一点,它仅仅用来对地址进行偏移。指针的基本概念200920:39610041000100110021003121004图1一个变量指向另一个变量内存单元内存地址200920:3971、变量指针(变量的指针)一个变量x的地址就是该变量的指针,记作&x,即在变量名前加上取地址运算符“&”。2、指针变量专门用来存放地址的变量称为指针变量。当指针变量中存放着某一个变量的地址时,就称这个指针变量指向那一个变量。由于地址或指针是常量,因此当我们需要对地址进行操作的时候一般要用指针变量来保存该地址再做处理。变量的指针与指针的变量200920:398整型变量i变量i_pointer…...…...102000200420062005200120022003变量指针与指针变量变量指针:一个变量的地址指针变量:专门存放变量地址的变量2000指针变量整型变量i的内容指针变量i_pointer的内容(是地址)变量的地址指针指针变量变量变量地址(指针)变量值指向地址存入指针变量200920:399一般形式:[存储类型]数据类型符*变量名[=初始值];合法标识符表示定义指针变量不是‘*’运算符指针的目标变量的数据类型指针变量本身的存储类型注意:int*p1,*p2;与int*p1,p2;指针变量名是p1,p2,不是*p1,*p2指针变量只能指向定义时所规定类型的变量指针变量定义后,变量值不确定,应用前必须先赋值例int*p1,*p2;float*q;staticchar*name;指针变量的定义与赋值200920:3910赋值语句赋值例inta=20;int*p,*q;p=&a;q=p;整型变量a指针变量p指针变量q……...2000…...…...2020002000200920:3911零指针与空类型指针零指针:定义:指针变量值为零表示:int*p=0;p指向地址为0的单元,系统保证该单元不作它用表示指针变量值没有意义#defineNULL0int*p=NULL;p=NULL与未对p赋值不同用途:避免指针变量的非法引用在程序中常作为状态比较例int*p;......while(p!=NULL){...…}200920:3912指针变量的命名规则和其他变量的命名规则一样;指针变量不能与现有变量同名;指针变量可存放C语言中的任何基本数据类型、数组和其他所有高级数据结构的地址;若指针变量已声明为指向某种类型数据的地址,则它不能用于存储其他类型数据的地址;应为指针变量指定一个地址后,才能在语句中使用指针.指针变量的特点200920:3913想要动态地根据需要开辟和回收存储空间,通过调用动态内存分配函数可以做到这一点。因此要学习动态链表,首先就要学习能实现动态开辟存储空间功能的几个函数。动态内存分配函数200920:39141.malloc函数(1)函数原型:void*malloc(unsignedintsize);(2)作用在内存的动态存储区中分配一个长度为size的的连续空间。(3)函数返回值返回一个指向分配域起始地址的指针(类型为void*),若未能成功执行则返回空指(NULL)。8.3动态链表和动态内存分配函数200920:3915inta=2;int*b=(int*)malloc(sizeof(a*3));该程序段将会开辟以b为首地址的连续的a*3个int空间,而b就相当于数组名。200920:39162.calloc函数(1)函数原型:void*calloc(unsignedintn,unsignedintsize);(2)作用在内存的动态存储区中分配n个长度为size的的连续空间。(3)函数返回值返回一个指向分配域起始地址的指针(类型为void*),若未能成功执行则返回空指针(NULL)。8.3动态链表和动态内存分配函数200920:39173.realloc函数(1)函数原型:void*realloc(void*p,unsignedintnewsize);(2)作用给一个已经分配了地址的指针p重新分配空间,参数p为原有的空间地址,newsize是重新申请的地址长度。(3)函数返回值返回一个指向分配域起始地址的指针(类型为void*),若未能成功执行则返回空指针(NULL)。200920:39184.free函数(1)函数原型:voidfree(void*p);(2)作用释放由p指向的内存区,使这部分内存区能被其他变量所使用。(3)函数返回值无8.3动态链表和动态内存分配函数200920:3919所谓链表,是由具有指针域的结构体(在链表中把它叫作节点)构成的,节点之间通过各自的指针域连接起来(第n个节点的地址等于第n-1个节点的指针域)形成的一种链式结构,链表之名由此而得。链表200920:3920链表的图示DATApointer节点1DATApointer节点2DATApointer节点n-1图2链表DATApointer节点n…………..链表概述200920:3921观察图2可以发现,如果想在第x个节点和第x+1个节点之间插入新节点,只需要让第x个节点的指针域指向新节点而新节点的指针域指向第x+1个节点,其他的节点不需要移动。如果要删除第x个节点,只需要把第x-1个节点的指针域指向第x+1个节点,也不需要移动其他节点。这是由于链表中的数据不是顺序存放的,因此给数据的插入和删除带来了方便,进行节点的插入和删除不再总是需要大量地移动其他数据。链表概述200920:3922所谓动态链表是指能在程序执行过程中动态建立和动态变化的链表。其实动态链表如果除去动态分配内存空间的因素,就是一个静态链表。动态链表200920:3923一个动态链表(以后就简称为链表)的结点,其结构体的内容分为两部分:1.数据域:用来存储本身数据。2.链域或称为指针域:用来存储下一个结点地址或者说指向其直接后继的指针。建立动态链表200920:3924typedefstructstudent{longnum;/*学号*/charname[20];/*姓名*/intage;/*年龄*/charsex;/*性别*/floatscore;/*分数*/structstudent*next;/*用来存储它的直接后继节点的地址*/}stud;这样就定义了一个链表的节点结构体。建立动态链表200920:3925定义好了链表的节点结构之后,在程序运行的时候在数据域中存储适当的数据。如有后继结点,则把链域指向其直接后继,若没有,则置为NULL。建立动态链表200920:3926动态链表的创建过程有以下几步:1)定义链表的数据节点的结构体类型。创建一个空表。2)利用动态内存分配函数向系统申请分配一个节点。3)将新节点的指针成员赋值为空。若是空表,将新节点连接到表头;若是非空表,将新节点接到表尾。4)判断一下是否有后续节点要接入链表,若有转到3),否则结束。建立动态链表200920:3927NULLNULL图8_3建立链表的过程第一步,创建空表:第二步,申请新节点::若是空表,将新节点接到表头::若是非空表,将新节点接到表尾:第四步,申请新节点::遇到结束标志,则结束,否则转到第三步。第三步p2=p1p2-next=p1headNULLDATANULLp1,p2head,p1,p2head…...DATAADATANULLp1DATANULLhead…...DATAAp1,p2p2p1200920:3928注意:在链表的创建过程中,链表的头指针是非常重要的参数。因为对链表的输出和查找都要从链表的头开始,所以链表创建成功后,要返回一个链表头节点的地址,即头指针。建立动态链表200920:3929注意:写动态内存分配的程序时应注意,请尽量对分配是否成功进行检测。建立动态链表