[1] [2]的原型是这样的:int ** a?

时间:2011-04-13 02:28:16

标签: c

a[1][2]由编译器扩展,如下所示:*( *(a+1) +2 )。因此,如果a有这样的原型:int **a

上述表达应该像这样解释:

  1. 从符号表中获取a的地址。注意它是a指针 指针

  2. 现在我们按1添加它,然后它指向旁边的某处  a指向的地方。

  3. 然后我们取消引用它。我认为这是未定义的行为,  因为我们不知道a+1是否有效,我们可以随意访问它。

  4. 好的,如果我们足够幸运,我们成功获得了价值  *(a+1)。我们通过2添加此内容。

  5. 完成此步骤后,我们取消引用(*(a+1) +2 )。我们现在幸运吗?

  6. 我在第10章中的专家C编程中读到了这一点。它是否正确?

2 个答案:

答案 0 :(得分:3)

编辑问题之后的新答案:

要使a[1][2]有效,假定a定义为int **a;,则这两者都必须为真:

  • a必须指向两个连续int *个对象中的第一个;
  • 这些int *个对象中的第二个必须指向三个连续int个对象中的第一个。

安排这个的最简单方法是:

int x[3];
int *y[2] = { 0, x };
int **a = y;

原始答案:

如果表达式a[1][2]有效,那么a的类型有很多不同的可能性(甚至忽略const之类的限定词:

  1. type **a;(指向 type 的指针)
  2. type *a[n];(指向 type 的n个指针数组)
  3. type (*a)[n];(指向n type 的数组的指针)
  4. type a[m][n];(n type 的m个数组的数组)
  5. 确切地说,如何评估表达式取决于a实际上具有哪种类型。

    首先计算a + 1。如果a本身是指针(情况1或情况3),则直接加载a的值。如果a是一个数组(情况2或情况4),则加载a的第一个元素的地址(与a本身的地址相同)。

    此指针现在由它指向的类型的1个对象偏移。在情况1和情况2中,它将被1“指向 type ”对象的指针偏移;在案例3和案例4中,它将被1“n type ”对象的数组偏移,这与n 类型对象的设置相同。

    现在取消引用计算的(偏移)指针。在情况1和2中,结果具有类型“指向类型的指针”,在情况3和4中,结果具有类型“n type ”的数组。

    计算下一个*(a + 1) + 2。与第一种情况一样,如果*(a + 1)是指针,则直接使用该值(此时,情况1和2)。如果*(a + 1)是一个数组(情况3和4),则采用该数组的第一个元素的地址。

    结果指针(此时始终具有类型“指向 type 的指针”)现在由2个类型对象偏移。现在解除引用最终偏移量指针,并检索类型对象。

答案 1 :(得分:0)

假设a的定义如下所示:

int a[2][2] = {{1, 2}, {3, 4}};

以下是符号a的存储内容:

[ 1 ][ 2 ][ 3 ][ 4 ]

在C中,当您对指针执行算术运算时,指针值递增或递减的实际数量取决于存储在数组中的类型的大小。 a的第一个维度中包含的类型是int[2],因此当我们要求C计算指针值(a + 1)时,它会获取a命名的位置并递增它通过int[2]的大小,这导致指针指向包含整数值[3]的内存位置。所以是的,当你取消引用这个指针然后向它添加2时,结果就是整数值5.当你试图取消引用那个整数值时,它就没有意义了。

现在让我们说数组包含指针:

char const * one = "one",
             two = "two",
             three = "three",
             four = "four";
char const * a[2][2] = {{one, two}, {three, four}};

将1添加到a然后取消引用它,并获得引用字符串“three”的char指针。添加两个,你会得到一个指针,指向一个现在较短的字符串“ree”。取消引用,你得到char值'r',但只有纯粹的运气才能避免内存保护错误。