user-0 提问: 不带头节点单链表删除第一个结点出错

回复:
user: user-0
content: 引用 9 楼 qybao的回复:[quote=引用 6 楼 肥牛肉^*^ 的回复：][quote=引用 2 楼 qybao的回复:][quote=引用 1 楼 qybao 的回复:]  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就是二级指针。 [/quote] delete里面用一级指针只是删除i=1这个位置有乱码，删除i为2的位置就可以，如果这样里面的参数没有改变，那为什么删除2这个位置结果就有效呢，[/quote]你没理解我说的，传二级指针是为了修改函数外的头指针，如果删除第二个位置，不需要修改函数外的头指针，所以没问题；而删除第一个位置，因为头指针被释放了，如果不修改函数外的头指针就会出问题（就像你说的问题一样，野指针的东西内容是不确定的，所以就可能出现乱码）。要修改函数外的头指针，那参数只能传函数外的头指针的地址，即&head（明白我举的例子的意思了吗？你觉得&head和head都是地址，但它们等效吗？），所以就是二级指针（head是一级指针，&head就是二级指针）[/quote] 理解了。。。

user: user-1
content: 数据结构对单链表进行数据排序 http://bbs.csdn.net/topics/392201633

user: user-2
content: 引用 6 楼 肥牛肉^*^ 的回复：[quote=引用 2 楼 qybao的回复:][quote=引用 1 楼 qybao 的回复:]  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就是二级指针。 [/quote] delete里面用一级指针只是删除i=1这个位置有乱码，删除i为2的位置就可以，如果这样里面的参数没有改变，那为什么删除2这个位置结果就有效呢，[/quote]你没理解我说的，传二级指针是为了修改函数外的头指针，如果删除第二个位置，不需要修改函数外的头指针，所以没问题；而删除第一个位置，因为头指针被释放了，如果不修改函数外的头指针就会出问题（就像你说的问题一样，野指针的东西内容是不确定的，所以就可能出现乱码）。要修改函数外的头指针，那参数只能传函数外的头指针的地址，即&head（明白我举的例子的意思了吗？你觉得&head和head都是地址，但它们等效吗？），所以就是二级指针（head是一级指针，&head就是二级指针）

user: user-2
content: 引用 5 楼 肥牛肉^*^ 的回复：[quote=引用 2 楼 qybao的回复:][quote=引用 1 楼 qybao 的回复:]  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就是二级指针。 [/quote] 要把p的地址传给函数，但p不就是一个地址了吗，[/quote]你好好理解我给你的例子，p也是个指针，但是传二级指针和一级指针是有区别的，传二级指针是传p自己的地址，传一级指针是传p指向的地址，自己的地址和指向的地址不是一回事。

user: user-3
content: 引用 6 楼 肥牛肉^*^ 的回复:[quote=引用 2 楼 qybao的回复:][quote=引用 1 楼 qybao 的回复:]  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就是二级指针。 [/quote] delete里面用一级指针只是删除i=1这个位置有乱码，删除i为2的位置就可以，如果这样里面的参数没有改变，那为什么删除2这个位置结果就有效呢，[/quote]  楼主的删除函数传的是一重指针还是二重指针？这个需要明确了，提问题的时候如果不确定讨论起来就不好说了。  传二重指针，删除头结点没问题。原因是二重指针*head = p->next;这句就是相当于修改了main函数里的head节点，更新了main函数里的head指针指向，因为传的是二重指针嘛，如果传一重指针不可以的原因是head = p->next;这里的head是形参的head并不是main函数里的head了。

user: user-0
content: 引用 2 楼 qybao的回复:[quote=引用 1 楼 qybao 的回复:]  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就是二级指针。 [/quote] delete里面用一级指针只是删除i=1这个位置有乱码，删除i为2的位置就可以，如果这样里面的参数没有改变，那为什么删除2这个位置结果就有效呢，

user: user-0
content: 引用 2 楼 qybao的回复:[quote=引用 1 楼 qybao 的回复:]  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就是二级指针。 [/quote] 要把p的地址传给函数，但p不就是一个地址了吗，

user: user-3
content: 引用 1 楼 qybao 的回复: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的地址 } 楼主用的好像就是二重指针～

user: user-3
content: #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=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的值是一个随机值～

user: user-2
content: 引用 1 楼 qybao 的回复: 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就是二级指针。

user: user-2
content: 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的地址 }