关于双维和三维 pointers/double 维数组
Regarding double and triple pointers/double dimension arrays
所以,我一直在玩 C 指针和指针算法,因为我对它们并不完全满意。我想出了这个代码。
char* a[5] = { "Hi", "My", "Name", "Is" , "Dennis"};
char** aPtr = a; // This is acceptable because 'a' is double pointer
char*** aPtr2 = &aPtr; // This is also acceptable because they are triple pointers
//char ***aPtr2 = &a // This is not acceptable according to gcc 4.8.3, why ?
//This is the rest of the code, the side notes are only for checking
printf("%s\n",a[0]); //Prints Hi
printf("%s\n",a[1]); //Prints My
printf("%s\n",a[2]); //Prints Name
printf("%s\n",a[3]); //Prints Is
printf("%s\n",a[4]); //Prints Dennis
printf("%s\n",*(a+0)); //Prints Hi
printf("%s\n",*(a+1)); //Prints My
printf("%s\n",*(a+2)); //Prints Name
printf("%s\n",*(a+3)); //Prints Is
printf("%s\n",*(a+4)); //Prints Dennis
printf("%s\n",*(*(aPtr2) +0)); //Prints Hi
printf("%s\n",*(*(aPtr2) +1)); //Prints My // ap = a, *ap = *a, *(ap)+1 = *a+1 ?
printf("%s\n",*(*(aPtr2) +2)); //Prints Name
printf("%s\n",*(*(aPtr2) +3)); //Prints Is
printf("%s\n",*(*(aPtr2) +4)); //Prints Dennis
char*** aPtr2 = &a
根据 gcc 4.8.3 是不可接受的,为什么?
抱歉忘记添加编译器警告:
warning: initialization from incompatible pointer type [enabled by default]
可能不清楚我想说什么,所以我不得不添加这个链接:
- 这是有效的代码:http://ideone.com/4ePj4h。 (第 7 行。注释掉)
- 这是无效的代码:http://ideone.com/KMG7OS。 (第 6 行。注释掉)
注意注释掉的行。
a
是 5 个指针的缓冲区的地址并且是不可变的(即它是一个固定的指针)。如果你允许
char ***aPtr2 = &a;
然后
*aPtr2 = &a[3];
实际上会修改地址 a
(这是禁止的)。
这来自 C 处理数组和地址的方式:
int a[5];
a
是 int * const
类型,true,这意味着您可以在需要指针的地方使用它。但是,在堆栈上未分配指针的 space,只有五个整数的 space。含义 a
与 &a[0]
相同。这都是预料之中的,但奇怪的部分来了:
a
等同于 &a
。这是因为指针没有存储在任何地方,您无法获取它的地址。但是 C 标准并没有使编译失败,而是说它们是相同的,所以一些算法会起作用。
但是,由于您正在执行 char ***aPtr2 = &a;
,您实际上是在执行 char ***aPtr2 = a;
,这就是您出现段错误的原因。只是双指针,不是三指针。
您可以检查调试器中的所有值以更清楚地查看它,或者 运行 一个程序,例如:
#include <stdio.h>
int main(void)
{
char *a[5] = { "Hi", "My", "Name", "Is" , "Dennis"};
char **aPtr = a;
char ***aPtr2 = &aPtr;
char ***aPtr3 = &a;
printf("%p %c\n", a, *a);
printf("%p %p %c\n", aPtr, *aPtr, **aPtr);
printf("%p %p %p %c\n", aPtr2, *aPtr2, **aPtr2, ***aPtr2);
printf("%p %p %c\n", aPtr3, *aPtr3, **aPtr3);
return 0;
}
产生输出:
0xfff65578 H
0xfff65578 0x8048648 H
0xfff65574 0xfff65578 0x8048648 H
0xfff65578 0x8048648 H
编辑:另一个有趣的事情是函数指针以相同的方式处理。 &func
等同于 func
.
int add(int a, int b) { return a + b; }
typedef int (*PFUNC)(int, int);
PFUNC p1 = add;
PFUNC p2 = &add;
if (p1 == p2)
printf("Huh. %d, %d\n", (*p1)(1,2), p2(3, 4)); // the dereference is also optional
所以,我一直在玩 C 指针和指针算法,因为我对它们并不完全满意。我想出了这个代码。
char* a[5] = { "Hi", "My", "Name", "Is" , "Dennis"};
char** aPtr = a; // This is acceptable because 'a' is double pointer
char*** aPtr2 = &aPtr; // This is also acceptable because they are triple pointers
//char ***aPtr2 = &a // This is not acceptable according to gcc 4.8.3, why ?
//This is the rest of the code, the side notes are only for checking
printf("%s\n",a[0]); //Prints Hi
printf("%s\n",a[1]); //Prints My
printf("%s\n",a[2]); //Prints Name
printf("%s\n",a[3]); //Prints Is
printf("%s\n",a[4]); //Prints Dennis
printf("%s\n",*(a+0)); //Prints Hi
printf("%s\n",*(a+1)); //Prints My
printf("%s\n",*(a+2)); //Prints Name
printf("%s\n",*(a+3)); //Prints Is
printf("%s\n",*(a+4)); //Prints Dennis
printf("%s\n",*(*(aPtr2) +0)); //Prints Hi
printf("%s\n",*(*(aPtr2) +1)); //Prints My // ap = a, *ap = *a, *(ap)+1 = *a+1 ?
printf("%s\n",*(*(aPtr2) +2)); //Prints Name
printf("%s\n",*(*(aPtr2) +3)); //Prints Is
printf("%s\n",*(*(aPtr2) +4)); //Prints Dennis
char*** aPtr2 = &a
根据 gcc 4.8.3 是不可接受的,为什么?
抱歉忘记添加编译器警告:
warning: initialization from incompatible pointer type [enabled by default]
可能不清楚我想说什么,所以我不得不添加这个链接:
- 这是有效的代码:http://ideone.com/4ePj4h。 (第 7 行。注释掉)
- 这是无效的代码:http://ideone.com/KMG7OS。 (第 6 行。注释掉)
注意注释掉的行。
a
是 5 个指针的缓冲区的地址并且是不可变的(即它是一个固定的指针)。如果你允许
char ***aPtr2 = &a;
然后
*aPtr2 = &a[3];
实际上会修改地址 a
(这是禁止的)。
这来自 C 处理数组和地址的方式:
int a[5];
a
是 int * const
类型,true,这意味着您可以在需要指针的地方使用它。但是,在堆栈上未分配指针的 space,只有五个整数的 space。含义 a
与 &a[0]
相同。这都是预料之中的,但奇怪的部分来了:
a
等同于 &a
。这是因为指针没有存储在任何地方,您无法获取它的地址。但是 C 标准并没有使编译失败,而是说它们是相同的,所以一些算法会起作用。
但是,由于您正在执行 char ***aPtr2 = &a;
,您实际上是在执行 char ***aPtr2 = a;
,这就是您出现段错误的原因。只是双指针,不是三指针。
您可以检查调试器中的所有值以更清楚地查看它,或者 运行 一个程序,例如:
#include <stdio.h>
int main(void)
{
char *a[5] = { "Hi", "My", "Name", "Is" , "Dennis"};
char **aPtr = a;
char ***aPtr2 = &aPtr;
char ***aPtr3 = &a;
printf("%p %c\n", a, *a);
printf("%p %p %c\n", aPtr, *aPtr, **aPtr);
printf("%p %p %p %c\n", aPtr2, *aPtr2, **aPtr2, ***aPtr2);
printf("%p %p %c\n", aPtr3, *aPtr3, **aPtr3);
return 0;
}
产生输出:
0xfff65578 H
0xfff65578 0x8048648 H
0xfff65574 0xfff65578 0x8048648 H
0xfff65578 0x8048648 H
编辑:另一个有趣的事情是函数指针以相同的方式处理。 &func
等同于 func
.
int add(int a, int b) { return a + b; }
typedef int (*PFUNC)(int, int);
PFUNC p1 = add;
PFUNC p2 = &add;
if (p1 == p2)
printf("Huh. %d, %d\n", (*p1)(1,2), p2(3, 4)); // the dereference is also optional