user-0 提问: 关于二级指针有关的赋值及作为参数的问题

回复:
user: user-1
content: 理论上不可以有啥指回问题。 改变二级指针指向，只好用三级指针做形参，传递二级指针的地址。 C++可以用指针的引用做形参。 ，，，，，，，，，，，，，，，，， 话说，C,C++给程序员一定的灵活性， 代价是自己控制逻辑，自己检查问题， 编译器对这种灵活的技巧， 不支持，也不反对 全靠自己保证没问题。

user: user-2
content: 对任何开发语言，都需要 自己控制逻辑，自己检查问题， 编译器对程序员使用灵活的技巧， 不支持，也不反对 全靠自己保证没问题。  区别仅仅是五十步笑百步而已。

user: user-2
content: 理解和讨论之前请先学会如何观察！  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！ 不会单步Release版对应汇编？在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有，然后在IDE中运行。（一般人我不告诉他！）  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",...);或者cout<<...】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “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-1
content: 看错了，这里没有传递过  局部非静态变量的地址。   #include<stdio.h> int k=7,m=5; void f(int **s) { int *t=&k;//局部非静态变量指针 t，指向全局变量k没有问题 s=&t;*s=&m; //s=&t:只能在函数内部起作用，出了函数，实参指针r的值，没变 printf("%d,%d,%d\n",k,*t,**s);//这地方没问题。输出7,5,5 //t=&k;这句不起作用。 //因为 *s 就是t ; //*s=&m ;改变了t的值，结果就是 t 的值是m的地址 ,所以,*t,和**s 都是m,所以输出 7,5,5 } int main() { int i=3,*p=&i,**r=&p; f(r);//r 的值不变，依然是 &p; printf("%d,%d,%d\n",i,*p,**r);//这地方 r 依然是&p } PS： 这个运行结果不奇怪 //运行结果7,5,5 3,3,3  #include<stdio.h> int k=7; void f(int **s) { int *t=&k; *s=t;//*s=t;这个结果影响了实参所指对象的值，因为实参和s 的值相同,他们指向的是同一块内存。         // 结果就是 *s 就是k的地址,因此，**s 就是 k;                 //传递指针的作用就是，使用，或者修改 *s,**s 等等，可以间接使用和修改的数据。         //这里指针参数的用法，完全没问题，不过直接写*s=&k;就可以了。         //这里*s =t 就是    于间接引用中的写，也就是修改。  printf("%d,%d,%d\n",k,*t,**s);//这里的输出，就属于间接引用中的（读取）使用。 } main() { int i=3,*p=&i,**r=&p; // f(r);//函数调用结束,*r =&k; 所以， printf("%d,%d,%d\n",i,*p,**r);//输出3，7，7                                             // *r 被改变了，也就是 p 被改变了，                                            //指向k了，此时 *p 变成 &k了                                           //*p 是k,**r 也是k 所以输出3，7，7   } //运行结果7,7,7 3,7,7

user: user-0
content: 明白了  引用 16 楼 lm_whales 的回复:。。。。。。。。。局部非静态变量的地址 在哪？？指针t吗？？

user: user-1
content: 。。。。。。。。。局部非静态变量的地址

user: user-1
content: 局部变量的地址， 不能通过返回值， 或者参数在函数调用结束后， 传递出函数供调用者使用，这样的话，会造成， 使用结束了生命周期的变量的内存（地址）的错误，结果未定义 这里未定义，有几种情况 1）仅仅为何输出地址，当然不会有错误了，       然而很难控制仅仅输出地址，而不是去读写。而且必要性也不大。       或者弃而不用。这同样是说的好听，很难做到。       所以，不应该返回这个变量的地址，       而不是返回了再控制不去使用，或者仅仅输出地址（或者其他诸如，比较地址）之用。  2）读取数据，可能会出错，这个数据有可能不正确，但是不一定会出错       未定义在这里的含义是，可能但未必出错，       最重要的是，不要这么做，因为结果不可靠。 3）写入数据，可能会出错，但是不一定会出错，然而一旦出错，就会很严重     写入的数据，很可能破坏了了堆栈的结构。导致程序不能正常执行。     未定义在这里的含义是，同样是，可能但未必出错，     但是这里问题，比读取要严重得多，程序可能会出现莫名其妙的错误，很难查找追踪。

user: user-1
content: 指针是为了间接引用数据（不是变量） 如果指针指向 int,double ,struct 等数据类型 我们说它是一级指针 如果指向指针，我们说它是多级指针 这个级指的是间接引用次数 通过多少次间接引用，可以指向 int,double ,struct 等数据类型。就说这个指针是多少级指针。 int *p;//一级指针 int **pp;//二级指针   int ***ppp;//三级指针 int n=10; int *p=&n; //从指针p到 n ，也就是 *p 是一次间接引用，*p就是 n了。 int **pp=&p;从指针 pp 到 p,再到 n，是两次间接引用，*pp 就是 p ,*p 就是 n ,所以 **pp就是 n;pp是二级指针。 多级指针，就是这回事。 从定义看，就是*号的个数。 当然这是概略的，不够严谨的表述。  更复杂的情况，要更加细致的描述，但是初学指针，这就够了

