標題數據結構與算法學習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;
}