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

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

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

#include<stdio.h>

int main()

{

int *ptr; // 声明一个int指针

int val = 1; // 声明一个int值

ptr = &val; // 为指针分配一个int值的引用

int deref = *ptr; // 对指针进行取值,打印存储在指针地址中的内容

printf("deref地址=%ld,值=%d\n",ptr, deref);

}

白话一点来讲就是把一个变量只想另一个变量使两个变量的值和第一个变量的值相等。

而何为链表以下会有解释:

链表由一系列不必在内存中相连的结构组成。每一个结构均含有表元素和指向包含该元素后继元的结构指针。我们称之为next指针。最后一个单元的next指针指向NULL;该值由C定义并且不能与其它指针混淆。ANSI C规定NULL为零。
指针变量是包含存储另外某个数据的地址的变量。因此,如果P被声明为指向一个结构的指针,那么存储在P中的值就被解释为内存中的一个位置,在该位置能够找到一个结构。该结构的一个域可以通过P->FileName访问,其中FileName是我们要考察的域的名字。如图1所示,这个表含有五个结构,恰好在内存中分配给它们的位置分别是1000,800,712,992和692。第一个结构的指针含有值800,它提供了第二个结构所在的位置。其余每个结构也都有一个指针用于类似的目的。当然,为了访问该表,我们需要知道在哪里能够找到第一个单元。

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


下面就来看一个建立带表头(若未说明,以下所指链表均带表头)的单链表的完整程序。

#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所指向的结点的链域,这样就把p和s所指向的结点连接起来了*/

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*/

}

这只是最简单的链表以及指针的运用 还有一些复杂一些的无法简单的进行说明。

本人学识有限这就是我对链表及指针的基本理解。

另附上运用以上知识的C语言源代码

#include <stdio.h>

#include <conio.h>

#include <string.h>

#include <stdlib.h>

#define N 3

typedef struct node

{

char name[20];

struct node *link;

}stud;

stud * creat(int n) /*建立单链表的函数*/

{

stud *p,*h,*s;

int i;

if((h=(stud *)malloc(sizeof(stud)))==NULL)

{

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

exit(0);

}

h->name[0]='\0';

h->link=NULL;

p=h;

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

{

if((s= (stud *) malloc(sizeof(stud)))==NULL)

{

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

exit(0);

}

p->link=s;

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

scanf("%s",s->name);

s->link=NULL;

p=s;

}

return(h);

}

stud * search(stud *h,char *x) /*查找函数*/

{

stud *p;

char *y;

p=h->link;

while(p!=NULL)

{

y=p->name;

if(strcmp(y,x)==0)

return(p);

else p=p->link;

}

if(p==NULL)

printf("没有查找到该数据!");

}

stud * search3(stud *h,char *x)

/*另一个查找函数,返回的是上一个查找函数的直接前驱结点的指针,

h为表头指针,x为指向要查找的姓名的指针

其实此函数的算法与上面的查找算法是一样的,只是多了一个指针s,并且s总是指向指针p所指向的结点的直接前驱,

结果返回s即是要查找的结点的前一个结点*/

{

stud *p,*s;

char *y;

p=h->link;

s=h;

while(p!=NULL)

{

y=p->name;

if(strcmp(y,x)==0)

return(s);

else

{

p=p->link;

s=s->link;

}

}

if(p==NULL)

printf("没有查找到该数据!");

}

void insert(stud *p) /*插入函数,在指针p后插入*/

{

char stuname[20];

stud *s; /*指针s是保存新结点地址的*/

if((s= (stud *) malloc(sizeof(stud)))==NULL)

{

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

exit(0);

}

printf("请输入你要插入的人的姓名:");

scanf("%s",stuname);

strcpy(s->name,stuname); /*把指针stuname所指向的数组元素拷贝给新结点的数据域*/

s->link=p->link; /*把新结点的链域指向原来p结点的后继结点*/

p->link=s; /*p结点的链域指向新结点*/

}

void del(stud *x,stud *y) /*删除函数,其中y为要删除的结点的指针,x为要删除的结点的前一个结点的指针*/

{

stud *s;

s=y;

x->link=y->link;

free(s);

}

void print(stud *h)

{

stud *p;

p=h->link;

printf("数据信息为:\n");

while(p!=NULL)

{

printf("%s \n",&*(p->name));

p=p->link;

}

}

void quit()

{

exit(0);

}

void menu(void)

