為什么把原代碼中的int ListDelete(pSingLink* head, int i, ElemType *x);中的二級指標改成pSingLink head,到時候在主函式里直接ListDelete(head,1,&x)這樣改后洗掉單鏈表的第一個元素就會出現亂碼,而洗掉其他位置就可以,但是ListDelete里面head改成二級指標然后主函式這樣ListDelete(&head,1,&x)就可以修改不會出現亂碼,感覺在洗掉函式中i=1的位置洗掉了頭指標也不會丟失呀,為什么后面會出現亂碼?
原代碼 #include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct SLNode
{
ElemType data;
struct SLNode *next;
}SingLink,*pSingLink;
pSingLink TailCreatList();
void DisPlay(pSingLink L);
int ListDelete(pSingLink* head, int i, ElemType *x);
int main(void)
{
int i,x;
pSingLink head=NULL;
head=TailCreatList();
DisPlay(head);
printf("請輸入洗掉位置:");
scanf("%d",&i);
if(ListDelete(&head,i,&x))
printf("洗掉成功\n");
else
printf("洗掉失敗");
printf("洗掉的元素是%d:\n ",x);
DisPlay(head);
return 0;
}
pSingLink TailCreatList()
{
pSingLink head,r;
pSingLink s;
int i,len,x;
head=NULL;
r=head;
printf("請輸入單鏈表的長度");
scanf("%d",&len);
printf("請輸入單鏈表中的元素");
for(i=0;i<len;i++)
{
scanf("%d",&x);
s=(pSingLink)malloc(sizeof(SingLink));
s->data=https://bbs.csdn.net/topics/x;
if(head==NULL)
{
head=s;
r=s;
continue;
}
r->next = s;
r=s;
}
if(r!=NULL)
r->next =NULL;
return head;
}
void DisPlay(pSingLink L)
{
while(L!=NULL)
{
printf("%d ",L->data);
L=L->next;
}
return;
}
int ListDelete(pSingLink* head, int i, ElemType *x)
{
pSingLink p,s;
int j;
j=1;
p=*head;
while(p->next!=NULL&&j<i-1)
{
p=p->next;
j++;
}
if(i==1)
{
*head=p->next;
*x=p->data;
free(p);
return 1;
}
else if(j!=i-1)
{
printf("位置出錯");
return 0;
}
else
{
s=p->next;
*x=s->data ;
p->next =s->next ;
free(s);
}
return 1;
}
uj5u.com熱心網友回復:
int ListDelete(pSingLink* head, int i, ElemType *x) //這里用二級指標,是因為函式里有*head=p->next; //這樣修改也能改變函式外的head的指向
int ListDelete(pSingLink head, int i, ElemType *x) //如果是一級指標,函式里
head=p->next; //這樣修改是不能改變函式外的head的指向
具體原因解釋過很多遍了,要想在函式內修改引數也能影響函式外,引數要用指標型別,且函式里不能用 引數=xxx 來修改(這樣是修改函式堆疊的引數的堆疊記憶體的資訊,這樣引數的記憶體就不再保存原來指標指向的地址資訊了,所以就不會影響函式外的變數),而是要用 *引數=xxx 來修改(這樣是不修改函式堆疊的引數的堆疊記憶體的資訊,而是修改它指向的記憶體地址的資訊,所以會影響函式外的變數)。
你洗掉第一個元素,要修改頭指標,要想在函式內修改也影響函式外的變數,就必須把函式外的變數的地址傳給函式,因為函式外的變數是指標型別,傳它的地址,就是二級指標,所以ListDelete(pSingLink* head, int i, ElemType *x) 要用二級指標
舉個例子,好好理解其中的差別
int a=5,b=6;
void change1(int *p) {p=&b;}
void change2(int **p) {*p=&b;}
int main() {
int *p = &a; //*p=5
printf("%p, %p\n", &a, &b); //查看a,b的地址
change1(p);
printf("%p, %d\n", p, *p); //函式內的修改不影響函式外的p,p還是指向a的地址
change2(&p); //要想在函式修改p也能影響函式外的p,就要傳p的地址,p本身是指標,p的地址就是二級指標,所以引數就是二級指標型別
printf("%p, %d\n", p, *p); //函式內的修改影響函式外的p,p指向b的地址
}
uj5u.com熱心網友回復:
補充說明,例子代碼的意思就是,p是個指標,剛開開始指向a的地址,change1是在函式內修改引數p指向b的地址,結果無效;change2是在函式內修改引數*p指向b的地址,結果有效,所以想在函式內改變也能影響p,就要把p的地址&p傳給函式,函式里用*p=xxx的方式修改。因為p本身是指標,所以它的&p就是二級指標。
uj5u.com熱心網友回復:
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct SLNode
{
ElemType data;
struct SLNode *next;
}SingLink,*pSingLink;
pSingLink TailCreatList();
void DisPlay(pSingLink L);
int ListDelete(pSingLink* head, int i, ElemType *x);
int main(void)
{
int i,x;
pSingLink head=NULL;
head=TailCreatList();
DisPlay(head);
printf("請輸入洗掉位置:");
scanf("%d",&i);
if(ListDelete(&head,i,&x)) {
printf("洗掉成功, ");
printf("洗掉的元素是:%d\n ",x);
} else {
printf("洗掉失敗\n");
}
DisPlay(head);
return 0;
}
pSingLink TailCreatList()
{
pSingLink head,r;
pSingLink s;
int i,len,x;
head = NULL;
r=head;
printf("請輸入單鏈表的長度");
scanf("%d",&len);
printf("請輸入單鏈表中的元素");
for(i=0;i<len;i++)
{
scanf("%d",&x);
s=(pSingLink)malloc(sizeof(SingLink));
s->data=https://bbs.csdn.net/topics/x;
if(head==NULL)
{
head=s;
r=s;
continue;
}
r->next = s;
r = s;
}
if(r!=NULL)
r->next = NULL;
return head;
}
void DisPlay(pSingLink L)
{
while(L!=NULL)
{
printf("%d ",L->data);
L=L->next;
}
putchar(10);
return;
}
int ListDelete(pSingLink* head, int i, ElemType *x)
{
pSingLink p,s;
int j;
if (!(*head)) //需要判斷頭結點
return 0;
j=1;
p = *head;
while(p->next!=NULL&&j<i-1)
{
p=p->next;
j++;
}
if(i==1)
{
*head=p->next;
*x=p->data;
free(p);
return 1;
}
//else if(j!=i-1)
if(j != i-1 || !p->next) //需要考慮p->next是否為NULL
{
printf("位置出錯");
return 0;
}
else
{
s = p->next;
*x=s->data ;
p->next =s->next ;
free(s);
}
return 1;
}
供參考~
不是洗掉頭結點出的錯,是i的值如果大于鏈表長度出的段錯誤;需要考慮p->next是否為NULL;
其他小問題一并修改了,比如如果洗掉失敗,x的值是一個隨機值~
uj5u.com熱心網友回復:
樓主用的好像就是二重指標~
uj5u.com熱心網友回復:
要把p的地址傳給函式,但p不就是一個地址了嗎,
uj5u.com熱心網友回復:
int a=5,b=6;
void change1(int *p) {p=&b;}
void change2(int **p) {*p=&b;}
int main() {
int *p = &a; //*p=5
printf("%p, %p\n", &a, &b); //查看a,b的地址
change1(p);
printf("%p, %d\n", p, *p); //函式內的修改不影響函式外的p,p還是指向a的地址
change2(&p); //要想在函式修改p也能影響函式外的p,就要傳p的地址,p本身是指標,p的地址就是二級指標,所以引數就是二級指標型別
printf("%p, %d\n", p, *p); //函式內的修改影響函式外的p,p指向b的地址
}
補充說明,例子代碼的意思就是,p是個指標,剛開開始指向a的地址,change1是在函式內修改引數p指向b的地址,結果無效;change2是在函式內修改引數*p指向b的地址,結果有效,所以想在函式內改變也能影響p,就要把p的地址&p傳給函式,函式里用*p=xxx的方式修改。因為p本身是指標,所以它的&p就是二級指標。
delete里面用一級指標只是洗掉i=1這個位置有亂碼,洗掉i為2的位置就可以,如果這樣里面的引數沒有改變,那為什么洗掉2這個位置結果就有效呢,
uj5u.com熱心網友回復:
int a=5,b=6;
void change1(int *p) {p=&b;}
void change2(int **p) {*p=&b;}
int main() {
int *p = &a; //*p=5
printf("%p, %p\n", &a, &b); //查看a,b的地址
change1(p);
printf("%p, %d\n", p, *p); //函式內的修改不影響函式外的p,p還是指向a的地址
change2(&p); //要想在函式修改p也能影響函式外的p,就要傳p的地址,p本身是指標,p的地址就是二級指標,所以引數就是二級指標型別
printf("%p, %d\n", p, *p); //函式內的修改影響函式外的p,p指向b的地址
}
補充說明,例子代碼的意思就是,p是個指標,剛開開始指向a的地址,change1是在函式內修改引數p指向b的地址,結果無效;change2是在函式內修改引數*p指向b的地址,結果有效,所以想在函式內改變也能影響p,就要把p的地址&p傳給函式,函式里用*p=xxx的方式修改。因為p本身是指標,所以它的&p就是二級指標。
delete里面用一級指標只是洗掉i=1這個位置有亂碼,洗掉i為2的位置就可以,如果這樣里面的引數沒有改變,那為什么洗掉2這個位置結果就有效呢,
樓主的洗掉函式傳的是一重指標還是二重指標?這個需要明確了,提問題的時候如果不確定討論起來就不好說了。
傳二重指標,洗掉頭結點沒問題。原因是二重指標*head = p->next;這句就是相當于修改了main函式里的head節點,更新了main函式里的head指標指向,因為傳的是二重指標嘛,如果傳一重指標不可以的原因是head = p->next;這里的head是形參的head并不是main函式里的head了。
uj5u.com熱心網友回復:
int a=5,b=6;
void change1(int *p) {p=&b;}
void change2(int **p) {*p=&b;}
int main() {
int *p = &a; //*p=5
printf("%p, %p\n", &a, &b); //查看a,b的地址
change1(p);
printf("%p, %d\n", p, *p); //函式內的修改不影響函式外的p,p還是指向a的地址
change2(&p); //要想在函式修改p也能影響函式外的p,就要傳p的地址,p本身是指標,p的地址就是二級指標,所以引數就是二級指標型別
printf("%p, %d\n", p, *p); //函式內的修改影響函式外的p,p指向b的地址
}
補充說明,例子代碼的意思就是,p是個指標,剛開開始指向a的地址,change1是在函式內修改引數p指向b的地址,結果無效;change2是在函式內修改引數*p指向b的地址,結果有效,所以想在函式內改變也能影響p,就要把p的地址&p傳給函式,函式里用*p=xxx的方式修改。因為p本身是指標,所以它的&p就是二級指標。
要把p的地址傳給函式,但p不就是一個地址了嗎,
uj5u.com熱心網友回復:
int a=5,b=6;
void change1(int *p) {p=&b;}
void change2(int **p) {*p=&b;}
int main() {
int *p = &a; //*p=5
printf("%p, %p\n", &a, &b); //查看a,b的地址
change1(p);
printf("%p, %d\n", p, *p); //函式內的修改不影響函式外的p,p還是指向a的地址
change2(&p); //要想在函式修改p也能影響函式外的p,就要傳p的地址,p本身是指標,p的地址就是二級指標,所以引數就是二級指標型別
printf("%p, %d\n", p, *p); //函式內的修改影響函式外的p,p指向b的地址
}
補充說明,例子代碼的意思就是,p是個指標,剛開開始指向a的地址,change1是在函式內修改引數p指向b的地址,結果無效;change2是在函式內修改引數*p指向b的地址,結果有效,所以想在函式內改變也能影響p,就要把p的地址&p傳給函式,函式里用*p=xxx的方式修改。因為p本身是指標,所以它的&p就是二級指標。
delete里面用一級指標只是洗掉i=1這個位置有亂碼,洗掉i為2的位置就可以,如果這樣里面的引數沒有改變,那為什么洗掉2這個位置結果就有效呢,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/173597.html
標籤:C語言
上一篇:c++頭檔案的一些疑問
