AlexD 有它:float *taps[3]; 是一个指向 float 的指针数组,但您没有任何地方可以让数据真正go。
这是工作代码:
#include "stdio.h"
float taps[3];
int
main(){
for (int i = 0; i < 3; i++) {
fscanf(stdin, "%f", &taps[i]);
}
printf("Values: %f %f %f", taps[0], taps[1], taps[2]);
return 0;
}
结果:
$ gcc taps.c
$ ./a.out
42
33.5
0.01
Values: 42.000000 33.500000 0.010000
$
这就是您的代码不起作用的原因。当您编写float taps[3]; 时,您声明了3 个指向float 的指针 空间,即3 个地址。但是,您不会初始化它们,因此它们中的数据将是上次设置它们时碰巧在这些位置的任何随机位。当您尝试使用fprintf 设置它们时,系统会查看内容,找到恰好在那里的任何地址,例如0xBEEF,并尝试将数据发送到那里。幸运的是,这不是您可以放置数据的地方,因此会引发分段错误。如果您不走运,那恰好是您可以写入数据的地方,这意味着在未来的某个时候,您可能会发生一些真正奇怪的事情,因为您搞混了与记忆。
现在,当您使用float taps[3]; 时,您现在正在内存中定义一个位置,该位置从放置tabs[0] 的位置开始,并有空间容纳三个浮点数。然后你的陈述
fscanf(stdin, "%f", &taps[i]);
获取该数组,找到元素的地址——这就是& 运算符所做的,并将你的值放在那里。
换句话说,float *taps[3]; 在浮点数的地址数组中; float taps[3];实际上是为3个floats分配空间。
更新
在答案中编写代码比在评论中编写代码更容易。
Alex,您需要考虑一下您的代码在说什么。正如我们所说,float *taps[3]; 是一个指向float 的指针数组,因此每个float* 元素都是一个地址。 float taps[3]; 是floats 的实际数组,因此每个元素都是float。所以,比如说,taps[2] 本身就是一个float。
(请注意,顺便说一句,您可以编写 taps[3] 编译器不会在意,因为 C 不检查边界。那意味着计算机将查看taps[2] 旁边的地址中的任何内容,并将其视为float,无论实际存在什么。)
& 运算符获取其右侧的地址,因此当我们给 fscanf 一个参数 &taps[i] 时,我们将获取该浮点数的 地址,并且将其传递给fscanf。浮点地址是指向float 或float* 的指针。
现在,这里出现了一些奇怪的地方。在 C 中,array 的名称基本上代表了一个地址。所以,如果我有一个原型为foo(float[]) 的函数,它会说该函数需要一个float 的数组。数组的名称本质上是对第一个值的地址的引用,所以这段代码可以工作:
void foo(float[] bar){
// print three floats in an array, and God;s help you if there
// aren't three there.
for(int ix=0; ix<4; ix++){
printf("%f\n",bar[ix]);
}
}
float taps[3] = {1.0, 2.0, 3.0 };
foo(taps);
...但是如果我尝试foo(*taps),它将无法编译。为什么?
想象一下这个类比。我家的地址是 1662。所以,当我想给人们提供我家的参考时,我告诉他们它是数字 1662。但“1662”只是我家的数字:地址 1662 的东西是我的房子.
获取“1662”的地址是什么意思?什么都没有——这只是一个数字——地址不占用任何空间。同样,在 C 中,名称taps 表示内存中某个位置的地址——但这只是一个数字,它不占用任何空间。因此,当您说*taps 时,您正在获取一个号码的地址;这是没有意义的,所以它不能编译。
现在,由于数组的名称只是一个地址,我们可以像这样声明我们的函数foo:
void foo(float*) {
同样有效。
实际上,在 C 中,对于任何数组T 和整数i,这是一个恒等式:
*(T+i) == T[i]
特别是T 表示与&T[0] 相同的地址。
所以,现在,想一想。您在某个函数quux 中有一个数组,它调用foo(float*):
void quux() {
float taps[3] = { 1.0, 2.0, 3.0 };
foo(taps); // This compiles: you're giving the function
// an array name, and that represents the address
// of an array
// but foo(*taps) WON'T compile: that's the address of the address
// of an array.
return ;
}