1函数体内指针变量的己值与他值if1includestdio。hincludestdlib。hvoidfoo(intpa,intan){pa解引用修改其指向的值,传址的解引用能够联系被调函数和主调函数的栈帧pa(int)malloc(sizeof(int));未解引用的pa是一个局部变量fool调用结束后其栈帧会被覆盖foo调用一次,堆内存就会泄漏一块大小为size(int)的内存}intmain(){inta0;foo(a,11);intan11;printf(d,a);11free(p);无法释放foo分配的动态内存,因为p本身本没有被修改,且造成了内存泄漏foo(p,22);intan22;pa22;printf(d,a);22上面两次调用,相当于指针pa做左值,一个用了取址,修改自身,一个是指针,指向一个变量,相当于用其做了中转来修改其指向free(p);无法释放foo分配的动态内存,因为p本身本没有被修改,且造成了内存泄漏看上面函数调用后的注释,其实p只是做了右值,本质也是一个值传递,只是其值有特殊性,是一个地址getchar();return0;}else上面试图修改pa指向动态内存造成了内存泄漏,如何正确修改呢?上例正确修改了pa指向的内存空间的值,是因为直接或间接使用了a做右值,其左值是与其类型一致的指针。所以要让pa正确指向一块动态内存而不造成内存泄漏,需要用pa做右值,其左值是与其类型一致的指针。肯定是更高一级的指针includestdio。hincludestdlib。hvoidfoo(intpp,intan){pp(int)malloc(sizeof(int));解引用参数指针可以产生副作用pp自身尽量避免用做左值,未解引用的pp是一个局部变量pp33;}intmain(){inta0;printf(d,a);0foo(pa,33);intan33;printf(dd,a,pa);033free(pa);正确释放foo(ppa,44);intan22;pa44;printf(dd,a,ppa);044free(ppa);正确释放getchar();return0;}总结一下主调函数如果需要利用被调函数的副作用来修改inta函数调用时的实参必须是a(可以是间接的a),左值应是int类型被调函数的函数体内必须是指向a的指针的解引用;主调函数如果需要利用被调函数的副作用来修改intpa函数调用时的实参必须是pa(可以是间接的pa),左值应是int类型被调函数的函数体内必须是指向pa的指针的解引用;endif 2被调函数读写主调函数的数组includestdio。hvoidfo(intpr,intn){for(inti0;i)pr〔i〕i1;可以是下面三种写法}voidfoo(int(prr)〔5〕,intn){for(inti0;i)for(intj0;j5;j)prr〔i〕〔j〕(i1)(j1);可以是下面三种写法}intmain(){intflag0;数组溢出测试用通过函数来读写一维数组元素intar〔5〕{0};ar〔3〕33;(ar3)33;ar〔i〕这种下标写法是指针(ari)写法的语法糖数组名做右值转化为指向数组首元素的首地址,由此可以正确完成下述的指针算术运算(pr3)33;pri,pr按其指向的元素的长度移动,数字i与类型取得一致也就是移动i个int类型单位的长度,isizeof(int)个字节有了上述铺垫以后,如何通过函数来读写一维数组ar的元素呢?(注意arr本身无意义)需要以ar做实参,也就是右值,其左值(形参)需要是一个int也就是实参对形参的赋值必须类似:在函数体内必须是式的左值写法fo(ar,5);通过函数来读写二维数组元素intarr〔3〕〔5〕{0};arr〔2〕〔3〕23;((arr2)3)23;arr〔i〕〔j〕这种下标写法是指针((arri)j)写法的语法糖int(prr)〔5〕数组名做右值转化为指向数组首元素的首地址,由此可以正确完成下述的指针算术运算数组元素的类型是int〔5〕int(prr)〔5〕的类型,去年标识符和符号r后的int〔5〕就是prr的类型((prr2)3)23;prri,pr按其指向的元素的长度移动,也就是int〔5〕的长度也就是移动i个int〔5〕类型单位的长度,isizeof(int)5个字节有了上述铺垫以后,如何通过函数来读写二维数组arr的元素呢?需要以arr做实参,也就是右值,其左值(形参)需要是一个int()〔5〕也就是实参对形参的赋值必须类似:int(prr)〔5〕在函数体内必须是式的左值写法foo(arr,2);int(prr)〔5〕foo(ar,1);int(prr)〔5〕注意此时第一个实参(或右值)的写法与上面的不同。for(inti0;i5;i)printf(d,ar〔i〕);12345ar与运算符在一起时,ar表示整个数组,而不是数组的元素数组当与运算符和sizeof在一起时表示整个数组,而不是数组的元素。与运算符和sizeof在一起这两种情况以外的上下文都会指向数组首元素注意此时类型的一致性,都是int〔5〕(prr1)99;加1的算术运算移动的是int〔5〕类型的长度,溢出到了arr外的相邻位置flag为什么会是到了flag呢?压栈时先压flat,再压ar〔4〕printf(d,flag);99getchar();return0;} 3通过函数参数返回动态数组 通过函数返回值返回动态数组相对于通过函数参数返回动态数组来说要相对容易一些,因为通过参数的话需要更高一级的指针参数:voidheapAr(intp,intn)通过函数参数返回一维动态数组{p(int)malloc(sizeof(int)n);}voidheappa(int(p)〔5〕,intn,intm)通过函数参数返回二维动态数组(列常量){for(inti0;i){(p)〔i〕(int)malloc(sizeof(int)m);}}voidheapArr(intp,intr,intc)通过函数参数返回二维动态数组{p(int)malloc(sizeof(int)r);for(inti0;i){(p)〔i〕(int)malloc(sizeof(int)c);}}注意堆内存的释放也要放两次,且逆向 End