死神少女资源:有关C语言指针的问题,超难,高手进!!!

来源:百度文库 编辑:高考问答 时间:2020/04/01 13:46:29
listelement * AddItem (listelement * listpointer, int data) {

listelement * lp = listpointer;

if (listpointer != NULL) {
while (listpointer -> link != NULL)
listpointer = (listelement *) listpointer -> link;
listpointer -> link = (struct listelement *) malloc (sizeof (listelement));
listpointer = listpointer -> link;
listpointer -> link = NULL;
listpointer -> dataitem = data;
return lp;
}
else {
listpointer = (struct listelement *) malloc (sizeof (listelement));
listpointer -> link = NULL;
listpointer -> dataitem = data;
return listpointer;
}
}

此程序我不是很懂,listpointer = (listelement *) listpointer -> link;
这句是怎么回事啊,(listelement *) 是什么???

整个函数的作用是-->在以listelement * listpointer为单向链表头的单向链表中的最尾段动态申请一个listelement结构的空间来存放要求加进单向链表的int data数据.并返回该链表的头指针....

以下是对程序代码的详细解释...

listelement * AddItem (listelement * listpointer, int data) {
//listpointer指向需要执行加入数据的单向链表的指针.这个指针可以指向任一条数据结构为listelement的单向链表
//data指的是要加入单向链表的具体数据

listelement * lp = listpointer; //使lp指向即将进行链表编历的头指针,这句为关键语句!

if (listpointer != NULL) { //如果链单不止一个有效项...则...

while (listpointer -> link != NULL)
listpointer = (listelement *) listpointer -> link; //这两名加起来为一个循环体! 其作用是编历整个链表的项.并保证listpointer指向链表中的最后一项!逻辑规定链表中的最后一项的listpointer -> link为NULL 其中listpointer = (listelement *) listpointer -> link中的(listelement *)为强制数据类型转换!目的是100%确保link为指向listelement结构的指针...这句话其实在正常的逻辑下是多余的.除非link除了指向本链表的下一个数据项外,还有别的作用! 但这样的可能性很少....

listpointer -> link = (struct listelement *) malloc (sizeof (listelement)); //动态申请一个listelement结构空间,并把申请到的首地址作为listpointer -> link! 由于前面的循环体的作用,使得listpointer -> link确保为链单中的最后一项...

listpointer = listpointer -> link; //使listpointer指向最后一项的实体,以便加入指定data数据项....看,这句listpointer = (listelement *) listpointer -> link是多么的相似!?(其执行结果肯定是一样的) 从这里可以看出,在前面循环体内的(listelement *)肯定是多余的!!!
listpointer -> link = NULL; //使listpointer在逻辑上成为本链表的最尾部!

listpointer -> dataitem = data; //加入数据
return lp; //返回本链表的头指针! 这和函数的第一句是对应的,是关键语句,绝不能少的!
}
else { //如果链表为空,也就是一个数据项都没有的话,则动态申请一个,并把data数据加到里面保存,然后使刚动态生成的listpointer为链表头指针! (以下的语句作用是就如此,我不多说了)

listpointer = (struct listelement *) malloc (sizeof (listelement));
listpointer -> link = NULL;
listpointer -> dataitem = data;
return listpointer;
}
}

PS:在高级语言里,指针的强制类型转换是经常用到的技巧!但由于各编译器的不同,会造成很多意想不到的逻辑错误!!!(很多时候,你以为确实是按自己的意思转换成指定的类型了,但实际上却完全不是这么一回事! 并这个错误有时是很难很难检测到底是为什么的!!!) 指针,用好了天下无敌,用不好就是一滴老鼠屎搞臭一锅汤!!! 这样情况的应用,用汇编是最不容易出错的!

PS:举个在G++编译器里一个容易误解的指针例子...两个不同的指针定义-->char *lp=new char[255]; 和 char lp[255];
里具体语句的lp[1]的含义到底有什么样的区别!? 这个例子,相信很多人都会觉得是一样没区别的(这是在C++标准里说明的)...但实际上,如果是在G++编译器里的话.定义为char lp[255];中的lp[1]的意义就是以lp为头指针的下一个单元!在这里,是我们常规并正确的理解! 但是,如果宝义成char *lp=new char[255];的话,则在G++编译器里lp[1]无解(结果是随机乱指一通)!!!虽然编译时不会出错,但结果肯定是错误的! 解决的方法超级郁闷.只能通过lp++来一步步寻址!(而不能通过lp[n]的方式直接寻址,当然如果还有效率高的方法,但这在逻辑上很容易让人混乱,那就是先把lp[0]转成DWORD类型再加上n之后再强制转成相应的指针类型!)

listelement是一个结构,可能是:
typedef struct listelement {
listelement *link; // 指针,指向某个表单元
int data; // 数据
.... // 也许还有别的变量
} listelement; //表单元结构,含一个数据变量和一个指针变量

AddItem(..) -- 加一项用的函数,送返一个指向一个表单元的指针.

listelement * lp -- 定义一个指针变量, 用于指向某表单元, 并赋初值 listpointer.

listpointer = (listelement *) listpointer -> link
这是显式类型转换赋值语句.
赋值号右边的 listpointer 是老的指针, link是老指针自身结构里面的一个成员,这个link恰恰也是个指针,
"listpointer->link"要看成一个整体,即"老指针里的指针". 赋值语句的意思就是把"老指针里的指针"赋值到赋值号左边,存放到(放回到)listpointer里.

(listelement *) 是显式类型转换, 转换成 listpointer的类型: "指向表单元的指针"型.

如果listelement结构内容如我上面猜测那样,这里的显式类型转换可以略去,因为我假设的link也是"指向表单元的指针"型.如果link的类型定得与我的假设不同,显式类型转换就不可略去.

在我们写下这句代码的那一刻:
listpointer = (listelement *) listpointer -> link;
我们并不知道listpointer -> link的类型是什么,这个是个好习惯,因为我们知道listpointer的类型,也知道我们这步的意图是将listpointer指向自己的下一个节点,所以我们需要强制转换link指针类型为我们的listpointer类型,这样就预防万一了,但是如果类型不一致会有什么情况呢?编译器会做自动隐式转换,但是这个转换,就看编译器的脸色了(你让他当家,你当然要依着他的性子来),绝大部分情况,编译器都能正确搞定,但是当你的指针是自己定义的struct的时候,大部分情况,都是错的,由于编译器根本不能识别你的自定义类型,原因就和楼上XD的PS里面解释的一样.不过这个不是郁闷,是隐式转换的时候G++这种编译器自己的默认规则而已呵呵.(对于不能识别的情况,默认是按UINT8*)

这是强制类型转换
和:
long l=10000L;
int i;
i=(int)l;
一个道理,不过你的问题比我讲的例子多2个知识点,一个是结构体,一个是指针。

这是个链表的添加节点函数。