user-0 提问: 关于动态内存，求大神解答

回复:
user: user-1
content: 引用 楼主 u012941377 的回复:#include<stdio.h> #include<malloc.h>  void f(int **q) { 	*q=(int *)malloc(sizeof(int));//为什么不去掉这行 该程序编译就回出错？ 	int i; 	i=10; 	*q=&i;  } int main(void) { 	int *p; 	f(&p); 	printf("%d\n",*p); 	return 0; } /////////////////////////////////////////////////////////////////// 楼主，你写出这样写代码迟早会出问题： 1.你在main函数已经定义了一个p指针，程序启动后它在进程空间中会有一个虚拟内存地址，此时p会占用4个字节（32位系统前提），这个指针里面没有指向； 2，然后你把p的虚拟内存地址传给了f（），f（）接受到参数&p，后，会干什么呢？ 3.你然后又在堆里面申请了一个int类型的4字节的空间传递给p，这样一来，p原来的地址被这4个字节的首地址覆盖，此时p原来的地址已经找不到了， 3.接着你又把栈里面的局部变量i的地址交给了p， 4.最后打印出来的*p到底是什么？ 这个先不说，楼主这样写，会出现内存泄露，你用molloc申请的内存，必须由程序员释放的，当程序结束后，系统也会回收这些在堆里面申请的内存，但是系统能回收吗？系统要释放，首先要找到这块int内存的首地址，但是它的地址已经丢失，他就无法释放这块内存，你程序运行一次，就有一块内存泄露，多运行几次，内存就完了，

user: user-2
content: 楼主，指针带回来一个栈区地址到底有什么意义。

user: user-3
content: 计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式的值【比如printf("%p\n",...)】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=...】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495

user: user-4
content: 除了第二条和语言规范,C标准有关外,其他都是逻辑错误. 有些会产生严重的运行时错误.

user: user-4
content: 1)分配的内存被替换,因而无法释放,内存泄漏.这是严重错误. 2)C,和C++有所不同,C变量声明定义要在其他执行语句之前,C99不清楚还是不是这样. 3)返回和传出函数局部自动变量的地址,是危险的行为,      因为变量的生命周期已经结束了,引用他的行为是错误的(这是个死魂灵了). 4)不是分配的内存,被释放掉,是个错误,至少逻辑是错误的.

user: user-5
content: 引用 28 楼 liu111qiang88 的回复:首先去不去掉都是错误的，你最后改变了p的指向，他指向了占内存，这个函数结束这个内存会释放的，你看到的结果是个假象，因为你用的是debug，你用release试试，肯定会有问题。 如果有人编不过，是因为c语言规范编译器要求定义放在最上边  Code Blocks的release版本证实了这是对的。

user: user-0
content: 引用 32 楼 my_live_123 的回复:ls说了一大堆，没有点题啊 很简单，你不分配内存，如何用？道理很简单，你指者一个空盆说，这是一盆水，然后你就用手去触摸水。有水的感觉嘛？没有！只有加满水，才能舒服摸摸！ “这是一盆水”——声明一个指针，”加水“——分配内存！“触摸水”——访问内存！”摸水的感觉“——读取内存数据！晓得？ 务必区分指针变量和存储数据的变量大神可以给个交流方式 详细的跟我讲解一下这个么

user: user-6
content: ls说了一大堆，没有点题啊 很简单，你不分配内存，如何用？道理很简单，你指者一个空盆说，这是一盆水，然后你就用手去触摸水。有水的感觉嘛？没有！只有加满水，才能舒服摸摸！ “这是一盆水”——声明一个指针，”加水“——分配内存！“触摸水”——访问内存！”摸水的感觉“——读取内存数据！晓得？ 务必区分指针变量和存储数据的变量

user: user-7
content: 引用 17 楼 u012941377 的回复:[quote=引用 13 楼 lijian19911012 的回复:] [quote=引用 10 楼 lijian19911012 的回复:] [quote=引用 7 楼 liuhengxiao 的回复:] [quote=引用 5 楼 lijian19911012 的回复:] [quote=引用 3 楼 dbzhang800 的回复:] [quote=引用 楼主 u012941377 的回复:] #include<stdio.h> #include<malloc.h>  void f(int **q) { 	*q=(int *)malloc(sizeof(int));//为什么不去掉这行 该程序编译就回出错？ } 你是想说，去掉就会出错么？？[/quote] 有个疑问是，i是在f()中定义的变量，存放在stack中，调用完成之后释放，为什么printf("%d\n",*p);不会报错。[/quote]  虽然i变量已经被释放了，但i这个变量原本的地址在内存依然存在的，printf时打印的结果会是垃圾数据[/quote] 我可以理解为，给一个地址，就可以允许访问他指向的内存空间吗？ int *pt = 0x12345678; printf("%d", *pt);??[/quote] 解引用野指针是未定义行为。打印的10只是个假象。[/quote]那为什么加上哪行会出错呢 ，应该是正确的吧[/quote] 出的什么错，贴出来

