前言
在复习和实现完顺序表的定义及基本操作之后,我准备去复习单链表的基本概念,不过还是不出以外的遇到了一些基础性的问题,于是便有了这篇记录性的文章
C函数的值传递与地址传递
正如昨天的记录中提到的,在定义某个函数的时候,你需要告诉这个函数传入的变量是否需要修改,不需要修改就传形参,需要修改就传入实参。
typedef struct{
int data[9];
int dataLength;
}SList;
void printAllElem(SList list){
int i = 0;
for(i=0;i<list.dataLength;i++){
printf_s("%d\n",list.data[i]);
}
}//打印所有元素,不需要修改
bool deleteHeadElem(SList &list){
int i = 0;
for(i=1;i<list.dataLength;i++){
list.data[i-1] = list.data[i];
}
list.dataLength--;
}//删除第一个元素,需要修改
int main(){
SList list;
initList(list);
printAllElem(list);
deleteHeadElem(list);
}
可以看到上面代码中,定义了一个顺序表结构体SList
和两个功能函数。其中printAllElem
函数不需要对顺序表进行修改,于是传入了结构体(数值变量)本体;而deleteHeadElem
函数需要对顺序表进行修改,于是传入了结构体变量的地址。
从这里就可以初见端倪,在定义函数时,直接进行值传递就是在传递形参,而传递地址就是传递实参。
而在引用的时候,不难发现两个函数传入的参数长相是一样的,尤其是printAllElem
函数在引用时竟然丢了取地址符号!这是因为取地址是一种对数值的操作方式,而SList list
本身不是地址值,所以要在声明时把这个list
告诉函数之外,还要告诉函数别忘了取出它的地址才行。也正因为如此,main中调用printAllElem
函数的时候只需要传入list
就行了,就不再需要告诉函数怎么操作才能取地址了。
那么如果是对结构体指针进行操作呢?有了上面的理解很快就能改出下面的代码了。
typedef struct{
int data[9];
int dataLength;
}SList;
void printAllElem(SList list){
int i = 0;
for(i=0;i<list->dataLength;i++){
printf_s("%d\n",list->data[i]);
}
}//打印所有元素,不需要修改
bool deleteHeadElem(SList* list){
int i = 0;
for(i=1;i<list->dataLength;i++){
list->data[i-1] = list->data[i];
}
list->dataLength--;
}//删除第一个元素,需要修改
int main(){
SList list;
SList* Plist = &list;//Plist本身存的就是地址
initList(Plist);//直接传入Plist就相当于地址传递
printAllElem(*Plist);//不修改顺序表,所以要传递数值,要把Plist存的地址值里对应的数据找出来,所以传入的是*Plist
deleteHeadElem(Plist);
}
抛砖引玉
- 在顺序表中,指针是为了方便修改顺序表元素而服务的,属于额外选项。
- 在单链表中,由于单链表在内存的物理结构中是离散的,所以天生必须要依靠指针去完成基本操作。
- 在单链表中,指针除了服务与“数值”,指针本身也要被修改,这也是链表逻辑理解和实现上的难点。