#include <stdio.h>
#include <string.h>
int main(void)
{
int arr2d[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
int* arr = (int*)arr2d;
int i = 0;
for (i = 0; i < 9; i++)
{
printf("%d ", arr[i]);
}
printf("nn");
int arr1[] = { 11,12 };
int arr2[] = {13, 14, 15, 16};
int arr3[] = { 17, 18, 19 };
int * parr[3] = { arr1,arr2,arr3 };
int *parr1 = (int*)parr;
for (i = 0; i < 9; i++)
{
printf("%d ", parr1[i]);
}
return 0;
一开始我从二维数组转换并打印出来,但之后我用指针数组做了,它不起作用,有人可以解释一下吗?
您可能希望了解这些对象在内存中的布局方式:
int array[][3] = { {1,2,3}, {4,5,6}, {7,8,9} };
int *p_array = (int *) array;
这会在内存(在本例中为堆栈)中创建类型为int[][3]
类型的对象array
,该对象以假设的(16 位字大小)体系结构物理布局为:
array 0x8000: 0x0001
0x8002: 0x0002
0x8004: 0x0003
0x8006: 0x0004
0x8008: 0x0005
0x800A: 0x0006
0x800C: 0x0007
0x800E: 0x0008
0x8010: 0x0009
p_array 0x8012: 0x8000
其中0x8000
表示array
的假想堆栈地址。
但是,在第二个示例中:
int array1[] = { 11, 12 };
int array2[] = { 13, 14, 15, 16 };
int array3[] = { 17, 18, 19 };
int *array_pointers[] = { array1, array2, array3 };
int *array_pointers2 = (int*) array_pointers;
这里array_pointers
是类型int *[]
,这意味着它是指向int
s 数组的指针。内存布局如下所示:
array1 0x8000: 0x000B
0x8002: 0x000C
array2 0x8004: 0x000D
0x8006: 0x000E
0x8008: 0x000F
0x800A: 0x0010
array3 0x800C: 0x0011
0x800E: 0x0012
0x8010: 0x0013
和
array_pointers: 0x8012: 0x8000 address of array1
0x8014: 0x8004 address of array2
0x8016: 0x800C address of array3
array_pointers2: 0x8018: 0x8012 address of array_pointers
因此,当您尝试打印array_pointers2
的内容时,现在包含指向int
数组的指针,您将打印地址值而不是它们指向的数字。
下面是一个输出这些对象的内存地址的示例:
https://ideone.com/T52Ow0
哪些打印:
array 0x7ffeda682090: 0x00000000000001
0x7ffeda682094: 0x00000000000002
0x7ffeda682098: 0x00000000000003
0x7ffeda68209c: 0x00000000000004
0x7ffeda6820a0: 0x00000000000005
0x7ffeda6820a4: 0x00000000000006
0x7ffeda6820a8: 0x00000000000007
0x7ffeda6820ac: 0x00000000000008
0x7ffeda6820b0: 0x00000000000009
p_array 0x7ffeda682038: 0x007ffeda682090
array1 0x7ffeda68204c: 0x0000000000000b
0x7ffeda682050: 0x0000000000000c
array2 0x7ffeda682060: 0x0000000000000d
0x7ffeda682064: 0x0000000000000e
0x7ffeda682068: 0x0000000000000f
0x7ffeda68206c: 0x00000000000010
array3 0x7ffeda682054: 0x00000000000011
0x7ffeda682058: 0x00000000000012
0x7ffeda68205c: 0x00000000000013
array_poin 0x7ffeda682070: 0x007ffeda68204c
0x7ffeda682078: 0x007ffeda682060
0x7ffeda682080: 0x007ffeda682054
array_poi2 0x7ffeda682040: 0x007ffeda682070
在我的电脑上。
外部链接过期时的源代码:
#include <stdio.h>
#include <string.h>
int main(void)
{
int array[][3] = { {1,2,3}, {4,5,6}, {7,8,9} };
int *p_array = (int*) array;
for (int i = 0; i < 9; i++) {
printf("%-10s %08p: %016pn", i == 0 ? "array" : "", &p_array[i], p_array[i]);
}
printf("%-10s %08p: %016pn", "p_array", &p_array, p_array);
int array1[] = { 11, 12 };
int array2[] = { 13, 14, 15, 16 };
int array3[] = { 17, 18, 19 };
int *array_pointers[] = { array1, array2, array3 };
int *array_pointers2 = (int*) array_pointers;
putchar('n');
for (int i = 0; i < sizeof(array1) / sizeof(array1[0]); i++) {
printf("%-10s %08p: %016pn", i == 0 ? "array1" : "", &array1[i], array1[i]);
}
for (int i = 0; i < sizeof(array2) / sizeof(array2[0]); i++) {
printf("%-10s %08p: %016pn", i == 0 ? "array2" : "", &array2[i], array2[i]);
}
for (int i = 0; i < sizeof(array3) / sizeof(array3[0]); i++) {
printf("%-10s %08p: %016pn", i == 0 ? "array3" : "", &array3[i], array3[i]);
}
for (int i = 0; i < sizeof(array_pointers) / sizeof(array_pointers[0]); i++) {
printf("%-10s %08p: %016pn", i == 0 ? "array_poin" : "", &array_pointers[i], array_pointers[i]);
}
printf("%-10s %08p: %016pn", "array_poi2", &array_pointers2, array_pointers2);
return 0;
}
您不能简单地将int *
与从 0 到 N 的单个循环一起使用,就像处理连续的整数数组一样,例如arr2d
因为:
- 指针在内存中可能相距很远
- 你需要取消引用这些指针中的每一个,你不能用
int *
这样做,因为int *
会A[i]
解释为int
,而不是指针。
要了解如何修复它,您可能需要了解事物在内存中的布局方式。 让我们从一个简单的开始:您的arr2d
声明。 假设一个 2 字节的int
,下面是它的外观:
arr2d @ 0x8000
=======================
| arr2d[0] @ 0x8000 |
| ----------------- |
| | 1 2 3 | |
| ----------------- |
| @8000 @8002 @8004 |
| |
| arr2d[1] @ 0x8006 |
| ----------------- |
| | 4 5 6 | |
| ----------------- |
| @8006 @8008 @800A |
| |
| arr2d[0] @ 0x800C |
| ----------------- |
| | 7 8 9 | |
| ----------------- |
| @800C @800E @8010 |
=======================
注意到从一个项目到下一个项目的内存地址是如何相隔 2 个字节的吗? 这就是为什么您可以执行int* arr = (int*)arr2d
并打印arr[i]
以获取所需值的原因之一。 另一个原因是您正在存储整数。
现在让我们看看parr
和arr1
、arr2
和arr3
:
arr1 @ 0xA000
----------
| 11 12 |
----------
@A000 @A002
arr2 @ 0xB000
-------------------------
| 13 14 15 16 |
-------------------------
@B000 @B002 @B004 @B006
arr3 @ 0xC000
------------------
| 17 18 19 |
------------------
@C000 @C002 @C004
parr @ 0xE000
------------------------
| @A000 @B000 @C000 |
| (arr1) (arr2) (arr3) |
------------------------
@E000 @E004 @E008
还记得我说过的arr2d
存储整数吗? 好吧,parr
存储指针,所以事情的工作方式有点不同。 首先,您需要使用*
运算符取消引用指针,但您使用的是int *parr1
,因此parr1[i]
会导致指针被错误地解释为整数。 另请注意,每个数组中整数的地址增加 2,而指针的地址 (@E000..@E008)增加4。 换句话说,您将 4 字节指针解释为 2 字节整数,如果您的系统对int
和int *
使用不同的大小,这可能会使您的问题变得更糟。 如果您声明int **parr1 = parr
并使用*parr1[i]
进行打印,情况会好得多。
但是,这将仅打印每个数组中的第一个值。 这是因为您存储了指向每个数组中第一项的指针(因为数组衰减将arr1
变成&arr1[0]
,arr2
变成&arr2[0]
,arr3
变成&arr3[0]
)。 指针没有元素计数,因为它们不是数组,并且由于您存储的是指向单个int
的指针而不是指向数组的指针,因此无论如何您都会有效地删除元素计数。 您需要自己跟踪每个数组的元素计数,也许在另一个数组中。 下面是一些修改后的代码,可以解决您的问题:
// Only works for real arrays, not pointers returned by malloc/calloc.
#define ARRAY_COUNT(a) (sizeof (a) / sizeof (a)[0])
int arr1[] = { 11,12 };
int arr2[] = {13, 14, 15, 16};
int arr3[] = { 17, 18, 19 };
int * parr[3] = { arr1,arr2,arr3 };
int **parr1 = (int*)parr;
int counts[] = { ARRAY_COUNT(arr1), ARRAY_COUNT(arr2), ARRAY_COUNT(arr3) };
for (i = 0; i < ARRAY_COUNT(counts); i++)
{
for (j = 0; j < counts[i]; j++)
{
printf("%d ", parr1[i][j]);
}
}
请注意,我使用了两个循环:1 用于计数,1 用于每个数组的内容。如果你真的想要,你可以合并两个循环,但遵循逻辑有点困难:
i = 0;
j = 0;
while (i < ARRAY_COUNT(counts))
{
if (j < counts[i]) {
printf("%d ", parr1[i][j]);
j++;
} else {
i++;
j = 0;
}
}