指向数组的指针与普通指针的区别

时间:2019-03-01 15:33:43

标签: c pointers scanf

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

int main()
{
    int *a;
    int *b= malloc(sizeof(int)*100);
    scanf("%d",&a);
    scanf("%d",b);
    printf("%d",a);
    printf("%d",*b);
    return 0;
}

在这段代码中,为什么与普通指针相比,指向数组的指针不需要scanf的地址位置? 同样对于printf(如果是指向数组的指针),为什么我们必须给星号而不是指针变量?

3 个答案:

答案 0 :(得分:2)

尽管printfscanf的格式说明符具有相似的语法,但它们并不完全相同。特别是%d的{​​{1}}期望scanf,因为它需要写入变量地址,而int *的{​​{1}}期望%d,因为它只需要一个值即可打印。

此代码的问题与printfint指向的内容无关,而是与它们在ab调用中的使用方式有关。

查看每一行:

printf

这是无效的,因为scanf的{​​{1}}格式说明符期望一个scanf("%d",&a); ,但是您要传递一个%d

scanf

这是有效的,因为int *int **。它将scanf("%d",b); 写入数组的第一个元素。

b

这是无效的,因为int *的{​​{1}}格式说明符期望一个int,但是您要传递一个printf("%d",a);

%d

这是有效的,因为printfint。它将打印数组的第一个元素。

答案 1 :(得分:1)

在我回答这个问题之前,您的代码中有一个错误需要修复:

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

int main()
{
    int a; // <<< remove * from declaration, such that a is a normal int
    int *b= malloc(sizeof(int)*100);
    scanf("%d",&a);
    scanf("%d",b);
    printf("%d",a);
    printf("%d",*b);
    return 0;
}

所以...

  

在这段代码中,为什么与普通指针相比,指向数组的指针不需要scanf的地址位置?

scanf调用中,%d说明符期望相应的参数具有类型int *,这是scanf期望写入的对象的位置一个整数值。您 b声明为int *,因此 expression b已经具有正确的类型,并且已将其设置为指向scanf可以在其中写入整数值的有效内存位置。

在上面的固定代码中,a的类型为int,因此我们必须使用 expression &a来获得int *值。该值是a location scanf在此处写入输入整数值。

  

对于printf,如果是指向数组的指针,为什么我们必须给星号而不是指针变量?

printf调用中,%d转换说明符期望相应的参数具有类型int,即您要设置格式的整数 value ,写入输出流。我们已经将声明 a声明为普通的int,因此 expression a已经具有正确的类型,并且 value 被格式化并写入输出流。

我们已将b声明为int *,因此它存储的是地址值,而不是整数。我们必须使用一元b一元运算符 dereference *来获得它指向的整数值。 表达式 *b的类型为int,其值是存储在b所指向的位置的整数值。

而且,为了令人讨厌的学究,我想澄清一些术语。  b并不指向 array -它指向的单个int对象恰好是数组的第一个元素(在这种情况下,它是动态分配的缓冲区)。指向 array 的指针如下所示:

int a[N];
int (*b)[N] = &a;

int (*b)[N] = malloc( sizeof *b );

我们不会在这里涉及到这一点,因为您不会经常处理指向数组的指针。

您可以将上面的scanfprintf调用重写为:

scanf( "%d", &b[0] ); // note & operator in this case
...
printf( "%d", b[0] );

下标表达式a[i]定义*(a + i)-给定地址a,偏移量i 元素 (不是字节!)从该地址开始,然后取消引用结果。

由于隐式取消引用操作,表达式 b[0]的类型为int,而不是int *,这就是为什么我们需要&的原因scanf调用中的运算符,而不需要则需要*调用中的printf运算符。

答案 2 :(得分:0)

您的代码中实际上有一个错字,只有在您使用“ int a”这样的方式时,此错才起作用:

int a;
int *b= (int *)malloc(sizeof(int)*100);
scanf("%d",&a);
scanf("%d",b);
printf("%d",a);
printf("%d",*b);

在这种情况下,应该很清楚:scanf始终需要一个指针,因此您对&而不是已经使用了指针的b使用&地址运算符。对于printf,您需要在a已经为int时取消引用b指针。

如果您坚持使用“ int * a”,则必须编写

int *a;
int *b= (int *)malloc(sizeof(int)*100);
scanf("%d",a);
scanf("%d",b);
printf("%d",*a);
printf("%d",*b);

,如您所见,指针被完全相同地对待。但是,* a指针是未定义的(指向“无处”),因此在scanf中使用时很可能崩溃。