对于一个C初学者来说,我在理解数组、指针和数组的指针方面有一些问题。不幸的是,这里提供的信息并没有帮助我,因为所有的处理"更容易"的问题。这是我的代码:
/* random.c */
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main(){
double particles[4][22];
int seed,i,x,y;
double px_buf, py_buf, pz_buf;
seed=time(NULL);
srand(seed);
/* The random numbers are generated between 1E-12 and 10E-12 */
/*Double precision floats support up to 15 decimal places*/
for(i=0;i<20;i++){
px_buf=((double)rand()/RAND_MAX)*9001E-15;
py_buf=((double)rand()/RAND_MAX)*9001E-15;
pz_buf=((double)rand()/RAND_MAX)*9001E-15;
particles[0][i]=px_buf;
particles[1][i]=py_buf;
particles[2][i]=pz_buf;
printf("(step: %i) The following noise momentum was generated: (%.15E,%.15E,%.15E)n",i,px_buf,py_buf,pz_buf);
}
sscanf("p[20] = nullvector(45.0000000000106,33.03951484238976,14.97124733712793,26.6317895033428)",
"p[20] = nullvector(%lf,%lf,%lf,%lf)",&particles[3][20],&particles[0][20],&particles[1][20],&particles[2][20]);
for(y=0;y<22;y++){
for(x=0;x<3;x++){
printf("%.15E t", particles[x][y]);
}
printf("n");
}
return 0;
}
这段代码工作得很好,但是正如您所看到的,最后四个(y=21)数组条目是"空的",我想用与现在使用sscanf行相同的方式填充它。
我想用一个合适的解析器函数替换sscanf部分,但是我完全困惑如何正确传递指针,特别是如何使用sscanf的地址一元操作符(&)。这是我的初步解析器函数:
/* parse.c */
void parser(char *input, double **particles){
sscanf(input, "p[20] = nullvector(%lf,%lf,%lf,%lf)",
&particles[3][20],&particles[0][20],&particles[1][20],&particles[2][20]);
printf("energy: %E, p: (%E, %E, %E)n",particles[3][20],
particles[0][20],particles[1][20],particles[2][20]);
}
正如你所看到的,我主要对以"nullvector("开头的四个双精度值感兴趣,我想从字符串中取出这些值,并将它们写入多数组"particles"的第21行。
但是当我添加
#include "parse.c"
(...)
parse("p[20] = nullvector(45.0000000000106,33.03951484238976,
14.97124733712793,26.6317895033428)",particles);
的主函数,它给了我以下错误:
[darillian@quantumbox rng]$ gcc random.c -Wall -pedantic -o ../../bin/random
random.c: In function ‘main’:
random.c:29:2: warning: passing argument 2 of ‘parse’ from incompatible pointer type [enabled by default]
In file included from random.c:4:0:
parse.c:1:6: note: expected ‘double **’ but argument is of type ‘double (*)[22]’
我做错了什么?div; D
因为你提前知道了代表粒子的向量的大小,所以逆数组索引更有意义:
#define NUM_PARTICLES 22
/* ... */
double particles[NUM_PARTICLES][4];
这会改变你的解析函数,使其更容易编写:
void parser(char *input, double particles[][4]){
sscanf(
input,
"p[20] = nullvector(%lf,%lf,%lf,%lf)",
&particles[20][3], &particles[20][0],
&particles[20][1], &particles[20][2]
);
}
这将编译并执行您想要的操作。额外的好处是,解析器不需要知道字段中有多少粒子。相反,它只需要知道粒子是如何表示的(它应该这样做)。
解析器需要知道字段中有多少粒子,这是一个很大的代码气味,表明有问题。更改程序以使其更有意义,也可以很好地处理您的错误!
作为提示,可以这样考虑二维数组:double arr[rows][columns];
新文件在GCC 4.6的Linux环境下可以正常编译。
澄清为什么我们需要给解析器函数列的数量?
否则函数将没有足够的信息来计算给定值的偏移量
一个一维数组看起来像这样:
|value0|value1|value2|...
通过告诉编译器这是double
数组来指定value
的宽度。
当你访问这个数组时,比如arr[17]
计算机实际上是这样做的:
address of value (bytes) = 17 * width of double (bytes)
现在考虑一个多维数组double arr[17][2]
:
|va0|vb0|va1|vb1|va2|vb2|...
当您尝试访问一个值时,例如arr[3][1]
,计算机现在将执行以下计算:
address of value (bytes) = (3 * width of inner array) + (1 * size of element)
,
width of inner array = no of elements * size of elements.
在上面的例子中,内部数组的元素个数是2,它们的大小是double类型的。
因此,它需要内部数组('列')的宽度来找到值的实际地址,否则它无法计算索引时的偏移量。
这是因为C使用行为主排序。