{

system("cls");

printf("\t\t\t单链表C语言实现实例\n");

printf("\t\t|----------------|\n");

printf("\t\t| |\n");

printf("\t\t| [1] 建 立 新 表 |\n");

printf("\t\t| [2] 查 找 数 据 |\n");

printf("\t\t| [3] 插 入 数 据 |\n");

printf("\t\t| [4] 删 除 数 据 |\n");

printf("\t\t| [5] 打 印 数 据 |\n");

printf("\t\t| [6] 退 出 |\n");

printf("\t\t| |\n");

printf("\t\t| 如未建立新表,请先建立! |\n");

printf("\t\t| |\n");

printf("\t\t|----------------|\n");

printf("\t\t 请输入你的选项(1-6):");

}

main()

{

int choose;

stud *head,*searchpoint,*forepoint;

char fullname[20];

while(1)

{

menu();

scanf("%d",&choose);

switch(choose)

{

case 1:

head=creat(N);

break;

case 2:

printf("输入你所要查找的人的姓名:");

scanf("%s",fullname);

searchpoint=search(head,fullname);

printf("你所查找的人的姓名为:%s",*&searchpoint->name);

printf("\n按回车键回到主菜单。");

getchar();getchar();

break;

case 3: printf("输入你要在哪个人后面插入:");

scanf("%s",fullname);

searchpoint=search(head,fullname);

printf("你所查找的人的姓名为:%s",*&searchpoint->name);

insert(searchpoint);

print(head);

printf("\n按回车键回到主菜单。");

getchar();getchar();

break;

case 4:

print(head);

printf("\n输入你所要删除的人的姓名:");

scanf("%s",fullname);

searchpoint=search(head,fullname);

forepoint=search3(head,fullname);

del(forepoint,searchpoint);

break;

case 5:

print(head);

printf("\n按回车键回到主菜单。");

getchar();getchar();

break;

case 6:quit();

break;

default:

printf("你输入了非法字符!按回车键回到主菜单。");

system("cls");

menu();

getchar();

}

}

}

第四部分、完整的学生信息管理系统

/*

*学生信息管理程序,

*管理学生的个人信息及各科成绩;

*/

#include <stdio.h>

#include <conio.h>

#include <string.h>

#include <stdlib.h>

typedef struct Node Node;

//定义成绩信息节点

//分别为语文、数学、英语和总成绩;

struct Score

{

int chinese,math,english,sum;

};

//定义学生信息节点

//分别为姓名、班级、学号、成绩和指向下一个节点的指针

//定义了4个全局变量,头节点,和临时节点变量;

struct Node

{

char name[20],classs[20],number[20];

struct Score score;

struct Node* next;

}*head,*u,*p,*q;

//定义多个学生的学生个数及各科平均成绩优秀率及格率;

int n,C,M,E,Cj,Cy,Mj,My,Ej,Ey;

char num[20];

//进入菜单函数

void Welcome()

{

printf("\t\t # # # # # # # # # # # # # # # # #\n");

printf("\t\t # 欢迎您使用学生成绩管理系统 #\n");

printf("\t\t # #\n");

printf("\t\t # 1.读取文件 #\n");

printf("\t\t # #\n");

printf("\t\t # 2.保存文件 #\n");

printf("\t\t # #\n");

printf("\t\t # 3.添加学生成绩 #\n");

printf("\t\t # #\n");

printf("\t\t # 4.修改学生成绩 #\n");

printf("\t\t # #\n");

printf("\t\t # 5.删除学生成绩 #\n");

printf("\t\t # #\n");

printf("\t\t # 6.查询个人成绩 #\n");

printf("\t\t # #\n");

printf("\t\t # 7.查询本班成绩 #\n");

printf("\t\t # #\n");

printf("\t\t # 8.查询全校成绩 #\n");

printf("\t\t # #\n");

printf("\t\t # 9.退出管理系统 #\n");

printf("\t\t # #\n");

printf("\t\t # # # # # # # # # # # # # # # # #\n\n");

printf("\t\t 请输入指令:(1-9) ");

}

//构造节点函数

Node* new_node(Node* uu)

{

uu = (Node*)malloc(sizeof(Node));

uu->next = NULL;

return uu;

}

//添加学生信息

void Add()

{

//新建一个节点;

u = new_node(u);

printf("\n请输入您要加入的学生的信息:\n");

printf("\n姓名: ");

scanf("%s",u->name);

printf("\n班级: ");

scanf("%s",u->classs);

printf("\n学号: ");

scanf("%s",u->number);

printf("\n语文、数学、英语成绩: ");

scanf("%d%d%d",&u->score.chinese,&u->score.math,&u->score.english);

//计算总成绩;

u->score.sum = u->score.chinese + u->score.math + u->score.english;

//采用头插法将新节点的尾指针指向第二个节点(掰开)

u->next = head->next;

//将新节点放在头节点后面;

head->next = u;

printf("\n--->添加成功!\n");

}

