指针算术和数组:什么是合法的?

时间:2010-03-05 00:52:34

标签: c arrays pointers pointer-arithmetic

考虑以下陈述:

int    *pFarr, *pVarr;

int    farr[3] = {11,22,33};
int    varr[3] = {7,8,9};

pFarr = &(farr[0]);
pVarr = varr;

在此阶段,两个指针都指向每个相应数组地址的开头。对于* pFarr,我们目前正在考虑11和* pVarr,7。

同样,如果我通过* farr和* varr请求每个数组的内容,我也会得到11和7。

到目前为止一切顺利。

现在,让我们试试pFarr++pVarr++。大。正如预期的那样,我们现在看22和8。

但现在......

尝试向上移动farr++varr++ ...我们得到“错误的参数类型以增加”。

现在,我认识到数组指针和常规指针之间的区别,但由于它们的行为相似,为什么会出现这种限制呢?

当我也考虑到在同一个程序中我可以用表面上正确的方式以另一种不正确的方式调用以下函数时,这让我更加困惑,并且我得到相同的行为,尽管与在上面张贴的代码!?

working_on_pointers ( pFarr, farr );  // calling with expected parameters
working_on_pointers ( farr, pFarr );  // calling with inverted parameters 

void working_on_pointers ( int *pExpect, int aExpect[] ) {

    printf("%i", *pExpect);  // displays the contents of pExpect ok
    printf("%i", *aExpect);  // displays the contents of aExpect ok

    pExpect++;               // no warnings or errors
    aExpect++;               // no warnings or errors

    printf("%i", *pExpect);  // displays the next element or an overflow element (with no errors)
    printf("%i", *aExpect);  // displays the next element or an overflow element (with no errors)

}

有人可以帮助我理解为什么数组指针和指针在某些情况下的行为方式相似,但在其他情况下有所不同吗?

非常感谢。

编辑:像我一样的Noobs可以从这个资源中获益: http://www.panix.com/~elflord/cpp/gotchas/index.shtml

6 个答案:

答案 0 :(得分:8)

不同之处在于,farr++会产生任何影响,编译器需要存储的地方farr将评估数组的第二个元素的地址。但是没有地方可以提供这些信息。编译器仅为3整数分配位置。

现在,当您声明函数参数是一个数组时,函数参数将不是一个数组。函数参数将是一个指针。 C中没有数组参数。因此以下两个声明是等效的

void f(int *a);
void f(int a[]);

在括号之间放置的数字甚至不重要 - 因为参数确实是一个指针,“size”只是被忽略了。

这与函数相同 - 以下两个是等效的,并且函数指针作为参数:

void f(void (*p)());
void f(void p()); 

虽然你可以调用一个函数指针和一个函数(所以它们被类似地使用),你也将无法写入函数,因为它不是一个指针 - 它只是转换指针:

f = NULL; // error!

与修改数组的方式大致相同。

答案 1 :(得分:5)

在C中,无法分配给数组。所以,给定:

T data[N];

T是一种类型而N是一个数字,你不能说:

data = ...;

鉴于上述情况,data++;正试图分配给data,您会收到错误。

C中有一个关于数组和指针的简单规则。在值上下文中,数组的名称等同于指向其第一个元素的指针,而在对象上下文中,数组的名称等同于数组。

对象上下文是指使用sizeof获取数组的大小,或者当您获取其地址(&data)时,或者在初始化数组时。在所有其他情境中,您处于价值背景中。这包括将数组传递给函数。

所以,你的功能:

void working_on_pointers ( int *pExpect, int aExpect[] ) {

相当于

void working_on_pointers ( int *pExpect, int *aExpect ) {

该函数无法判断它是否传递了数组或指针,因为它看到的只是一个指针。

以下问题的答案中有更多细节:

另请参阅C for smarties网站的这一部分,该部分写得非常好。

答案 2 :(得分:1)

尝试增加farrvarr失败,因为两者都不是指针。每个都是一个数组。数组的名称,当它自己计算时(除了作为sizeof或address-of运算符的操作数)计算为(一个rvalue),它是要分配给指针的正确类型。尝试增加它有点像尝试增加17。您可以增加一个包含值为17的int,但增量17本身将不起作用。数组的名称非常类似。

至于你的第二部分,它非常简单:如果你试图声明一个数组类型的函数参数,编译器会默默地将它“调整”为一个指针类型。因此,在working_on_pointers中,aExpectpExpect 完全相同的类型。尽管使用了数组样式表示法,但您已将aExpect定义为具有类型'指向int的指针'。由于两者是相同的,所以完全可以预期它们的行为相同。

答案 3 :(得分:0)

看看我在SO上发布的关于指针和数组之间差异的答案。

希望这有帮助。

答案 4 :(得分:-1)

好吧,我可能错了。但是数组和指针可以交替使用。

int * ptr = (int *)malloc(2* sizeof(int));
ptr[0]=1;
ptr[1]=2;

printf ("%d\n", ptr[0]);
printf ("%d\n", ptr[1]);

这里我声明了一个指针,现在我将它视为数组。

此外:

  

由于这个定义,   没有明显的区别   “数组下标”的行为   operator [],因为它适用于数组   和指针。在表达中   形成一个[i],数组引用“a”   衰败成一个指针,跟着   上面的规则,然后下标   就像一个指针变量一样   表达式p [i](尽管如此)   最终的内存访问将是   不同,正如所讨论的那样   2.2)。在任何一种情况下,表达式x [i](其中x是数组或a   根据定义,指针是相同的   到*((x)+(i))。

参考:http://www.lysator.liu.se/c/c-faq/c-2.html

答案 5 :(得分:-2)

您需要了解数组的基本概念。

当你声明一个数组时,即

int farr[]

你实际上是用这个声明声明一个指针

const int * farr

即;一个指向整数的“常量”指针。所以当你做farr ++时,你实际上是在尝试添加一个恒定的指针,因此编译器会给你一个错误。

如果你需要理解,尝试使用上面的声明声明一个指针,你将无法进行正常指针合法的算法。

P.S: 它已经安静了一段时间我用C编码所以我不确定确切的语法。但底线是指针和常量指针之间的差异。