c语言报错表达式必须包含指针类型,C语言中单链表的建立中的地址传递和打印以及逆置详解...

本文详细介绍了如何使用C++通过typedef定义LNode和LinkList,包括尾插法和头插法建立单链表,以及单链表的逆置操作。通过实例展示了如何处理内存分配和链表节点的插入。最后提供了完整的代码示例和运行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

插法建立单链表:

首先要定义一个单链表,其中typedef关键字是用来给数据类型重命名的。我这里命名为LNode,LinkList,其中LinkList为声明的头指针L。

注意:

在声明函数的时候,LNode与LinkList等价,不一样的是LinkList强调这是链表,LNode强调这是节点。c++

typedef struct LNode {//定义单链表节点类型

int data;//每一个节点存放一个数据元素

struct LNode* next;//指针指向下一个节点

}LNode,*LinkList;

下面是用尾插法建立一个单链表,首先要初始化一个单链表,而后每取一个数据,咱们须要把这个数据插入到表尾:(其中代码中我建立的单链表是带头节点的)

下图中,我为了方便观看每取一次数据我换了一个颜色,并进行了相应的编号区分方便你们经过看图更加全面的理解下面的代码尤为是r->next= s和r=s这两句

29f6c8d020cc8a4ce35be9bdc898cb7e.png

值得注意的是:函数

声明一个新指针而且要存数据的时候,记得考虑内存分配失败的状况,不然将会报错为"取消对null指针"xx"的引用"

LinkList List_TailInsert(LinkList *L) 这里我用到了地址传递,记得返回值要为&L,因此再后来我在main函数里调用为List_TailInsert(&L)

地址传递就至关于把某个值变成了全局变量,因此咱们须要经过地址来进行形参的定义;值传递就至关于局部变量,只改变当前函数里的形参的值,并不影响实参的值。另外:c语言里的地址传递至关于c++中的&引用调用同样。

LinkList List_TailInsert(LinkList *L) {

int x;

//*L = NULL;

*L = (LinkList)malloc(sizeof(LNode));//初始化空表

if (L==NULL) {//考虑内存分匹配失败的状况

return 0;

}

LNode *s,*r = *L;//定义两个指针使他们分别都和头指针指向相同

scanf_s("%d", &x);

while (x!=9999)

{

s = (LNode *)malloc(sizeof(LNode));//给s分配一个新的节点

if (s == NULL) {//考虑内存分匹配失败的状况

return 0;

}

s->data = x;//把x赋值给新的节点

if (r == NULL) {//考虑内存分匹配失败的状况

return 0;

}

r->next= s;//让r的下一个指针与s指针指向相同,也就是在r节点后插入s

r=s;//永远保持r只想最后一个节点

printf("--------------------");

scanf_s("%d", &x);

}

if (r == NULL) {

return 0;

}

r->next = NULL;

return *L;

}

下面就是打印单链表和主函数里的相应调用了:指针

void GetElem(LinkList L) {

LNode* p;

int j = 0;

p = L;

while (p!=NULL)

{

p = p->next;

printf("输入的值为:%d,地址为:%p\n", p->data, p);

}

}

int main() {

LinkList L;

L=List_TailInsert(&L);

GetElem(L);

}

所有代码:code

#include

#include

typedef struct LNode {

int data;

struct LNode* next;

}LNode,*LinkList;

LinkList List_TailInsert(LinkList *L) {

int x;

//*L = NULL;

*L = (LinkList)malloc(sizeof(LNode));

if (L==NULL) {

return 0;

}

LNode *s,*r = *L;

scanf_s("%d", &x);

while (x!=9999)

{

s = (LNode *)malloc(sizeof(LNode));

if (s == NULL) {

return 0;

}

s->data = x;

if (r == NULL) {

return 0;

}

r->next= s;

r=s;

printf("--------------------");

scanf_s("%d", &x);

}

if (r == NULL) {

return 0;

}

r->next = NULL;

return *L;

}

void GetElem(LinkList L) {

LNode* p;

int j = 0;

p = L;

while (p!=NULL)

{

p = p->next;

printf("输入的值为:%d,地址为:%p\n", p->data, p);

}

}

int main() {

LinkList L;

L=List_TailInsert(&L);

GetElem(L);

}

结果:

75dabd8c449bbf70e9f81f37246eae84.png

不建立头结点的尾插法建立单链表的方法:

值得注意的是,打印单链表的函数中,不能先让p指针指向p的下一个指针指向的位置,须要先打印再进行此操做blog

#include

#include

typedef struct LNode {

int data;

struct LNode* next;

}LNode, * LinkList;