user: user-0
content: 引用 18 楼 lm_whales 的回复:看错了，这里没有传递过  局部非静态变量的地址。   #include<stdio.h> int k=7,m=5; void f(int **s) { int *t=&k;//局部非静态变量指针 t，指向全局变量k没有问题 s=&t;*s=&m; //s=&t:只能在函数内部起作用，出了函数，实参指针r的值，没变 printf("%d,%d,%d\n",k,*t,**s);//这地方没问题。输出7,5,5 //t=&k;这句不起作用。 //因为 *s 就是t ; //*s=&m ;改变了t的值，结果就是 t 的值是m的地址 ,所以,*t,和**s 都是m,所以输出 7,5,5 } int main() { int i=3,*p=&i,**r=&p; f(r);//r 的值不变，依然是 &p; printf("%d,%d,%d\n",i,*p,**r);//这地方 r 依然是&p } PS： 这个运行结果不奇怪 //运行结果7,5,5 3,3,3  #include<stdio.h> int k=7; void f(int **s) { int *t=&k; *s=t;//*s=t;这个结果影响了实参所指对象的值，因为实参和s 的值相同,他们指向的是同一块内存。         // 结果就是 *s 就是k的地址,因此，**s 就是 k;                 //传递指针的作用就是，使用，或者修改 *s,**s 等等，可以间接使用和修改的数据。         //这里指针参数的用法，完全没问题，不过直接写*s=&k;就可以了。         //这里*s =t 就是    于间接引用中的写，也就是修改。  printf("%d,%d,%d\n",k,*t,**s);//这里的输出，就属于间接引用中的（读取）使用。 } main() { int i=3,*p=&i,**r=&p; // f(r);//函数调用结束,*r =&k; 所以， printf("%d,%d,%d\n",i,*p,**r);//输出3，7，7                                             // *r 被改变了，也就是 p 被改变了，                                            //指向k了，此时 *p 变成 &k了                                           //*p 是k,**r 也是k 所以输出3，7，7   } //运行结果7,7,7 3,7,7 谢谢，大致都懂了，就还有一个疑惑，就是二级指针s指向r是不是变三级指针还是四级指针。一级指针可以指回二级吗？

user: user-0
content: 引用 19 楼 zhao4zhong1 的回复:理解和讨论之前请先学会如何观察！  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！ 不会单步Release版对应汇编？在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有，然后在IDE中运行。（一般人我不告诉他！）  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",...);或者cout<<...】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “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-0
content: 终于明白了一点，不同类型间相互付地址即指针指向要用&号(二级指针类型和一级指针类型不同) 所以才有s=&t;类似一级指针指向变量时的t=&k;其中*s=t是因为两个都是同类型，不用&可以相互赋值，类似于相同类型变量赋值。  但是还是有一个问题就是两个形参**s都关联了r，为什么结果却大不相同？

user: user-3
content: 取地址符和星号可以说是互逆运算，加了星号代表值，加了取地址符表示地址打印出来就像一串乱码

user: user-3
content: *s就是一级指针，还是相当于地址，只有两个星号的时候才表示值，可以改变一个星号指的地址上面的值

user: user-3
content: int **s是二级指针

user: user-0
content: 引用 7 楼 qq_36048429 的回复:楼主明白了吗？应该不难，〖前提是我没看错什么〗 你说说看，看我能捞到什么自己遗漏的知识点

user: user-0
content: 引用 7 楼 qq_36048429 的回复:楼主明白了吗？应该不难，〖前提是我没看错什么〗  不明白，头都爆了，新手勿喷

user: user-3
content: 楼主明白了吗？应该不难，〖前提是我没看错什么〗

user: user-4
content: 引用 5 楼 cbaggdd66的回复:[quote=引用 1 楼 user-4 的回复:] 二给指针就是指向一级指针的指针  s=&t 就是取t的地址，t是一个一级指针，&t得到一个二级指针  不用&类型不同竟然会报错，一个是int*，一个是int** 不同类型的两个地址是不是不能相互赋值，还是用&就可以随便赋值？[/quote] 是的，1楼已经说了，二级指针就是指向一级指针的指针

user: user-0
content: 引用 1 楼 user-4 的回复:二给指针就是指向一级指针的指针  s=&t 就是取t的地址，t是一个一级指针，&t得到一个二级指针  不用&类型不同竟然会报错，一个是int*，一个是int** 不同类型的两个地址是不是不能相互赋值，还是用&就可以随便赋值？

user: user-0
content: 引用 1 楼 user-4 的回复:二给指针就是指向一级指针的指针  s=&t 就是取t的地址，t是一个一级指针，&t得到一个二级指针  不用&类型不同竟然会报错，一个是int*，一个是int**   那s=&t中的s代表的是什么？&t不是得到t的地址？然后付给s？