通过实际例子,数组和指针之间的异同

cor*_*rto 9 c arrays pointers

给出以下代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int a[1];
    int * b = malloc(sizeof(int));

    /* 1 */
    scanf("%d", &a);
    printf("%d\n", a[0]);

    /* 2 */ 
    scanf("%d", &b);
    printf("%d\n", b[0]); 

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译时获得以下警告(i686-apple-darwin9-gcc-4.0.1):

array.c: In function 'main':
array.c:9: warning: format '%d' expects type 'int *', but argument 2 has type 'int (*)[0u]'
array.c:14: warning: format '%d' expects type 'int *', but argument 2 has type 'int **'
Run Code Online (Sandbox Code Playgroud)

但是,为什么在第二个printf中发生执行错误,同时它适用于第一个printf

更重要的是,如果用scanf代替第一个scanf("%d",a),为什么得到相同的输出;

非常感谢提前

Joh*_*ode 10

在大多数情况下,数组类型的表达式将从"N元素数组T"隐式转换为"指向T",其值将设置为指向数组的第一个元素.此规则的例外情况是当数组是&sizeof运算符的操作数时,或者数组是用于初始化声明中的另一个数组的字符串文字.

那么所有与你的代码有什么关系呢?

在线

scanf("%d", &a);
Run Code Online (Sandbox Code Playgroud)

您正在将&运算符应用于数组.这抑制了从"T的数组"到"指向T的指针"的隐式转换,并返回类型为"指向T的数组的指针"的值,或者T (*)[N](因此是您的第一个警告).现在事实证明,指向数组的指针的值和指向数组的第一个元素的指针的值是相同的,它们只是具有不同的类型.所以假设它a在地址0x0001000:

expression      type          value         note
----------      ----          -----         ----
         a      int *         0x0001000     implicitly converted to pointer
        &a      int (*)[N]    0x0001000     
     &a[0]      int *         0x0001000
Run Code Online (Sandbox Code Playgroud)

这就是你第一次打电话给scanf()"工作"的原因; 你正在传递正确的指针,但编译器抱怨,因为表达式的类型与函数所期望的不匹配.如果你写的

scanf("%d", a);
Run Code Online (Sandbox Code Playgroud)

你不会收到任何警告,因为a将会采取类型int *,这是scanf()预期的.请注意,这与呼叫相同

scanf("%d", &a[0]);
Run Code Online (Sandbox Code Playgroud)

至于b......

您显式声明b为指向int的指针并为其分配一块内存.当你&对它应用运算符时,你得到的是带有类型的变量 的地址(因此是第二个警告),而不是指向的地址. bint **b

expression      type          value         note
----------      ----          -----         ----
         b      int *         0x0040000     value contained in b
        &b      int **        0x0001000     address of b
Run Code Online (Sandbox Code Playgroud)

对于这种情况,你只需通过未修饰的b:

scanf("%d", b);
Run Code Online (Sandbox Code Playgroud)


Pup*_*ppe 5

数组a放在堆栈上,第一个元素的地址与a的地址相同. &a [0]和&a是相同的地址

数组b分配有malloc,存储的地址在堆上,而指针b的地址在堆栈上.&b [0]与&b的地址不同.

这就是为什么第一个scanf和printf工作但不是第二个.

C-FAQ解释了它在更多的细节.