标题数据结构与算法学习1:双重指针在函数调用中的认识
说来愧疚,这个在C语言学习的时候就应该弄懂得东西我到了学习数据结构与算法的双向循环链表的时候才认识到,在此处提出来,算是加深自己的印象,也为像我一样的初学者提供一点警示。本问题及代码原型来自于论坛https://fishc.com.cn/forum.php
一、问题背景
输入一个整数(可负),输出A~Z相应移位后的结果。
e.g. 3-> DEFG…ZABC
二、错误程序
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef char ElemType;
typedef int Status;
typedef struct DualNode
{
ElemType data;
struct DualNode *prior;
struct DualNode *next;
} DualNode,*DuLinkList;
Status InitList(DualNode *L)
{
DualNode *p,*q;
int i;
L = (DuLinkList)malloc(sizeof(DualNode));
if( !L )
{
return ERROR;
}
else
{
L->next = NULL;
L->prior = NULL;
p = L;
for( i=0; i<26; i++ )
{
q = (DualNode *)malloc(sizeof(DualNode));
if (!q)
{
return ERROR;
}
else
{
q->data = 'A' + i;
q->prior = p;
q->next = p->next;
p->next = q;
p = q;
}
}
p->next = L->next;
L->next->prior = p;
return OK;
}
}
void Caesar(DualNode *L, int i)
{
if( i > 0 )
{
do
{
L = L->next;
}while( --i );
}
if( i < 0 )
{
do
{
L = L->prior;
}while(++i);
}
}
int main()
{
DuLinkList L;
int i;
int n;
scanf("%d",&n);
InitList(L);
Caesar(L,n);
for( i=0; i<26; i++ )
{
L = L->next; //**********************此处为关键行*****************
printf("%c",L->data);
}
return 0;
}
三、错误分析
1、我们在子函数调用形参和实参时认识到,若要一个函数调用的参数在子函数中修改,应传入一个指针,子函数通过修改指针所指地址单元的值达到主子函数间传递参数的效果。
2、同样,我们发现在关键行处,对指向结构体DualNode的指针变量L进行了修改,而L为Caesar()函数的调用参数,因此同样的,我们无法达到想要的目的,即在子函数中修改L的值,再在主函数中使用修改后的值,而修改的方法,即为双重指针。所以说,指针起到保护的作用。
3、更进一步,为了防止这类事情的发生,我们应该在声明变量的时候尽可能地认识到我们需要的是一个双重指针,即应该尽可能的认识到我们需要对一个指针进行修改操作。在这个双向循环链表的题目环境中,我们在算法构想的时候应该敏锐的发现:我们会将指向链表结点的指针进行修改,就应该在之前的定义中定义为指向这个指针的指针,在子函数调用时调用的参数为这个双重指针,这样就可以达到修改指针的操作。
4、在理解上面的基础上,我们可以在主函数中调用&(指针)来实现不定义双重指针但实现了双重指针对其底层指针“打开读写权限”的操作。
四、修改后代码
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef char ElemType;
typedef int Status;
typedef struct DualNode
{
ElemType data;
struct DualNode *prior;
struct DualNode *next;
} DualNode,*DuLinkList;
Status InitList(DuLinkList *L)
{
DualNode *p,*q;
int i;
(*L) = (DuLinkList)malloc(sizeof(DualNode));
if( !(*L) )
{
return ERROR;
}
else
{
(*L)->next = NULL;
(*L)->prior = NULL;
p = (*L);
for( i=0; i<26; i++ )
{
q = (DualNode *)malloc(sizeof(DualNode));
if (!q)
{
return ERROR;
}
else
{
q->data = 'A' + i;
q->prior = p;
q->next = p->next;
p->next = q;
p = q;
}
}
p->next = (*L)->next;
(*L)->next->prior = p;
return OK;
}
}
void Caesar(DuLinkList *L, int i)
{
if( i > 0 )
{
do
{
(*L) = (*L)->next;
}while( --i );
}
if( i < 0 )
{
do
{
(*L) = (*L)->prior;
}while(++i);
}
}
int main()
{
DuLinkList L;
int i;
int n;
scanf("%d",&n);
InitList(&L);
Caesar(&L,n);
for( i=0; i<26; i++ )
{
L = L->next;
printf("%c",L->data);
}
return 0;
}