LinkList List_TailInsert(LinkList* L) {

int x;

int i = 0;

*L = NULL;

//*L = (LinkList)malloc(sizeof(LNode));

//if (L == NULL) {

//return 0;

//}

LNode * s, * r = *L;

//LNode* s = *L;

scanf_s("%d", &x);

s = (LNode*)malloc(sizeof(LNode));

if (s == NULL) {

return 0;

}

s->data = x;

*L = s;//L指针指向s指针所指向的节点

r = *L;.//r指针指向L指针所指向的节点,这里指向s也是一个道理

printf("^^^^^^^^^^^^^^^");

scanf_s("%d", &x);

while (x != 9999)//里面的循环就和有头结点的循环同样了

{

s = (LNode*)malloc(sizeof(LNode));

if (s == NULL) {

return 0;

}

s->data = x;

if (r == NULL) {

return 0;

}

r->next = s;

r = s;

printf("--------------------");

scanf_s("%d", &x);

}

if (r == NULL) {

return 0;

}

r->next = NULL;

return *L;

}

//打印单链表

void GetElem(LinkList L) {

LNode* p;

int j = 0;

p = L;

while (p != NULL)

{

printf("输入的值为:%d,地址为:%p\n", p->data, p);

p = p->next;

}

}

int main() {

LinkList L;

L = List_TailInsert(&L);

GetElem(L);

}

结果:

5e8eb6ed93c0f5d3f1f21b54d87aee15.png图片

头插法创建单链表:

首先须要初始化单链表,而后每取一次数据就向表头插一个数据。

值得注意的是,这里的指针L要表示指针L的下一个指针时须要带括号,不然就会报错"表达式必须包含指向结构或联合的指针类型"内存

#include

#include

typedef struct LNode {

int data;

struct LNode* next;

}LNode, * LinkList;

LinkList List_HeadInsert(LinkList* L) {

LNode* s;

int x;

*L = (LinkList)malloc(sizeof(LNode));//建立头结点

(*L)->next = NULL;//初始为空链表

scanf_s("%d", &x);

while (x != 9999)

{

s = (LNode*)malloc(sizeof(LNode));

if (s == NULL) {

return 0;

}

s->data = x;

s->next = (*L)->next;//s指针的下一个指针指向l的下一个指针,也就是s指针的下一个指针指向null

(*L)->next = s;//l指针的下一个指针指向s指针的所指的方向

printf("--------------------");

scanf_s("%d", &x);

}

return *L;

}

void GetElem(LinkList L) {

LNode* p;

int j = 0;

p = L;

while (p!=NULL)

{

p = p->next;

printf("输入的值为:%d,地址为:%p\n", p->data, p);

}

}

int main() {

LinkList L;

L = List_HeadInsert(&L);

GetElem(L);

}

结果:

cb462e9018030b36c10b7598b4e345b4.png

由此可看,单链表的数据是逆置的,因此咱们须要考虑单链表逆置io

单链表逆置

下图是单链表逆置的图像解析,为了方便更好理解代码,这个思路有点像后插法,咱们须要声明两个指针变量。一个用来引导指针L一个用来寻找后续节点。

e8adb8c8e201a29dccd2f29f3d97affa.png

代码以下:class

LinkList Reverse(LinkList L) {

LNode * p,* r;

p = L->next;

L->next = NULL;//断链

while (p!=NULL)

{

r = p->next;

p->next = L->next;

L->next = p;

p = r;

}

return L;

}

综合上述,头插法创建单链表的所有代码为:变量

#include

#include

typedef struct LNode {

int data;

struct LNode* next;

}LNode, * LinkList;

LinkList List_HeadInsert(LinkList* L) {

LNode* s;

int x;

*L = (LinkList)malloc(sizeof(LNode));//建立头结点

(*L)->next = NULL;//初始为空链表

scanf_s("%d", &x);

while (x != 9999)

{

s = (LNode*)malloc(sizeof(LNode));

if (s == NULL) {

return 0;

}

s->data = x;

s->next = (*L)->next;//s指针的下一个指针指向l的下一个指针,也就是s指针的下一个指针指向null

(*L)->next = s;//l指针的下一个指针指向s指针的所指的方向

printf("--------------------");

scanf_s("%d", &x);

}

return *L;

}

void GetElem(LinkList L) {

LNode* p;

int j = 0;

p = L;

while (p!=NULL)

{

p = p->next;

printf("输入的值为:%d,地址为:%p\n", p->data, p);

}

}

//单链表逆置

LinkList Reverse(LinkList L) {

LNode * p,* r;

p = L->next;

L->next = NULL;//断链

while (p!=NULL)

{

r = p->next;

p->next = L->next;

L->next = p;

p = r;

}

return L;

}

int main() {

LinkList L;

L = List_HeadInsert(&L);

L = Reverse(L);

GetElem(L);

}

结果为:

7f5ed6025d93b07f98736217c85867e7.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值