//根据学号修改信息

//和查找函数一样,依次从第二个节点开始遍历,如果找到这更新

void Mod()

{

n = 0;

printf("\n请输入您要修改的学号: ");

scanf("%s",num);

for(u = head; u != NULL;u = u->next)

{

if(strcmp(u->number,num) == 0)

{

n = 1;

printf("\n请输入新的语文、数学、英语成绩: ");

scanf("%d%d%d",&u->score.chinese,&u->score.math,&u->score.english);

u->score.sum = u->score.chinese + u->score.math + u->score.english;

printf("\n--->修改成功!\n");

break;

}

}

if(!n)

printf("\n--->没有这个学生的信息!\n");

}

//根据学号删除学生信息,

//从头节点开始遍历,如果找到这删除此节点;

void Del()

{

n = 0;

printf("\n请输入您要删除的学生的学号: ");

scanf("%s",num);

for(u = head; u != NULL;u = u->next)

{

if(strcmp(u->number,num) == 0)

{

n = 1;

p->next = u->next;

free(u);

printf("\n--->删除成功!\n");

break;

}

p = u;

}

if(!n)

printf("\n--->没有这个学生的信息!\n");

}

void Sort()

{

int i,j;

//记录学生总数;

n = 0;

for(u = head->next; u != NULL;u = u->next)

n++;

//采用冒泡法对各个节点按班级升序和总成绩降序排列

for(i=1;i<=n;i++)

{

u = head;

for(j=0;j<n-i;j++)

{

p = u->next;

q = p->next;

if(strcmp(p->classs,q->classs) > 0 || strcmp(p->classs,q->classs) == 0 && p->score.sum < q->score.sum)

{

u->next = q;

p->next = q->next;

q->next = p;

}

u = u->next;

}

}

}

//按学号查找某一学生成绩;

void Que_One()

{

//标志变量,记录是否查找成功;

n = 0;

printf("\n请输入您要查询的学生的学号: ");

scanf("%s",num);

//从第二个节点开始遍历,直到最后一个节点为止;

for(u = head->next; u != NULL;u = u->next)

{

//如果当前节点学号与要查找学号一致这输出此学生信息;

if(strcmp(u->number,num) == 0)

{

n = 1;

printf("\n");

puts("班级 姓名 语文 数学 英语 总成绩");

printf("%-11s%-15s",u->classs,u->name);

printf("%-6d%-6d%-6d%-6d\n",u->score.chinese,u->score.math,u->score.english,u->score.sum);

break;

}

}

if(!n)

printf("\n--->没有这个学生的信息!\n");

}

void Analyze_Sco(Node *uu)

{

//对查找到的节点进行求各科平均成绩

//求优秀率及格率;

C += uu->score.chinese;

M += uu->score.math;

E += uu->score.english;

if(uu->score.chinese >= 60)

Cj++;

if(uu->score.chinese >= 90)

Cy++;

if(uu->score.math >= 60)

Mj++;

if(uu->score.math >= 90)

My++;

if(uu->score.english >= 60)

Ej++;

if(uu->score.english >= 90)

Ey++;

}

//打印各科平均成绩及格率优秀率

void Print_Sco()

{

printf("语文平均成绩: %-6.2f, 及格率: %%%-6.2f , 优秀率: %%%-6.2f.\n\n",(float)C/n,(float)100*Cj/n,(float)100*Cy/n);

printf("数学平均成绩: %-6.2f, 及格率: %%%-6.2f , 优秀率: %%%-6.2f.\n\n",(float)M/n,(float)100*Mj/n,(float)100*My/n);

printf("英语平均成绩: %-6.2f, 及格率: %%%-6.2f , 优秀率: %%%-6.2f.\n\n",(float)E/n,(float)100*Ej/n,(float)100*Ey/n);

}

//查找某一班级所以学生的信息;

void Que_Cla()

