user-0 提问: C语言小问题

回复:
user: user-1
content: 引用你只要记住数组与指针的关系（这里t相当于数组，不过数组名不可以++，但可以+i，t可以++）：*t就是t[0],*(t+1)就是t[1],*(t+i)就是t[i]，t作为首地址一般要保留着，假设TreeNode** p=t;在for里面每次p++以后,*p==*(t+1)==t[1],再p++后，*p==*(t+2)==t[2]，一直到*p==*(t+5)==t[5]，当然for里面用t++也可以。  p=t，p++以后，p==t+1,*p==*(t+1)==t[1] (*t)++什么意思呢，就是t[0]++，因为t[0]指向一个TreeNode结点，t[0]++相当于在一个结点内偏移一个指针位置，（*t）->m_Number=i+1;就是t[0]->m_Number=i+1;造成结构体套用错误，t[0]->m_Number指向的已经不是m_Number成员了，而是偏移后m_Number那么大内存里面的值。

user: user-2
content: 引用 楼主 u011488256 的回复:*t=(TreeNode*)malloc(sizeof(TreeNode)*6); 	// 下面这个问题还没有搞清楚 	for (int i=0;i<6;i++) 	{ 		t[i]->m_Number=i+1; 	}  这段程序自己调试 其中t 定义的是**t 但是在循环里面每次到t【2】的时候程序就死了 不知道怎么回事 球赐教 谢谢  如果t的定义是**t的话，那t就是数组arr的地址了，即*t = t[0] = arr，假设这个数组arr的长度是len，则有t[1] = arr+len，t[2] = arr+2*len，所以你的数组下标越界了哈 如果lz想要实现的是，用malloc出来的一个指针数组，用这些指针来控制实体对象，可以这样：  T** arrayOfPointers = (T**)malloc(sizeof(T*) * N);//先申请N个指针的空间 int i; for(i = 0; i < N; ++i){     arrayOfPointers[i] = (T*)malloc(sizeof(T));//给每一个指针malloc一个控制的对象 } //然后就可以通过这些指针来控制malloc出来的对象了，就像你写的那样 for(i = 0; i < N; ++i){     arrayOfPointers[i]->m_Number = i+1; }  //do something else  //最后，释放malloc申请的内存的时候也要注意，先释放为每个指针malloc的对象，再释放malloc出来的指针 for(i = 0; i < N; ++i){     free(arrayOfPointers[i]);//释放每一个指针指向的，malloc出来的对象 } free(arrayOfPointer);//释放malloc出来的N个指针

user: user-3
content: 你要么改成这样试试看t=(TreeNode**)malloc(sizeof(TreeNode*)); *t=(TreeNode*)malloc(sizeof(TreeNode)*6); for (int i=0;i<6;i++) {     (*t)[i].m_Number=i+1; }总之每一级指针都要初始化，不论是t还是*t,至于(*t)[i]表示的是一个对象了，所以要用.而不是->。你自己画一幅图，好好理解下吧。

user: user-4
content: 其实电脑开机后物理内存的每个字节都是可读写的，区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页，一页通常为4KB。

user: user-1
content: 引用 16 楼 u011488256 的回复:[quote=引用 14 楼 u010165006 的回复:] [quote=引用 10 楼 u011488256 的回复:]   [quote=引用 7 楼 u010165006 的回复:] [quote=引用 5 楼 u011488256 的回复:] 我  [quote=引用 4 楼 u010165006 的回复:] 是不是这样； TreeNode *t; t=(TreeNode*)malloc(sizeof(TreeNode)*6); 或者； TreeNode *t=(TreeNode*)malloc(sizeof(TreeNode)*6);   我用的是  TreeNode **t           *t=(TreeNode*)malloc(sizeof(TreeNode)*6); for (int i=0;i<6;i++) { t[i]->m_Number=i+1; }[/quote] 你给*t=赋值之前，先给t=赋值了吗？t首先应该是指向一个指针数组（数组的每个元素都是指针），然后给每个元素分别赋值，指向一个分配的结构体，单给*t=赋值只是相当于只对t[0]赋值。[/quote]  t 怎么变成指向一个数组的指针啊。我这里定义的就是一个普通的指向指针的指针[/quote] 2楼的： TreeNode** t=(TreeNode**)malloc(sizeof(TreeNode*)*6); 不就是吗？相当于t指向一个指针数组，*6是6个元素,sizeof(TreeNode*)是每个元素的大小，每个元素的类型是TreeNode*，t的类型是TreeNode**。每个元素还要指向一个分配的TreeNode。每个元素t[i]因为是指针，所以用t[i]->访问成员变量。[/quote]   你们说的我都理解了 但是我还有疑惑是： 一开始我发的代码为什么到t【2】，他才开始报错？ t【1】以后我调试 他都是正常按照我的思维运行的      后来我吧代码改了一下 for (int i=0;i<6;i++，（*t）++) { （*t）->m_Number=i+1; }  这样运行还是错的，是不是应该理解为我这个（*t）++应该是t所指向的指针数组的第一个元素的地址值在自己+1， 应该是这样的吧 我去··[/quote] 你只要记住数组与指针的关系（这里t相当于数组，不过数组名不可以++，但可以+i，t可以++）：*t就是t[0],*(t+1)就是t[1],*(t+i)就是t[i]，t作为首地址一般要保留着，假设TreeNode** p=t;在for里面每次p++以后,*p==*(t+1)==t[1],再p++后，*p==*(t+2)==t[2]，一直到*p==*(t+5)==t[5]，当然for里面用t++也可以。

