目录
关于指针
LinkList L和LinkList *L的区别
初始化注意点
scanf()的操作
顺序表相关操作符号的确定
关于指针
①指针和指针变量是两个不同的概念,但要注意的是,通常我们叙述时会把指针变量简称为指针。
②指针变量其实是一个变量,只不过其存放的内容为地址,如 int* p,这个p是指针类型,它的值存的是地址。
假设我们定义了一个指针变量 int *p;
1、 p:p是一个指针变量的名字,表示此指针变量指向的内存地址,如果使用%p来输出的话,它将是一个16进制数。
2、 *p:*p表示此指针指向的内存地址中存放的内容,一般是一个和指针类型一致的变量或者常量。
3、 &p:&是取地址运算符,&p就是取指针p的地址。
p和&p区别在于指针p同时也是个变量,既然是变量,编译器肯定要为其分配内存地址,无论是普通的变量还是指针变量在内存中都有一个地址 ,就像程序中定义了一个int型的变量i,编译器要为其分配一块内存空间一 样。而&p就表示编译器为指针变量p分配的内存地址,而因为p是一个指针变量,这种特殊的身份注定了它要指向另外一个内存地址,程序员按照程序的需要让它指向一个内存地址,这个它指向的内存地址就用p表示。
而且,p指向的地址中的内容就用*p表示。
LinkList L和LinkList *L的区别
在链表操作中,我们常常要使用链表变量作物函数的参数,这时,用LinkList L还是LinkList *L就很值得考虑深究了,一个用不好,函数就会出现逻辑错误,那该如何使用?
这里我们可以简单理解为:
①如果函数会改变指针L的值,而你希望函数结束调用后保存L的值,那你就要用LinkList *L,这样,向函数传递的就是指针的地址,结束调用后,自然就可以去改变指针的值;
②而如果函数只会修改指针所指向的内容,而不会更改指针的值,那么用LinkList L就行了。
因此对于上述LinkList *L作为函数的参数,那么调用函数时一般需要加&,如
void initList(LinkList* L){ // } //调用时一般需要使用以下方式 initList(&L);
而使用LinkList L时,调用时直接使用L即可,如
void PrintList(LinkList L){ // } //调用时不用加& PrintList(L);
但是笔者在后续写单链表的时候发现,
然后我在main函数中调用时,使用&L反而会出错
而使用GetElem(L, 4); 则可以正常运行
后来笔者问了相关的人,了解到是否使用&需要结合定义函数时的形参是否传入指针类型。
举例说明
一、这是单链表的相关操作
这里定义void headInsert(Node* L, int data)时候使用了指针,
调用函数时候使用headInsert(L, 1),因为初始化Node* L = initList();时L是一个指针,直接传就好
若在前加&,会出现
且运行时会出错。
二、这是线性表的相关操作
如果我在上面使用
会出现
当然这块内容可能需要多参悟 ,才能体会到底什么时候用什么。
初始化注意点
在使用结构体定义一个线性表时
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 20
typedef int ElemType;
//静态
typedef struct SqList {
ElemType data[MAXSIZE];
int length;
}SqList;
初始化时,
int initList(SqList* L) {
L->length = 0;
return 0;
}
int main() {
SqList L;
int i = initList(&L);
return 0;
}
上面的是int i = initList(&L);
void initList(SqList* L) {
L->length = 0;
}
int main() {
SqList L;
initList(&L);
return 0;
}
若使用void进行构造函数,则初始化时不能使用int i = initList(&L);报错信息如下
这就提示我们函数类型得搞清楚,避免张冠李戴。
scanf()的操作
scanf("%d",&a)中,&a表示变量a的地址,因为scanf函数需要得到的是输入数据的地址,所以需要加取地址符&。
顺序表相关操作符号的确定
在顺序表中,对于是否取等号,可以采用取特殊值,将边界值带入,
这里可以设length=5,j=5,假设插入顺序表第5个位置,i=5,此时需要将第5个位置向后移一位,因此需要带等号。
此外需要注意一下数组和位序的区别,防止出错。