指向数组的指针和指针指针有什么区别?

时间:2014-12-03 12:06:12

标签: c pointers function-pointers memory-address pointer-arithmetic

我是编程和学习数组中指针的新手。我现在有点困惑。看看下面的程序:

#include <stdio.h>
int fun();
int main()
{
    int num[3][3]={23,32,478,55,0,56,25,13, 80};
    printf("%d\n",*(*(num+0)+1));
    fun(num);
    printf("%d\n", *(*(num+0)+1));
    *(*(num+0)+0)=23;
    printf("%d\n",*(*(num+0)));
    return 0;
}
int fun(*p)  // Compilation error
{
    *(p+0)=0;
    return 0;
}

这是我老师的笔记中写的程序。在main()函数中,在printf()函数中,取消引用运算符被使用了两次,因为num是指向数组的指针,因此第一次取消引用运算符将​​指向int和然后第二个将给出指针指向的值。

我的问题是,当我将数组名称作为参数传递给函数fun()时,为什么使用*p;为什么不**p num是指向数组的指针?

第二件事为什么*(p+0)用于更改数组的第0个元素的值;为什么*(*(p+0)+0)=0函数main()中的*(*(num+0)+0)用于更改第0个元素的值?

对我来说整件事情让我很困惑,但无论如何我必须要理解它。我已经搜索过这个,发现指向数组的指针和指向指针的指针之间存在差异,但我无法理解。

4 个答案:

答案 0 :(得分:3)

诀窍是数组指针 - 衰减:当你提到数组的名称时,它会在几乎所有上下文中衰变为指向其第一个元素的指针。那就是num只是一个由三个整数组成的数组(type = int [3][3])。

让我们分析表达式*(*(num + 1) + 2)

当你在表达式num中提到*(num + 1)时,它会衰减成指向其第一个元素的指针,该元素是一个包含三个整数的数组(type = int (*)[3])。在此指针上执行指针运算,并将指针指向的任何大小添加到指针的值。在这种情况下,它是三个整数数组的大小(许多机器上的12个字节)。取消引用指针后,您将保留int [3]类型。

但是,这种解除引用仅涉及类型,因为在解除引用操作之后,我们看到表达式*(/*expression of type int[3]*/ + 2),因此内部表达式衰减回指向第一个数组元素的指针。此指针包含与num + 1产生的指针相同的地址,但它具有不同的类型:int*。因此,对该指针的指针运算使指针前进两个整数(8个字节)。因此表达式*(*(num + 1) + 2)12 + 8 = 20字节的偏移量处产生整数元素,这是数组中的第六个整数。


关于您对fun()的通话的问题,该通话实际上已被破坏,并且只有在您的老师未在fun()的前方声明中包含参数时才有效。代码

int fun(int* arg);

int main() {
    int num[3][3] = ...;
    ...
    fun(num);
}
由于指针类型错误,

会产生编译时错误。老师的代码&#34;工作&#34;,因为指向num中第一个数组的指针与指向num中第一个数组的第一个元素的指针相同,i。即他的代码相当于

int fun(int* arg);

int main() {
    int num[3][3] = ...;
    ...
    //both calls are equivalent
    fun(num[0]);
    fun(&num[0][0]);
}

将编译而不会出错。

答案 1 :(得分:1)

此示例显示了一个矩阵,指向数组的第一个整数的指针和指向指针

的指针
#include<stdio.h>
int fun(int (*p)[3]);  /* p is pointer to array of 3 ints */
int main()
{
    /* matrix */
    int num[3][3]={{23,32,478},{55,0,56},{25,13, 80}};
    /* three pointers to first integer of array */
    int *pnum[3] = {num[0], num[1], num[2]};
    /* pointer to pointer */
    int **ppnum = pnum;
    printf("%d\n", *(*(num+1)+2));
    fun(num);
    printf("%d\n", *(*(num+1)+2));
    pnum[1][2] = 2;
    printf("%d\n", *(*(num+1)+2));
    ppnum[1][2] = 3;
    printf("%d\n", *(*(num+1)+2));
    return 0;
}
int fun(int (*p)[3])
{
    p[1][2]=1;
    return 0;
}

答案 2 :(得分:0)

你实际上并不需要任何指针来打印任何东西。

你的int num[3][3]实际上是一个由三个元素组成的数组,每个元素都是一个由三个整数组成的数组。因此num[0][0] = 23num[1][1] = 0等等。因此,您可以说printf("%d", num[0][0])来打印数组的第一个元素。

答案 3 :(得分:0)

指向变量的指针:

指针是变量,用于存储地址(变量的 )。每个人都知道。


指向数组的指针:

数组是一个变量,它具有相同对象组的起始点(地址)。

指针是一个存储数组起始点(地址)的变量。

例如:

int iArray[3];

iArray是一个变量,其地址值为三个整数,并且内存是静态分配的。以下语法以典型的编程语言提供。

// iArray[0] = *(iArray+0);
// iArray[1] = *(iArray+1);
// iArray[2] = *(iArray+2);

在上面,iArray是一个变量,通过它我们可以使用上面提到的任何语法访问三个整数变量。

*(iArray + 0); //这里iArray + 0是第一个对象的地址。 *是取消引用 *(iArray + 1); //这里iArray + 1是第二个对象的地址。 *是取消引用

如此简单,有什么可以混淆的。


以下内容仅供您参考

int iArray1[3];
int iArray2[3][3];

int *ipArray = 0;

ipArray = iArray1;        // correct
ipArray = iArray2[0];     // correct
ipArray = iArray2[2];     // correct
int **ippArray = iArray2; // wrong

根据上面的最后一行,编译器不会将其作为有效赋值。所以没有使用** p。

由于分配内存的方式,指针关节不能应用于双数组。