user: user-3
content: 即便是你这样想，抛开t的一级指针赋值不谈。用数组做模型的话（方便理解点） *t=(TreeNode*)malloc(sizeof(TreeNode)*6); *t才指向了一个容量为6数组，那么(*t)[i]才是指向具体的单独一个节点吧。

user: user-3
content: 引用 10 楼 u011488256 的回复:  t 怎么变成指向一个数组的指针啊。我这里定义的就是一个普通的指向指针的指针 为什么就不能好好看看，我在2楼写的内容呢？你分配6个，就是模拟一个数组的形式嘛，理解的模型不一样罢了。数组本身就是类似指针的形式，指向数组的指针，就是指向指针的指针。就好比正方形是矩形的一个特例而已，不必死缠这些细节。

user: user-5
content: 对头，t[2]根本没有数据，你应该这样解引用(*t)[2],这样就是你的意图了

user: user-0
content: 引用 14 楼 u010165006 的回复:[quote=引用 10 楼 u011488256 的回复:]   [quote=引用 7 楼 u010165006 的回复:] [quote=引用 5 楼 u011488256 的回复:] 我  [quote=引用 4 楼 u010165006 的回复:] 是不是这样； TreeNode *t; t=(TreeNode*)malloc(sizeof(TreeNode)*6); 或者； TreeNode *t=(TreeNode*)malloc(sizeof(TreeNode)*6);   我用的是  TreeNode **t           *t=(TreeNode*)malloc(sizeof(TreeNode)*6); for (int i=0;i<6;i++) { t[i]->m_Number=i+1; }[/quote] 你给*t=赋值之前，先给t=赋值了吗？t首先应该是指向一个指针数组（数组的每个元素都是指针），然后给每个元素分别赋值，指向一个分配的结构体，单给*t=赋值只是相当于只对t[0]赋值。[/quote]  t 怎么变成指向一个数组的指针啊。我这里定义的就是一个普通的指向指针的指针[/quote] 2楼的： TreeNode** t=(TreeNode**)malloc(sizeof(TreeNode*)*6); 不就是吗？相当于t指向一个指针数组，*6是6个元素,sizeof(TreeNode*)是每个元素的大小，每个元素的类型是TreeNode*，t的类型是TreeNode**。每个元素还要指向一个分配的TreeNode。每个元素t[i]因为是指针，所以用t[i]->访问成员变量。[/quote]   你们说的我都理解了 但是我还有疑惑是： 一开始我发的代码为什么到t【2】，他才开始报错？ t【1】以后我调试 他都是正常按照我的思维运行的      后来我吧代码改了一下 for (int i=0;i<6;i++，（*t）++) { （*t）->m_Number=i+1; }  这样运行还是错的，是不是应该理解为我这个（*t）++应该是t所指向的指针数组的第一个元素的地址值在自己+1， 应该是这样的吧 我去··

user: user-0
content: 引用 12 楼 Adol1111 的回复:即便是你这样想，抛开t的一级指针赋值不谈。用数组做模型的话（方便理解点） *t=(TreeNode*)malloc(sizeof(TreeNode)*6); *t才指向了一个容量为6数组，那么(*t)[i]才是指向具体的单独一个节点吧。  你好 如上所说  *t才指向了一个容量为6的Treenode类型的数组，那按照你的意思t【2】应该根本没有指向对吧？因为t【2】应该是t所指向数组指针的第3个元素，但是t还没有指向任何东西。    我一直认为定义了**t后， *t指向一个东西，那么t自然就是指向*t的

user: user-1
content: 引用 10 楼 u011488256 的回复:  [quote=引用 7 楼 u010165006 的回复:] [quote=引用 5 楼 u011488256 的回复:] 我  [quote=引用 4 楼 u010165006 的回复:] 是不是这样； TreeNode *t; t=(TreeNode*)malloc(sizeof(TreeNode)*6); 或者； TreeNode *t=(TreeNode*)malloc(sizeof(TreeNode)*6);   我用的是  TreeNode **t           *t=(TreeNode*)malloc(sizeof(TreeNode)*6); for (int i=0;i<6;i++) { t[i]->m_Number=i+1; }[/quote] 你给*t=赋值之前，先给t=赋值了吗？t首先应该是指向一个指针数组（数组的每个元素都是指针），然后给每个元素分别赋值，指向一个分配的结构体，单给*t=赋值只是相当于只对t[0]赋值。[/quote]  t 怎么变成指向一个数组的指针啊。我这里定义的就是一个普通的指向指针的指针[/quote] 2楼的： TreeNode** t=(TreeNode**)malloc(sizeof(TreeNode*)*6); 不就是吗？相当于t指向一个指针数组，*6是6个元素,sizeof(TreeNode*)是每个元素的大小，每个元素的类型是TreeNode*，t的类型是TreeNode**。每个元素还要指向一个分配的TreeNode。每个元素t[i]因为是指针，所以用t[i]->访问成员变量。

