1、指针、引用和取值

什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量。从指针指向的内存读取数据称作指针的取值。指针可以指向某些具体类型的变量地址,例如intlongdouble。指针也可以是void类型、NULL指针和未初始化指针。

根据出现的位置不同,操作符 * 既可以用来声明一个指针变量,也可以用作指针的取值。当用在声明一个变量时,*表示这里声明了一个指针。其它情况用到*表示指针的取值。

&是地址操作符,用来引用一个内存地址。通过在变量名字前使用&操作符,我们可以得到该变量的内存地址。

2行,我们通过*操作符声明了一个int指针。接着我们声明了一个int变量并赋值为1。然后我们用int变量的地址初始化我们的int指针。接下来对int指针取值,用变量的内存地址初始化int指针。最终,我们打印输出变量值,内容为1

6行的&val是一个引用。在val变量声明并初始化内存之后,通过在变量名之前使用地址操作符&我们可以直接引用变量的内存地址。

8行,我们再一次使用*操作符来对该指针取值,可直接获得指针指向的内存地址中的数据。由于指针声明的类型是int,所以取到的值是指针指向的内存地址存储的int值。

这里可以把指针、引用和值的关系类比为信封、邮箱地址和房子。一个指针就好像是一个信封,我们可以在上面填写邮寄地址。一个引用(地址)就像是一个邮件地址,它是实际的地址。取值就像是地址对应的房子。我们可以把信封上的地址擦掉,写上另外一个我们想要的地址,但这个行为对房子没有任何影响。

2、指针和数组

C语言的数组表示一段连续的内存空间,用来存储多个特定类型的对象。与之相反,指针用来存储单个内存地址。数组和指针不是同一种结构因此不可以互相转换。而数组变量指向了数组的第一个元素的内存地址。

一个数组变量是一个常量。即使指针变量指向同样的地址或者一个不同的数组,也不能把指针赋值给数组变量。也不可以将一个数组变量赋值给另一个数组。然而,可以把一个数组变量赋值给指针,这一点似乎让人感到费解。把数组变量赋值给指针时,实际上是把指向数组第一个元素的地址赋给指针。

 

3、指针与结构体

就像数组一样,指向结构体的指针存储了结构体第一个元素的内存地址。与数组指针一样,结构体的指针必须声明和结构体类型保持一致,或者声明为void类型。

16行声明了一个person结构体,一个变量指向了一个person结构体和指向person结构体的指针。第8行为age成员赋了一个int值。第910行我们声明了一个char指针并赋值给一个char数组并赋值给结构体name成员。第11行我们把一个person结构体引用赋值给结构体变量。

13行我们打印了结构体实例的agename。这里需要注意两个不同的符号,’.’ 和 ‘->’ 。结构体实例可以通过使用 ‘.’ 符号访问age变量。对于结构体实例的指针,我们可以通过 ‘->’ 符号访问name变量。也可以同样通过(*ptr).name来访问name变量。

 

指针就是用它来讲不同的地址代码链接在一起。

 

将每一个方块指向下一个,800则指向A1,712指向A3,以此类推,而A1A2A3等,则是放数字,等。

 

为了执行打印表PrinListL)或查找表FindLkey),只要将一个指针传递到该表的第一个元素,然后用一些Next指针穿越该表即可。
typedef struct node
{
char name[20];
struct node *link;
}stud;
这样就定义了一个单链表的结构,其中char name[20]是一个用来存储姓名的字符型数组,指针*link是一个用来存储其直接后继的指针。定义好了链表的结构之后,只要在程序运行的时候在数据域中存储适当的数据,如有后继结点,则把链域指向其直接后继,若没有,则置为NULL。下面就来看一个建立带表头(若未说明,以下所指链表均带表头)的单链表的完整程序。

删除:若删除A3,则直接将A2指向A4

插入:讲X插入A2A3之间,就将A2指向xx再指向A3,即可。

 

链表

将不同地方的东西链接在一起,在启用时可以加快速度,提高效率。

 

 

 

例子:

#include <stdio.h>  

#include <conio.h>  

#include <string.h>  

#include <stdlib.h>

#define N 3 /*N为人数*/

typedef struct node

{

   char name[20];

   struct node *link;

}stud;

stud * creat(int n) /*建立单链表的函数,形参n为人数*/

{

   stud *p,*h,*s; /* *h保存表头结点的指针,*p指向当前结点的前一个结点,*s指向当前结点*/

   int i; /*计数器*/

   if((h=(stud *)malloc(sizeof(stud)))==NULL) /*分配空间并检测*/

   {

     printf("不能分配内存空间!");

     exit(0);

   }

   h->name[0]='\0'; /*把表头结点的数据域置空*/

   h->link=NULL; /*把表头结点的链域置空*/

   p=h; /*p指向表头结点*/

   for(i=0;i<N;i++)

   {

     if((s= (stud *) malloc(sizeof(stud)))==NULL) /*分配新存储空间并检测*/

     {

        printf("不能分配内存空间!");

        exit(0);

     }

     p->link=s; /*s的地址赋给p所指向的结点的链域,这样就把ps所指向的结点连接起来了*/

     printf("请输入第%d个人的姓名",i+1);

     scanf("%s",s->name); /*在当前结点s的数据域中存储姓名*/

     s->link=NULL;

     p=s;  //要把s的数据保存到p中,要不下次循环s就又指向一个空的新地址了。

   }

   return(h);

}

int main()

{

   int number; /*保存人数的变量*/

   stud *head; /*head是保存单链表的表头结点地址的指针*/

   number=N;

   head=creat(number); /*把所新建的单链表表头地址赋给head*/

}

这样就写好了一个可以建立包含N个人姓名的单链表了。
写动态内存分配的程序应注意,请尽量对分配是否成功进行检测。