指向数组与正常指针差异的指针

问题描述 投票:-3回答:3
#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,为什么我们必须给出星号符号而不仅仅是指针变量?

c pointers scanf
3个回答
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 *,因此表达式b已经具有正确的类型,并且您已将其设置为指向scanf可以写入整数值的有效内存位置。

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

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

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

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

而且,只是为了讨厌迂腐,我想要澄清一些术语。 b没有指向一个数组 - 它指向一个恰好是数组的第一个元素的int对象(或者在这种情况下,是一个动态分配的缓冲区)。指向数组的指针如下所示:

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
投票

虽然printfscanf的格式说明符的语法相似,但它们并不完全相同。特别是%dscanf期望int *,因为它需要变量地址写入,而%dprintf期望int,因为它只需要打印值。

这段代码的问题与ab指出的问题无关,而是如何在printfscanf调用中使用它们。

看每一行:

scanf("%d",&a);

这是无效的,因为%dscanf格式说明符需要int *但你传递的是int **

scanf("%d",b);

这是有效的,因为b是一个int *。它会将int写入数组的第一个元素。

printf("%d",a);

这是无效的,因为%dprintf格式说明符需要int但你传递的是int *

printf("%d",*b);

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


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总是需要一个指针,因此你使用&address运算符表示a而不是b表示已经是指针。对于printf,你需要取消引用b指针,而a已经是int。

如果你坚持使用“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中使用时可能会崩溃。

© www.soinside.com 2019 - 2024. All rights reserved.