#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(如果是指向数组的指针),为什么我们必须给星号而不是指针变量?
答案 0 :(得分:2)
尽管printf
和scanf
的格式说明符具有相似的语法,但它们并不完全相同。特别是%d
的{{1}}期望scanf
,因为它需要写入变量地址,而int *
的{{1}}期望%d
,因为它只需要一个值即可打印。
此代码的问题与printf
和int
指向的内容无关,而是与它们在a
和b
调用中的使用方式有关。
查看每一行:
printf
这是无效的,因为scanf
的{{1}}格式说明符期望一个scanf("%d",&a);
,但是您要传递一个%d
。
scanf
这是有效的,因为int *
是int **
。它将scanf("%d",b);
写入数组的第一个元素。
b
这是无效的,因为int *
的{{1}}格式说明符期望一个int
,但是您要传递一个printf("%d",a);
。
%d
这是有效的,因为printf
是int
。它将打印数组的第一个元素。
答案 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 );
我们不会在这里涉及到这一点,因为您不会经常处理指向数组的指针。
您可以将上面的scanf
和printf
调用重写为:
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中使用时很可能崩溃。