user-0 提问: 关于c语言链表指针的一些问题，希望大神帮我解答，感谢！

回复:
user: user-0
content: 引用 11 楼 qybao的回复:我觉得已经讲的挺清楚了，只是你没好好理解。 free只是设置一个flag告诉系统这块内存不再使用了，系统可以把这块内存让给其他程序使用。但是并不代表立刻有别的程序来占用这块内存，所以这块内存的信息一时半会没有被擦写，还是原来的老信息，所以可能继续访问时还能读出原来的信息。 然而一旦这块内存被系统重新份配给别的程序，别的程序就有可能重新修改了这块内存的信息，那么这块内存的信息就未必符合原来的结构体形式，比如原来老信息是一个int，一个长度为10的char数组，新的信息是一个char，一个int，这样你按原来的结构体形式来读取，结果必然出错，而且新的内存空间没有老的内存空间大，按原来的结构体形式读取还可能造成越界。打个比方，原来某个地址有一块地被你租用，你建了一栋500平米的楼房，后来你free把地退租了，地和楼房被房东收回，此时房东还没把楼拆了，你偷偷溜回来那自然还可以正常使用房子，然而如果房东把它拆了把地分割租给了别的租户，别的租户只建了50平米的平房租，这时你非要闯进人家的平房，并按原来500平米的楼房来使用，那可不就出错了吗？而且，人家平房的租客有可能把门锁了不让你进来，你进不来不就造成非法访问了吗？ 所以，同样是野指针，也分野指针指向的地址是什么情况，楼房还没拆，那就一时半会还能使用，楼房拆了被改建为平房了，那如果平房们没锁你还可以溜进去，只是房子布局不一样了，人家没2楼你非要上2楼，那就会出错，甚至如果平房锁着禁止进入，你就成了非法入侵的窃贼。 所以，你在delete函数里的野指针属于楼房没拆的情况（地址是明确的，只是房东还没来得及拆楼）；在main里的野指针属于没有乱闯入民宅并把民宅当楼房使用的情况（因为没分配过内存，地址是随机的，也就是你随机闯入任何一家民宅）。 能理解吗？ 我理解了，大神别生气，本人比较愚笨，还有一小点儿疑问，，就是 我上面 又重新定义了一个方法void 在 void方法里面定义了一个指针 freeaid 这个时候，这个指针还没有分配内存，这个野指针跟free函数里，已经指向了被释放空间的指针(被释放前不是野指针，释放后就是野指针了)的情况还不太一样。 我在void的方法里面调num参数也是能打印出值的，也没有报错。但是在main里 随便定义一个*stu类型的指针 取他的 num值就会报错(这个经过你的提点我已经知道是咋回事了)   我就是想知道。为啥 同样都是没分配空间的野指针，在主函数就会报错，在void函数里就不会报错   大神关于房子的解答真的很形象，我理解的更透彻了。感谢。。。100分都是你的

user: user-1
content: 我觉得已经讲的挺清楚了，只是你没好好理解。 free只是设置一个flag告诉系统这块内存不再使用了，系统可以把这块内存让给其他程序使用。但是并不代表立刻有别的程序来占用这块内存，所以这块内存的信息一时半会没有被擦写，还是原来的老信息，所以可能继续访问时还能读出原来的信息。 然而一旦这块内存被系统重新份配给别的程序，别的程序就有可能重新修改了这块内存的信息，那么这块内存的信息就未必符合原来的结构体形式，比如原来老信息是一个int，一个长度为10的char数组，新的信息是一个char，一个int，这样你按原来的结构体形式来读取，结果必然出错，而且新的内存空间没有老的内存空间大，按原来的结构体形式读取还可能造成越界。打个比方，原来某个地址有一块地被你租用，你建了一栋500平米的楼房，后来你free把地退租了，地和楼房被房东收回，此时房东还没把楼拆了，你偷偷溜回来那自然还可以正常使用房子，然而如果房东把它拆了把地分割租给了别的租户，别的租户只建了50平米的平房租，这时你非要闯进人家的平房，并按原来500平米的楼房来使用，那可不就出错了吗？而且，人家平房的租客有可能把门锁了不让你进来，你进不来不就造成非法访问了吗？ 所以，同样是野指针，也分野指针指向的地址是什么情况，楼房还没拆，那就一时半会还能使用，楼房拆了被改建为平房了，那如果平房们没锁你还可以溜进去，只是房子布局不一样了，人家没2楼你非要上2楼，那就会出错，甚至如果平房锁着禁止进入，你就成了非法入侵的窃贼。 所以，你在delete函数里的野指针属于楼房没拆的情况（地址是明确的，只是房东还没来得及拆楼）；在main里的野指针属于没有乱闯入民宅并把民宅当楼房使用的情况（因为没分配过内存，地址是随机的，也就是你随机闯入任何一家民宅）。 能理解吗？

