大家好!想必C语言当中,对于计算机小白来讲,最难懂的就是指针和结构体的部分了,而老师通常只是留下了一大堆让同学们死记硬背的知识,并没有给同学真正的启发。
所以,本篇文章打算用制作顺序表的方法给大家梳理一下指针与结构体的知识点。
本篇文章纯属提供给小白。和正在学数据结构的群众。
目录
指针的作用就是为了和结构体结合使用的
首先我们先来梳理一个很重要的点,就是C语言当中,指针的作用就是为了和结构体结合使用的。但是很多老师并没有告诉你这一点,通常在大多数编程项目当中,看得到结构体就一定看得到指针。但看得到指针并不一定有结构体,你可以想象成你吃饭,结构体就是一碗饭,而指针就是一双筷子。吃饭时一定用到筷子,但用筷子的时候不一定在吃饭,也可以吃一些不可描述的东西....。
废话不多说,直接上代码:
初始化定义
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<windows.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20//链表的最大长度
typedef int Status;
typedef int ElemType;
typedef struct SqList
{
ElemType data[MAXSIZE];//链表的内容
int length;//链表的长度
} SqList;
这一段是定义了一段结构体(顺序表),因为typedef的作用是取一个别名,所以结构体在以后写代码时都可以直接使用SqList来代替struct SqList。顺序表如下图所示:
每一个格子代表的是在内存的存储空间,我们要做的就是把每一个输入的值保存在内容当中,首先使用指针把结构体定义一下:
int main()
{
SqList L;//使用指针定义结构体
return 0;
}
到此为止,在main()函数里面已经创建了一个完整的顺序表,下来只需要追加一些链表的操作即可。
1.查看列表
如何查看当前链表中每一个格子的内容是什么?大家都是聪明的小可爱,一定都知道,就是用循环的方式把L->data给printf("");出来,如果data里没有元素,那么就返回ERROR,完整代码如下:
Status ViewList(SqList *L)
{
int i;
system("cls");
if(L->length == 0)
{
printf("\n列表没有元素\n\n");
return ERROR;//如果链表长度为0,返回0
}
for(i=0;i<L->length;i++)
{
printf("序号%2d元素为:%d\n\",i,L->data[i]);
}
}
2.获取元素
通过上面的例子,相信大家都可以举一反三。如果我们想获取这个链表的元素,需要一个变量,表示需要查看顺序表的第几个元素,如果这个数超出了范围,或者小于1,那么也返回ERROR。
Status GetElem(SqList *L , int i)
{
system("cls");
if( L->length==0 || i<1 || i>L->length)
{
printf("列表没有元素或输出的长度超出范围\n");
return ERROR;
}
return L->data[i-1];//返回元素的内容
}
3.插入元素
如果我想在链表中插入一个元素呢?大家不要着急着自己想答案,先听我道来。首先,大家想象一下,假如有一行人在排队,如果有其中一个人想要插入进来,那么全部的人都得往后一格,顺序表也是一样,如果本来在这个序号就已经有一个元素了,现在我们要在这里插入一个元素,那么在这个序号的后头所有的数字都要往后退一格。一张图展示一下:
通过这一张图,我们可以很清晰的看出,想在2号的后面插入一个元素,那么从原本的3号序列到结尾,所有的元素序号都要加1,而插入的元素序号就是3。很简单吧,如果是正在学数据结构的同学,这个步骤可以尝试着自己做一下,成功与否没关系,做好了在回来看答案,给大家一个提示,我们定义的结构体当中的L->data[i]就是代表着序号,如果插入的元素插入了相应的序号,那么在此之后的所有序号的元素应该后退一格,那么后退一格的这个代码怎么写呢?仔细思考一下哦。
那么公布答案就是:
Status ListInsert(SqList *L , int i , ElemType e)
{
int t;
if(L->length == MAXSIZE)//如果顺序表的长度等于了最大值,返回ERROR。
{
printf("输出长度超出范围\n");
return ERROR;
}
if(i<=0 || i>L->length+1)//插入的位置小于1,或大于表的长度,返回ERROR。
{
printf("输出长度不在范围内\n");
return ERROR;
}
if(i<=L->length){
for(t=L->length ; t>=i-1 ; t--)
{
L->data[t+1] = L->data[t]; //将即将被插入的元素往后所有的元素位置都倒退一格.
}
}
L->data[i-1] = e;//将插入的元素放入相应的位置。
L->length ++;//表的长度+1。
return OK;
}
大家是不是都是大大心目中的小聪明呢?其实重点是for循环里面语句表示着把需要退后的元素退后,如果能够写到for循环里的内容,基本就已经掌握了这个环节的重点了。给自己鼓励一下👏👏👏👏👏👏👏👏👏👏。
4.删除元素
通过插入元素的例子,如果都理解到这的朋友,相信这一个步骤你也是很容易就掌握的,还是先给大家上一张图。
还是排队的例子,如果在排队的其中一个人走了之后,那么是不是相应的,在走了的那个人的后面,是不是就应该都向前移动一格,把之前走的人位置给顶替上。
所以我们要做的其实是把要删除的位置后面的元素,依次往前挪动一格就完成了。
代码如下:
Status ListDelet(SqList *L , int i )
{
if(i<=0 || i>=L->length+1)//如果要删除的位置小于1或大于顺序表的长度,返回ERROR。
{
return ERROR;
}
if(L->length ==0)//如果顺序表的长度为0,返回ERROR。
{
return ERROR;
}
if(i<L->length)
{
for(;i<L->length;i++)
{
L->data[i-1] = L->data[i];//依次把被删除的元素往后的所有元素向前一格。
}
}
L->length --;//顺序表的长度-1。
return OK;
}
5.指针的使用
至此为止,所有的功能代码都已经完成了,只需要在主函数里把这些功能给调用上就完了。这里需要补充的是,如果在主函数里想要创建不止一个顺序表,那么需要在写一个创建顺序表的函数就行了。但具体是咋样呢?
如果只是为了想听指针和结构体的朋友,之前的代码看不懂也没关系,这里才是你们要听的关键:
typedef int Status;
typedef int ElemType;
typedef struct SqList
{
ElemType data[MAXSIZE];
int length;
} SqList;
Status InitList(SqList *L)
{
printf("子函数里的L的地址 = %u\n",L);
L->length = 0;
return OK;
}
int main()
{
int result;
SqList *L;
printf("主函数里的L的地址 = %u\n",L);
InitList(L);//创建一个顺序表
return 0;
}
上面是一段错误的代码,也是通常小白最容易犯下的错误,当使用InitList(L);的时候,这句话的作用等同于:
int main()
{
int *A,*B;
A = B;
return 0;
}
你只是把指针B赋值给了A,而指针想要得到一个变量的值,应该是赋值其地址。正确的写法是:
int main()
{
int result;
SqList L;
printf("主函数里的L的地址 = %u\n",L);
InitList(&L);//创建一个顺序表
return 0;
}
这才是正确的赋值指针的方式,以后想要创建多个顺序表时,只需要SqList L,L1,L2...Ln;就可以了。
6.完整代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<windows.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20
typedef int Status;
typedef int ElemType;
typedef struct SqList
{
ElemType data[MAXSIZE];
int length;
} SqList;
Status InitList(SqList *L)
{
printf("%u\n",&L);
printf("%u\n",L+1);
L->length = 0;
}
Status ViewList(SqList *L)
{
int i;
system("cls");
if(L->length == 0)
{
printf("\n列表没有元素\n\n");
return ERROR;
}
for(i=1;i<L->length+1;i++)
{
if(i%2==1)
{
printf("|序号%2d元素为:%d |",i,L->data[i-1]);
}
else
{
printf(" 序号%2d元素为:%d|\n\n",i,L->data[i-1]);
}
}
}
Status GetElem(SqList *L , int i , ElemType e)
{
system("cls");
if( L->length==0 || i<1 || i>L->length)
{
printf("列表没有元素或输出的长度超出范围\n");
return ERROR;
}
e = L->data[i-1];
return e;
}
Status ListInsert(SqList *L , int i , ElemType e)
{
int t;
if(L->length == MAXSIZE)
{
printf("输出长度超出范围\n");
return ERROR;
}
if(i<=0 || i>L->length+1)
{
printf("输出长度不在范围内\n");
return ERROR;
}
if(i<=L->length){
for(t=L->length ; t>=i-1 ; t--)
{
L->data[t+1] = L->data[t];
}
}
L->data[i-1] = e;
L->length ++;
return OK;
}
Status ListDelet(SqList *L , int i )
{
if(i<=0 || i>=L->length+1)
{
return ERROR;
}
if(L->length ==0)
{
return ERROR;
}
if(i<L->length)
{
for(;i<L->length;i++)
{
L->data[i-1] = L->data[i];
}
}
L->length --;
return OK;
}
int main()
{
int n,i,result,length=0;
SqList L;
InitList(&L);
while(OK)
{
printf("1. *查看*\n");
printf("2. *查找编号*\n");
printf("3. *按顺序编辑*\n");
printf("4. *插入编号*\n");
printf("5. *删除编号*\n");
printf("6. *退出*\n");
scanf("%d",&i);
switch(i)
{
case 1:
{
ViewList(&L);
system("pause");
system("cls");
break;
}
case 2:
{
printf("请输入您要查找第几个元素第几个元素:\n");
scanf("%d",&i);
result = GetElem(&L , i , i);
printf("%d\n",result);
system("pause");
system("cls");
break;
}
case 3:
{
for(n=1+length;n<=MAXSIZE;n++)
{
printf("请输入您想插入的数字:");
scanf("%d",&i);
result = ListInsert(&L , n , i);
}
system("pause");
system("cls");
break;
}
case 4:
{
printf("请输入你想在哪个位置插入:\n");
scanf("%d",&n);
printf("请输入你想插入的元素:\n");
scanf("%d",&i);
result = ListInsert(&L , n , i);
length++;
system("pause");
system("cls");
break;
}
case 5:
{
printf("请输出您想删除的位置:\n");
scanf("%d",&n);
ListDelet(&L , n);
length--;
system("pause");
system("cls");
break;
}
case 6:system("pause");system("cls");return 0;
}
}
}
以上内容就是本篇文章想告诉大家的指针与结构体的使用,如果喜欢的陌生人,请给个点赞和关注。下期内容将介绍链式存储表的使用。你的鼓励就是创作者最大的支持,谢谢大家。
有问题的小伙伴可以留个评论