{

//对链表节点排序;

Sort();

n = C = M = E = Cj = Cy = Mj = My = Ej = Ey = 0;

printf("\n请输入您要查询的班级: ");

scanf("%s",num);

printf("\n");

for(u = head->next; u != NULL;u = u->next)

{

//不是该班的学生则跳过;

if(strcmp(u->classs,num))

continue;

//如果是第一个学生则打印头信息

if(!n)

puts("学号 姓名 语文 数学 英语 总成绩");

n++;

printf("%-11s%-15s",u->number,u->name);

printf("%-6d%-6d%-6d%-d\n",u->score.chinese,u->score.math,u->score.english,u->score.sum);

Analyze_Sco(u);

}

if(!n)

{

printf("没有这个班级的学生信息!\n");

return ;

}

//打印该班级学生的各个成绩的特征值;

printf("\n该班共有学生 %d 人.\n\n",n);

Print_Sco();

}

//打印全校所以学生的信息

//具体情况同打印班级学生信息;

void Que_All()

{

Sort();

n = C = M = E = Cj = Cy = Mj = My = Ej = Ey = 0;

printf("\n");

if(head->next == NULL)

{

printf("--->没有学生信息!\n");

return ;

}

puts("班级 学号 姓名 语文 数学 英语 总成绩");

for(u = head->next; u != NULL;u = u->next)

{

n++;

printf("%-12s%-12s%-15s",u->classs,u->number,u->name);

printf("%-6d%-6d%-6d%-d\n",u->score.chinese,u->score.math,u->score.english,u->score.sum);

Analyze_Sco(u);

}

printf("\n全校共有学生 %d 人.\n\n",n);

Print_Sco();

}

//保存文件;

void Save()

{

char c;

printf("\n确认保存?(Y/N): ");

scanf("%*c%c",&c);

if(c == 'N')

return ;

FILE *fp;

if((fp=fopen("C:\\data.txt","w"))==NULL)

{

printf("\n--->无法打开文件\n");

return ;

}

//写入数据表头信息;

fputs("班级 学号 姓名 语文 数学 英语 总成绩",fp);

if(head->next != NULL)

fputs("\n",fp);

//从头节点开始依次写入文件;

for(u = head->next; u != NULL;u = u->next)

{

fprintf(fp,"%-11s%-11s%-15s",u->classs,u->number,u->name);

fprintf(fp,"%-6d%-6d%-6d%-d",u->score.chinese,u->score.math,u->score.english,u->score.sum);

if(u->next != NULL)

fprintf(fp,"\n");

}

fclose(fp);

printf("\n--->成绩成功存入C:\\\\data.txt中\n");

}

//读取文件;

void Open()

{

printf("\n请把数据放到目录C:\\\\data.txt中,按任意键确认.\n");

getch();

FILE *fp;

//从c盘根目录下读取文件;

if((fp=fopen("C:\\data.txt","r"))==NULL)

{

printf("\n--->没有找到文件!\n");

return ;

}

char tmp[100];

//读取65个菜单头字符存入tem字符数组中;

fgets(tmp,66,fp);

//读到文件结尾处跳出循环;

while(!feof(fp))

{

u = new_node(u);

fscanf(fp,"%s%s%s",u->classs,u->number,u->name);

fscanf(fp,"%d%d%d%d",&u->score.chinese,&u->score.math,&u->score.english,&u->score.sum);

//头插法建立链表;

u->next = head->next;

head->next = u;

}

printf("\n--->成绩读入成功!\n");

fclose(fp);

}

//退出程序

void Exi()

{

char c;

printf("\n确定退出?(Y/N): ");

scanf("%*c%c",&c);

if(c == 'N')

return ;

//打印结束语;

system("cls");

printf("\n\n");

printf("\t\t\t %c %c %c %c %c %c %c %c %c\n",4,4,4,4,4,4,4,4,4);

printf("\t\t\t %c 谢谢使用 %c\n",4,4);

printf("\t\t\t %c %c %c %c %c %c %c %c %c\n",4,4,4,4,4,4,4,4,4);

printf("\t\t\t Thank you!\n\n\n");

exit(0);

}

int main()

{

//存储指令的变量

int orz;

//设置系统文本颜色

system("color 0B");

//新建一个学生信息头节点;

head = new_node(head);

while(1)

{

//显示菜单、

Welcome();

//接收用户命令、

scanf("%d",&orz);

//调用系统函数清屏;

system("cls");

switch(orz)

{

//根据指令进入相应菜单选项

case 1:Open();break;

case 2:Save();break;

case 3:Add();break;

case 4:Mod();break;

case 5:Del();break;

case 6:Que_One();break;

case 7:Que_Cla();break;

case 8:Que_All();break;

case 9:Exi();break;

default :printf("\n--->无效的指令!\n");

}

printf("\n");

//执行系统函数

system("pause");

system("cls");

}

return 0;

}