user: user-1
content: 我觉得已经讲的挺清楚了，只是你没好好理解。 free只是设置一个flag告诉系统这块内存不再使用了，系统可以把这块内存让给其他程序使用。但是并不代表立刻有别的程序来占用这块内存，所以这块内存的信息一时半会没有被擦写，还是原来的老信息，所以可能继续访问时还能读出原来的信息。 然而一旦这块内存被系统重新份配给别的程序，别的程序就有可能重新修改了这块内存的信息，那么这块内存的信息就未必符合原来的结构体形式，比如原来老信息是一个int，一个长度为10的char数组，新的信息是一个char，一个int，这样你按原来的结构体形式来读取，结果必然出错，而且新的内存空间没有老的内存空间大，按原来的结构体形式读取还可能造成越界。打个比方，原来某个地址有一块地被你租用，你建了一栋500平米的楼房，后来你free把地退租了，地和楼房被房东收回，此时房东还没把楼拆了，你偷偷溜回来那自然还可以正常使用房子，然而如果房东把它拆了把地分割租给了别的租户，别的租户只建了50平米的平房租，这时你非要闯进人家的平房，并按原来500平米的楼房来使用，那可不就出错了吗？而且，人家平房的租客有可能把门锁了不让你进来，你进不来不就造成非法访问了吗？ 所以，同样是野指针，也分野指针指向的地址是什么情况，楼房还没拆，那就一时半会还能使用，楼房拆了被改建为平房了，那如果平房们没锁你还可以溜进去，只是房子布局不一样了，人家没2楼你非要上2楼，那就会出错，甚至如果平房锁着禁止进入，你就成了非法入侵的窃贼。 所以，你在delete函数里的野指针属于楼房没拆的情况（地址是明确的，只是房东还没来得及拆楼）；在main里的野指针属于没有乱闯入民宅并把民宅当楼房使用的情况（因为没分配过内存，地址是随机的，也就是你随机闯入任何一家民宅）。 能理解吗？

