0

对于 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(”的四个双精度值感兴趣,我想从字符串中取出这些值并将它们写入多数组“粒子”的第 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]’

我究竟做错了什么?;D

4

1 回答 1

1

因为您事先知道表示粒子的向量的大小,所以反转数组索引更有意义:

#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|...

value通过告诉编译器这是一个double数组来指定宽度。

所以当你访问这个数组时,假设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,它们的大小是双精度数。

因此,它需要内部数组(“列”)的宽度来找到值的真实地址,否则它无法在索引时计算偏移量。

这是因为 C 使用row-major ordering

于 2013-03-26T17:28:47.823 回答