user-0 提问: 求详细代码注释

回复:
user: user-1
content: nt arr[m][n], arr[i][j] = arr+((i*n)+j)*sizeof(int); int **arr; ... arr[i][j]=arr+sizeof(int*)*i+sizeof(int)*j

user: user-2
content: 这就是它的内存模型

user: user-0
content: 引用 4 楼 自信男孩 的回复:*(*(ptr + i) + j)等价ptr[i][j]，因此*(ptr + i) + j等价&ptr[i][j]  ptr + i即ptr的地址向后偏移i * sizeof(int **)个字节。通过打印可以看出楼主的编译器是64位的，因为每次偏移8个字节，即sizeof(int **)是8；对于这句定论楼主可以再验证一下，使用sizeof(long)输出一下值。  *(ptr+i)即ptr[i]是第i行的首地址。*(ptr+i)因为每行是2个元素（两列），因此ptr[i]每次偏移2 * sizeof(int)个字节。但是这个地方不知道为什么是偏移32个字节，我这里怀疑是申请时故意多给了16个字节。 谢谢请问为什么ptr+0和*(ptr+0)和后面的ptr+1和*(ptr+`1)没有关系

user: user-2
content: 引用 4 楼 自信男孩 的回复:*(*(ptr + i) + j)等价ptr[i][j]，因此*(ptr + i) + j等价&ptr[i][j]  ptr + i即ptr的地址向后偏移i * sizeof(int **)个字节。通过打印可以看出楼主的编译器是64位的，因为每次偏移8个字节，即sizeof(int **)是8；对于这句定论楼主可以再验证一下，使用sizeof(long)输出一下值。  *(ptr+i)即ptr[i]是第i行的首地址。*(ptr+i)因为每行是2个元素（两列），因此ptr[i]每次偏移2 * sizeof(int)个字节。但是这个地方不知道为什么是偏移32个字节，我这里怀疑是申请时故意多给了16个字节。 就好比 int *a,*b; a= new int[2]; b=new int[2]; a和b 差16也好，差32也好，都是可能的

user: user-2
content: 每行一个指针，彼此没有关系。相当于一个数组，每个元素都是一个指针，每个指针各自有其开辟的时机，没必要连续。。。

user: user-3
content: *(*(ptr + i) + j)等价ptr[i][j]，因此*(ptr + i) + j等价&ptr[i][j]  ptr + i即ptr的地址向后偏移i * sizeof(int **)个字节。通过打印可以看出楼主的编译器是64位的，因为每次偏移8个字节，即sizeof(int **)是8；对于这句定论楼主可以再验证一下，使用sizeof(long)输出一下值。  *(ptr+i)即ptr[i]是第i行的首地址。*(ptr+i)因为每行是2个元素（两列），因此ptr[i]每次偏移2 * sizeof(int)个字节。但是这个地方不知道为什么是偏移32个字节，我这里怀疑是申请时故意多给了16个字节。

user: user-2
content: 我觉得我说的已经比较清楚了，如果你不明白，请把你不明白的具体那一行代码说出来，而不是让我从头讲起，就好比初中数学老师上课不会讲加减乘除。

user: user-0
content: 引用 1 楼 真相重于对错 的回复:ptr是二级指针，他的数据是连续的4个指针，每个指针指向一个包含连续的2个int的地址。老哥具体点啊

user: user-2
content: ptr是二级指针，他的数据是连续的4个指针，每个指针指向一个包含连续的2个int的地址。

user: user-2
content: int arr[m][n], arr[i][j] = arr+((i*n)+j)*sizeof(int); int **arr; ... arr[i][j]=arr+sizeof(int*)*i+sizeof(int)*j

user: user-2
content: 你说的是差32,不可理解,对吧? 那么我这写,你觉得差多少呢？   int** arr = new int[2];     arr[0] = new int[10];     arr[1] = new int[20];  再说你说要在栈动态申请，你不怕破坏栈吗？

user: user-3
content: 引用 14 楼 真相重于对错 的回复:[quote=引用 13 楼 自信男孩 的回复:] [quote=引用 10 楼 真相重于对错 的回复:] 这没有涉及到碎片的问题。 例如 int** aaa = new int*[2]; aaa[0]=new int[7];  //这里执行了另外操作。。 //比如  //又有开辟一个指针 int *x = new int[123]; //然后 aaa[1]=new int[6]; //那么aaa[0]和aaa[1],之间完全可以不连续 这种形式二级指针来模拟二维数组，不同于二维数组，二维数组是连续的，而这个部要求连续。。所以也不涉及碎片。。 是不要求连续，但是malloc/realloc也不是这一下，那里一下分配空间的，需要考虑分配空间的效率和一定规则～所以多分配的可以考虑其他方面。[/quote] 当然写程序，分配内存考虑碎片是肯定的，但是，就此情况来说，他们之间无论差多少都不是灵异事件。没必要大惊小怪。[/quote] 当然需要，这也是为了学习堆分配空间的方法。那么在栈上动态申请空间也是需要考虑。

user: user-2
content: 引用 13 楼 自信男孩 的回复:[quote=引用 10 楼 真相重于对错 的回复:] 这没有涉及到碎片的问题。 例如 int** aaa = new int*[2]; aaa[0]=new int[7];  //这里执行了另外操作。。 //比如  //又有开辟一个指针 int *x = new int[123]; //然后 aaa[1]=new int[6]; //那么aaa[0]和aaa[1],之间完全可以不连续 这种形式二级指针来模拟二维数组，不同于二维数组，二维数组是连续的，而这个部要求连续。。所以也不涉及碎片。。 是不要求连续，但是malloc/realloc也不是这一下，那里一下分配空间的，需要考虑分配空间的效率和一定规则～所以多分配的可以考虑其他方面。[/quote] 当然写程序，分配内存考虑碎片是肯定的，但是，就此情况来说，他们之间无论差多少都不是灵异事件。没必要大惊小怪。

user: user-3
content: 引用 10 楼 真相重于对错 的回复:这没有涉及到碎片的问题。 例如 int** aaa = new int*[2]; aaa[0]=new int[7];  //这里执行了另外操作。。 //比如  //又有开辟一个指针 int *x = new int[123]; //然后 aaa[1]=new int[6]; //那么aaa[0]和aaa[1],之间完全可以不连续 这种形式二级指针来模拟二维数组，不同于二维数组，二维数组是连续的，而这个部要求连续。。所以也不涉及碎片。。 是不要求连续，但是malloc/realloc也不是这一下，那里一下分配空间的，需要考虑分配空间的效率和一定规则～所以多分配的可以考虑其他方面。

user: user-2
content: 续上  for(int i=0;i<3;i++)   a[i]=new int[3];  a[2][1] = *(a+2)+1

user: user-2
content: 引用 9 楼 自信男孩 的回复:[quote=引用 6 楼 真相重于对错 的回复:] [quote=引用 4 楼 自信男孩 的回复:] *(*(ptr + i) + j)等价ptr[i][j]，因此*(ptr + i) + j等价&ptr[i][j]  ptr + i即ptr的地址向后偏移i * sizeof(int **)个字节。通过打印可以看出楼主的编译器是64位的，因为每次偏移8个字节，即sizeof(int **)是8；对于这句定论楼主可以再验证一下，使用sizeof(long)输出一下值。  *(ptr+i)即ptr[i]是第i行的首地址。*(ptr+i)因为每行是2个元素（两列），因此ptr[i]每次偏移2 * sizeof(int)个字节。但是这个地方不知道为什么是偏移32个字节，我这里怀疑是申请时故意多给了16个字节。 就好比 int *a,*b; a= new int[2]; b=new int[2]; a和b 差16也好，差32也好，都是可能的[/quote] 也要考虑多申请的情况，也可能是考虑碎片处理的。 堆上的空间一般也是顺序申请的，一般不会散乱的申请的，所以除非碎片，否则不会差16，差32的[/quote] int array[3][3] array[2][1] 相当于 array+sizeof(int)*2*3+1; 而 int **a  = new int*[3]；

user: user-2
content: 这没有涉及到碎片的问题。 例如 int** aaa = new int*[2]; aaa[0]=new int[7];  //这里执行了另外操作。。 //比如  //又有开辟一个指针 int *x = new int[123]; //然后 aaa[1]=new int[6]; //那么aaa[0]和aaa[1],之间完全可以不连续 这种形式二级指针来模拟二维数组，不同于二维数组，二维数组是连续的，而这个部要求连续。。所以也不涉及碎片。。

user: user-3
content: 引用 6 楼 真相重于对错 的回复:[quote=引用 4 楼 自信男孩 的回复:] *(*(ptr + i) + j)等价ptr[i][j]，因此*(ptr + i) + j等价&ptr[i][j]  ptr + i即ptr的地址向后偏移i * sizeof(int **)个字节。通过打印可以看出楼主的编译器是64位的，因为每次偏移8个字节，即sizeof(int **)是8；对于这句定论楼主可以再验证一下，使用sizeof(long)输出一下值。  *(ptr+i)即ptr[i]是第i行的首地址。*(ptr+i)因为每行是2个元素（两列），因此ptr[i]每次偏移2 * sizeof(int)个字节。但是这个地方不知道为什么是偏移32个字节，我这里怀疑是申请时故意多给了16个字节。 就好比 int *a,*b; a= new int[2]; b=new int[2]; a和b 差16也好，差32也好，都是可能的[/quote] 也要考虑多申请的情况，也可能是考虑碎片处理的。 堆上的空间一般也是顺序申请的，一般不会散乱的申请的，所以除非碎片，否则不会差16，差32的