user: user-6
content: TreeNode* x; //t要正确初始化 TreeNode**t = &x; *t =(TreeNode*)malloc(sizeof(TreeNode)*6); // 下面这个问题还没有搞清楚 for (int i=0;i<6;i++) {   (*t)[i].m_Number=i+1; }

user: user-4
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语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “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-3
content: 引用 15 楼 u011488256 的回复:[quote=引用 12 楼 Adol1111 的回复:] 即便是你这样想，抛开t的一级指针赋值不谈。用数组做模型的话（方便理解点） *t=(TreeNode*)malloc(sizeof(TreeNode)*6); *t才指向了一个容量为6数组，那么(*t)[i]才是指向具体的单独一个节点吧。  你好 如上所说  *t才指向了一个容量为6的Treenode类型的数组，那按照你的意思t【2】应该根本没有指向对吧？因为t【2】应该是t所指向数组指针的第3个元素，但是t还没有指向任何东西。    我一直认为定义了**t后， *t指向一个东西，那么t自然就是指向*t的[/quote] ...这是不可能的，任何指针都是一级级下来的，你没有指名他的指向，谁知道你是如何分配的？系统不会擅自帮你做决定。我写了3种，其中2种是二维指针，都是一级级分配的，你好好看看吧。你用指针的时候，最好能画个图，分清楚到底是谁指向谁。指向的是一个元素，还是一个数组什么的。总之，先确定一级的指针，然后再确定二级的，一步步来，不要跳步。

user: user-1
content: 是不是这样； TreeNode *t; t=(TreeNode*)malloc(sizeof(TreeNode)*6); 或者； TreeNode *t=(TreeNode*)malloc(sizeof(TreeNode)*6);

user: user-7
content: t的申明贴出来看看！ t=2 挂了，可能越界访问了

user: user-4
content: 仅供参考//在堆中开辟一个4×5的二维int数组 #include <stdio.h> #include <malloc.h> int **p; int i,j; void main() {     p=(int **)malloc(4*sizeof(int *));     if (NULL==p) return;     for (i=0;i<4;i++) {         p[i]=(int *)malloc(5*sizeof(int));         if (NULL==p[i]) return;     }     for (i=0;i<4;i++) {         for (j=0;j<5;j++) {             p[i][j]=i*5+j;         }     }     for (i=0;i<4;i++) {         for (j=0;j<5;j++) {             printf(" %2d",p[i][j]);         }         printf("\n");     }     for (i=0;i<4;i++) {         free(p[i]);     }     free(p); } //  0  1  2  3  4 //  5  6  7  8  9 // 10 11 12 13 14 // 15 16 17 18 19

user: user-0
content: 引用 7 楼 u010165006 的回复:[quote=引用 5 楼 u011488256 的回复:] 我  [quote=引用 4 楼 u010165006 的回复:] 是不是这样； TreeNode *t; t=(TreeNode*)malloc(sizeof(TreeNode)*6); 或者； TreeNode *t=(TreeNode*)malloc(sizeof(TreeNode)*6);   我用的是  TreeNode **t           *t=(TreeNode*)malloc(sizeof(TreeNode)*6); for (int i=0;i<6;i++) { t[i]->m_Number=i+1; }[/quote] 你给*t=赋值之前，先给t=赋值了吗？t首先应该是指向一个指针数组（数组的每个元素都是指针），然后给每个元素分别赋值，指向一个分配的结构体，单给*t=赋值只是相当于只对t[0]赋值。[/quote]  t 怎么变成指向一个数组的指针啊。我这里定义的就是一个普通的指向指针的指针

user: user-8
content: 非法读写内存

user: user-3
content: 你的指针定义有问题，改成这两种：//版本1 TreeNode* t=(TreeNode*)malloc(sizeof(TreeNode)*6); for (int i=0;i<6;i++) {     t[i].m_Number=i+1; }  //版本2 TreeNode** t=(TreeNode**)malloc(sizeof(TreeNode*)*6); for (int i=0;i<6;i++) {     t[i]=(TreeNode*)malloc(sizeof(TreeNode));     t[i]->m_Number=i+1; }如果是二维指针，需要初始化2次，第一次是声明指针数组的形式，第二次才是指向一个指向TreeNode元素的指针