4

考虑以下陈述:

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)

}

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

非常感谢。

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

4

6 回答 6

8

不同之处在于,farr++为了产生任何效果,编译器需要将其存储在某个地方,这farr将评估为数组第二个元素的地址。但是没有地方存放这些信息。编译器只为3整数分配位置。

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

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

你在括号之间放什么数字甚至都没有关系——因为参数真的是一个指针,所以“大小”被忽略了。

函数也是如此——以下两个是等价的,并且有一个函数指针作为参数:

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

虽然您可以同时调用函数指针和函数(因此它们的使用相似),但您也无法写入函数,因为它不是指针 - 它只是转换为指针:

f = NULL; // error!

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

于 2010-03-05T00:57:42.690 回答
5

在 C 中,您不能分配给数组。所以,给定:

T data[N];

whereT是一个类型并且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网站的这部分,它写得非常好。

于 2010-03-05T01:44:10.277 回答
1

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

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

于 2010-03-05T01:08:51.427 回答
0

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

希望这可以帮助。

于 2010-03-05T01:03:05.717 回答
-1

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

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

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

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

而且:

由于此定义,“数组下标”运算符 [] 的行为没有明显差异,因为它适用于数组和指针。在 a[i] 形式的表达式中,数组引用“a”按照上面的规则衰减为一个指针,然后像表达式 p[i] 中的指针变量一样被下标(尽管最终的内存如问题 2.2 中所述,访问将有所不同)。在任何一种情况下,表达式 x[i](其中 x 是数组或指针)根据定义与 *((x)+(i)) 相同。

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

于 2010-03-05T02:24:41.343 回答
-2

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

当你声明一个数组时,即

int farr[]

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

const int * farr

IE; 指向整数的“常量”指针。因此,当您执行 farr++ 时,您实际上是在尝试添加一个常量指针,因此编译器会给您一个错误。

如果您需要理解,请尝试使用上述声明声明一个指针,您将无法执行对普通指针合法的算术运算。

PS:我已经用 C 编码了一段时间,所以我不确定确切的语法。但底线是指针和常量指针之间的区别。

于 2010-03-05T01:22:28.337 回答