user: user-8
content: 首先去不去掉都是错误的，你最后改变了p的指向，他指向了占内存，这个函数结束这个内存会释放的，你看到的结果是个假象，因为你用的是debug，你用release试试，肯定会有问题。 如果有人编不过，是因为c语言规范编译器要求定义放在最上边

user: user-9
content: *q=(int *)malloc(sizeof(int*));//为什么不去掉这行 该程序编译就回出错？

user: user-10
content: 引用 28 楼 liu111qiang88 的回复:首先去不去掉都是错误的，你最后改变了p的指向，他指向了占内存，这个函数结束这个内存会释放的，你看到的结果是个假象，因为你用的是debug，你用release试试，肯定会有问题。 如果有人编不过，是因为c语言规范编译器要求定义放在最上边 我倒是没想到这一点，malloc的是堆，i是栈，编译没问题，运行就有问题。

user: user-11
content: 使用visual studio2010的编译器也没问题。如果你想要c-free专业版，加我QQ：2901452412，我给你发过去，带激活码的。

user: user-11
content: 你换个编译器试试，我是用的是c-free专业版，里边默认使用mingw编译器，代码应该没什么问题。

user: user-12
content: 引用 26 楼 u012941377 的回复:[quote=引用 19 楼 mcmay 的回复:] 在CodeBlocks和TC下编译，都没有出错。 不过 *q = (int *) malloc(sizeof(int)); 这个语句没有起到任何作用， *q所指向的地址由*q = &i; 这个语句给替换掉了。malloc所分配的空间地址犹在，但却没有指针指向它了。在CB下 可以编译了 感谢，可是根据我们老师讲的 如果q分配的不是动态内存的话，下面的p应该不会是10啊，我在动态内存在纠结了[/quote] 难道q一定要分配动态内存，*p的值才是10吗？*p的值之所以是10，是因为*q的值是10。而*q的值成为10，是因为*q = &i。&i覆盖了malloc返回值赋予q的指针。当*q = &i时，q与(int *)malloc(sizeof(int))的返回值已经没有任何关系了。

user: user-0
content: 引用 19 楼 mcmay 的回复:在CodeBlocks和TC下编译，都没有出错。 不过 *q = (int *) malloc(sizeof(int)); 这个语句没有起到任何作用， *q所指向的地址由*q = &i; 这个语句给替换掉了。malloc所分配的空间地址犹在，但却没有指针指向它了。在CB下 可以编译了 感谢，可是根据我们老师讲的 如果q分配的不是动态内存的话，下面的p应该不会是10啊，我在动态内存在纠结了

user: user-13
content: 你要用动态分配将f函数改成这样就没问题了void f(int **q) {     *q=(int *)malloc(sizeof(int));//为什么不去掉这行 该程序编译就回出错？ //  int i; //  scanf("%d",&i); //  *q=&i; 	scanf("%d", *q); }

user: user-0
content: 引用 21 楼 u010211892 的回复:因为c的声明要放在语句前，你把那句和下面的定义掉换个位置。 #include<stdio.h> #include<malloc.h>   void f(int **q) {     int i; 	*q=(int *)malloc(sizeof(int));     i=10;     *q=&i;   } int main(void) {     int *p;     f(&p);     printf("%d\n",*p);     return 0; }这样就不会报错了，你的c基础不够扎实。还是不正确

user: user-13
content: 引用 22 楼 a515360208 的回复:[quote=引用 15 楼 u014687239 的回复:] #include<stdio.h> #include <iostream> #include<malloc.h>   void f(int **q) {     *q=(int *)malloc(sizeof(int));//为什么不去掉这行 该程序编译就回出错？     int i;     scanf("%d",&i);     *q=&i;   } int main(void) {     int *p;     f(&p);     printf("%d\n",*p); 	free(p); 	*p=NULL;     system("pause");     return 0; }  我改了改，在free（p）编译器报错。是指向指针的指针，使用free（p)是不是释放了一块内存。。这个程序写的可读性太差了，地址不知不觉改变了，你自己都不知道，你在f中malloc后又用其它的地址去替代，也就造成了一块分配的内存无法访问了，而你free的是另一个地方，你单步调试看看各变量的地址变化就清楚了[/quote]准确的说你free的是f函数中变量i的地址，

user: user-13
content: 引用 15 楼 u014687239 的回复:#include<stdio.h> #include <iostream> #include<malloc.h>   void f(int **q) {     *q=(int *)malloc(sizeof(int));//为什么不去掉这行 该程序编译就回出错？     int i;     scanf("%d",&i);     *q=&i;   } int main(void) {     int *p;     f(&p);     printf("%d\n",*p); 	free(p); 	*p=NULL;     system("pause");     return 0; }  我改了改，在free（p）编译器报错。是指向指针的指针，使用free（p)是不是释放了一块内存。。这个程序写的可读性太差了，地址不知不觉改变了，你自己都不知道，你在f中malloc后又用其它的地址去替代，也就造成了一块分配的内存无法访问了，而你free的是另一个地方，你单步调试看看各变量的地址变化就清楚了