user: user-0
content: 引用 6 楼 qybao的回复:[quote=引用 5 楼 qq_35541626 的回复：]感谢两位大大的答复，我把之前的代码改了一下，现在p_freeAid可以打印 p_free->next->num 的值了。  void free_node(STU **p_head){     STU*p_free;     STU*p_freeAid;     printf("p_freeAid的值是：0X%x\n",p_freeAid->num);     p_free=*p_head;     if(*p_head==NULL){         printf("这个链表为空，无需释放\n");     }     else{         while (p_free!=NULL) {             p_freeAid=p_free->next;             if(p_freeAid!=NULL){                 printf("p_freeAid0000000的值是：0X%x\n",p_free->next->num);             }              printf("p_freeAid的值是：0X%x\n",p_freeAid);             printf("p_free的值是：0X%x\n",p_free->next);             int num=p_free->num;             printf("%d\n",num);             free(p_free);             printf("%d\n",p_free->num);             p_free=p_freeAid;         }     }     //*p_head=NULL; }   但是又有一些新的问题出现。 int main() {     STU* link_head=NULL;    STU*test_01;    //test();    printf("0X%x\n",test_01);    //printf("0X%x\n",test_01->num);     //test_01=NULL;    int num=test_01->num;    printf("0X%x\n",test_01);     return 0; }  我在主函数 main 里面直接定义了一个 STU格数的test函数，然后直接调test->num.果然出现了，之前那样的段错误提醒。  但是 void test(){     STU*test_02;     printf("0X%x\n",test_02->num); }  int main() {     STU* link_head=NULL;    STU*test_01;    test();    printf("0X%x\n",test_01);    //printf("0X%x\n",test_01->num);     //test_01=NULL;    int num=test_01->num;    printf("0X%x\n",test_01);     return 0; }  当我在函数 test里面定义了一个STU类型的*test指针，然后调用test函数，这里编译通过，然后值就出来了（虽然是没有意义的值，但是编译通过了），所以我就不太明白，同样都是指空的指针，为什么一个出现了段错误，一个没有。 这也是我一直想不明白的。 就是我在最开始的链表释放函数node_free里面，刚开始定义的指针 *stu p_freeAid 后，马上打印p_freeAid->num 是有值的，但是当我给他赋值，free->next的时候，他就出现了段错误。 所以我的核心问题就是 同样都是野指针，然后我调里面的值，为什么一个直接出现段错误，一个就没有，能打出来值（虽然值没有什么意义。。）  还有一个问题就是我之前的 链表释放函数node_free里面，我已经free过的空间，我再次用 p_free去调里面的值，按理说，这时空间已经被释放，这个时候，p-free就是个野指针，我用debug看，p-free里面的值已经变成了“-16168940”之类的数，我理解就是已经释放掉了，但是我用p-free去调里面的 num 居然可以打印出来值，也没有报段错误，那么我这个free（）函数究竟有没有生效呢？ 这种情况应该怎么解释呢？ 费解....  再次感谢两位大大的解答，谢谢。 既然是野指针，那就说明指针指向的地址是不确定的。你刚释放内存，又继续访问该内存，如果该内存没有被其他程序占用，那你访问它不会出错；如果该内存被其他程序占用了，那就有问题了，如果该内存被其他程序设定不可读写，你非要读写，就会出非法内存访问错误了。[/quote] 你好，非常感谢您的回复，但是我的问题是 我free了之后，为什么访问被free的区域还是有值，我也知道不能访问，但是访问之后为什么有值是我比较纠结的，所以我这个free到底有没有成功?  还有就是 为什么我同样都是野指针，我在函数里面调值就可以调，但是在主函数那里就会报段错误。这两个问题请您再解释一下。 解决完问题我就结帖了。   希望您再回复一下。谢谢。

user: user-0
content: 引用 7 楼 赵4老师的回复:数据结构对单链表进行数据排序 http://bbs.csdn.net/topics/392201633 您好，请您再看下我的问题好不，我不是纠结链表怎么做，我是在纠结c语言本身的机制问题，为什么free了还有数值，还有 为什么 同样都是野指针，在函数里定义野指针就不会报段错误，在主方法里定义就会报段错误呢？

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

user: user-1
content: 引用 5 楼 qq_35541626 的回复：感谢两位大大的答复，我把之前的代码改了一下，现在p_freeAid可以打印 p_free->next->num 的值了。  void free_node(STU **p_head){     STU*p_free;     STU*p_freeAid;     printf("p_freeAid的值是：0X%x\n",p_freeAid->num);     p_free=*p_head;     if(*p_head==NULL){         printf("这个链表为空，无需释放\n");     }     else{         while (p_free!=NULL) {             p_freeAid=p_free->next;             if(p_freeAid!=NULL){                 printf("p_freeAid0000000的值是：0X%x\n",p_free->next->num);             }              printf("p_freeAid的值是：0X%x\n",p_freeAid);             printf("p_free的值是：0X%x\n",p_free->next);             int num=p_free->num;             printf("%d\n",num);             free(p_free);             printf("%d\n",p_free->num);             p_free=p_freeAid;         }     }     //*p_head=NULL; }   但是又有一些新的问题出现。 int main() {     STU* link_head=NULL;    STU*test_01;    //test();    printf("0X%x\n",test_01);    //printf("0X%x\n",test_01->num);     //test_01=NULL;    int num=test_01->num;    printf("0X%x\n",test_01);     return 0; }  我在主函数 main 里面直接定义了一个 STU格数的test函数，然后直接调test->num.果然出现了，之前那样的段错误提醒。  但是 void test(){     STU*test_02;     printf("0X%x\n",test_02->num); }  int main() {     STU* link_head=NULL;    STU*test_01;    test();    printf("0X%x\n",test_01);    //printf("0X%x\n",test_01->num);     //test_01=NULL;    int num=test_01->num;    printf("0X%x\n",test_01);     return 0; }  当我在函数 test里面定义了一个STU类型的*test指针，然后调用test函数，这里编译通过，然后值就出来了（虽然是没有意义的值，但是编译通过了），所以我就不太明白，同样都是指空的指针，为什么一个出现了段错误，一个没有。 这也是我一直想不明白的。 就是我在最开始的链表释放函数node_free里面，刚开始定义的指针 *stu p_freeAid 后，马上打印p_freeAid->num 是有值的，但是当我给他赋值，free->next的时候，他就出现了段错误。 所以我的核心问题就是 同样都是野指针，然后我调里面的值，为什么一个直接出现段错误，一个就没有，能打出来值（虽然值没有什么意义。。）  还有一个问题就是我之前的 链表释放函数node_free里面，我已经free过的空间，我再次用 p_free去调里面的值，按理说，这时空间已经被释放，这个时候，p-free就是个野指针，我用debug看，p-free里面的值已经变成了“-16168940”之类的数，我理解就是已经释放掉了，但是我用p-free去调里面的 num 居然可以打印出来值，也没有报段错误，那么我这个free（）函数究竟有没有生效呢？ 这种情况应该怎么解释呢？ 费解....  再次感谢两位大大的解答，谢谢。 既然是野指针，那就说明指针指向的地址是不确定的。你刚释放内存，又继续访问该内存，如果该内存没有被其他程序占用，那你访问它不会出错；如果该内存被其他程序占用了，那就有问题了，如果该内存被其他程序设定不可读写，你非要读写，就会出非法内存访问错误了。

user: user-1
content: p_freeAid=p_free->next; //如果p_free->next是NULL，p_freeAid就是NULL，否则你后面的p_free=p_freeAid是怎么让p_free变为NULL而退出while循环？所以，此时p_freeAid是NULL，打印p_freeAid->num就出错。这和你的showlink可是有区别的，showlink是先打印p_mov->num，然后才p_mov=p_mov->next，所以p_mov为NULL就退出while了不会继续打印p_mov->num，所以showlink不会出错

user: user-0
content: 感谢两位大大的答复，我把之前的代码改了一下，现在p_freeAid可以打印 p_free->next->num 的值了。  void free_node(STU **p_head){     STU*p_free;     STU*p_freeAid;     printf("p_freeAid的值是：0X%x\n",p_freeAid->num);     p_free=*p_head;     if(*p_head==NULL){         printf("这个链表为空，无需释放\n");     }     else{         while (p_free!=NULL) {             p_freeAid=p_free->next;             if(p_freeAid!=NULL){                 printf("p_freeAid0000000的值是：0X%x\n",p_free->next->num);             }              printf("p_freeAid的值是：0X%x\n",p_freeAid);             printf("p_free的值是：0X%x\n",p_free->next);             int num=p_free->num;             printf("%d\n",num);             free(p_free);             printf("%d\n",p_free->num);             p_free=p_freeAid;         }     }     //*p_head=NULL; }   但是又有一些新的问题出现。 int main() {     STU* link_head=NULL;    STU*test_01;    //test();    printf("0X%x\n",test_01);    //printf("0X%x\n",test_01->num);     //test_01=NULL;    int num=test_01->num;    printf("0X%x\n",test_01);     return 0; }  我在主函数 main 里面直接定义了一个 STU格数的test函数，然后直接调test->num.果然出现了，之前那样的段错误提醒。  但是 void test(){     STU*test_02;     printf("0X%x\n",test_02->num); }  int main() {     STU* link_head=NULL;    STU*test_01;    test();    printf("0X%x\n",test_01);    //printf("0X%x\n",test_01->num);     //test_01=NULL;    int num=test_01->num;    printf("0X%x\n",test_01);     return 0; }  当我在函数 test里面定义了一个STU类型的*test指针，然后调用test函数，这里编译通过，然后值就出来了（虽然是没有意义的值，但是编译通过了），所以我就不太明白，同样都是指空的指针，为什么一个出现了段错误，一个没有。 这也是我一直想不明白的。 就是我在最开始的链表释放函数node_free里面，刚开始定义的指针 *stu p_freeAid 后，马上打印p_freeAid->num 是有值的，但是当我给他赋值，free->next的时候，他就出现了段错误。 所以我的核心问题就是 同样都是野指针，然后我调里面的值，为什么一个直接出现段错误，一个就没有，能打出来值（虽然值没有什么意义。。）  还有一个问题就是我之前的 链表释放函数node_free里面，我已经free过的空间，我再次用 p_free去调里面的值，按理说，这时空间已经被释放，这个时候，p-free就是个野指针，我用debug看，p-free里面的值已经变成了“-16168940”之类的数，我理解就是已经释放掉了，但是我用p-free去调里面的 num 居然可以打印出来值，也没有报段错误，那么我这个free（）函数究竟有没有生效呢？ 这种情况应该怎么解释呢？ 费解....  再次感谢两位大大的解答，谢谢。

user: user-3
content: printf("p_freeAid的值是：0X%x\n",p_freeAid->num); 这条语句是在哪里打印的，从你的函数里可以知道，这条语句是在定义两个变量后直接打印的，你定义的变量没有初始化呀，没初始化就是野指针，之所以说是可能出现段错误，是因为野指针指向的位置可能是不可以读写的，既然不可以读写，那么必然会出现段错误。   //printf("p_freeAid的值是：0X%x\n",p_free->next->num); 这条语句是因为不能保证p_free->next指向的内容不是链表的末尾，如果指向了链表末尾，即NULL，那么这条语句打印必然会导致段错误～

user: user-0
content: 你好，首先非常感谢您的解答，我初学c，以前用Java模拟过链表，但是好像没c语言要考虑的那么多。关于您的回答我还是有一些疑问。 “printf("p_freeAid的值是：0X%x\n",p_freeAid->num);这句之前p_freeAid是野指针，这样操作可能导致段错误” 关于这句话，P-freeAid 的指向，我认为明明是指向 p-free->next 的。 而且在执行这行代码的时候，明明在free.next里面还是有值的。所以按照我的理解P-freeAid里面应该是有值的，而且 我debug里面， p-freeAid里面的“num”也是有值的，但是我用 printf函数调的时候，程序就进行不下去，所以就不太理解，所以还是希望您能就这点再给解答一下。  而且之前那个 showLink函数里面，我就把p_head->next的值赋给了p_mov。然后我在打印的时候  就是调用的 p_mov->num,来取值的。 在free函数里面 我用p_freeAid 来接收 p_free->next的值，然后同样想调用 p_freeAid->num 来取值为什么就不行了呢？   费解中。。。。

user: user-3
content: 在free_node函数里有多处问题， 1. printf("p_freeAid的值是：0X%x\n",p_freeAid->num);这句之前p_freeAid是野指针，这样操作可能导致段错误； 2.  printf("p_freeAid的值是：0X%x\n",p_free->next->num);这条打印也可能出现多错误，因为p_free不是NULL，不等于p_free->next不为NULL； 3.  free(p_free);             printf("%d\n",p_free->num); 在释放之后打印这条语句，结果是未定义的，因为已经释放的空间，其内容具有不确定性，释放的空间不能再次直接使用，需要重新malloc； 4.  //*p_head=NULL;这句不能注释掉，因为头结点已经释放掉了，为了保证后面对头结点的使用不出现问题，这句需要加上（去掉注释）；  void free_node(STU **p_head) {     STU*p_free;     STU*p_freeAid;     //printf("p_freeAid的值是：0X%x\n",p_freeAid->num);     p_free=*p_head;     if(*p_head==NULL){         printf("这个链表为空，无需释放\n");         return;     }     //else{     while (p_free!=NULL) {         p_freeAid=p_free->next;         //printf("p_freeAid的值是：0X%x\n",p_free->next->num);         printf("p_freeAid的值是：0X%x\n",p_freeAid);         printf("p_free的值是：0X%x\n",p_free->next);         int num=p_free->num;         printf("%d\n",num);         free(p_free);         printf("%d\n",p_free->num);         p_free=p_freeAid;     }     //}     *p_head=NULL; } 代码逻辑可以稍微改一下，去掉else， 另外，打印指针建议用%p