3

我有一个包含许多数组的头文件。每个数组对(即x0,y0)的长度相同,但不同的对具有不同的长度。

numPaths[] = 4;
pathLengths[] = {12, 11, 13, 10};
int x0[] ={4.0, 4.0, ...};
int x1[] ={224.0, 224.0, ...};
int x2[] ={446.0, 446.0, 446.0, ...};
int x3[] ={598.0, 598.0, ...};
int y0[] ={11.0, 11.0, 11.0, 15.0, ...};
int y1[] ={2.0, 2.0, 2.0, 6.0, 17.0, ...};
int y2[] ={1.0, 1.0, 1.0, 5.0, ...};
int y3[] ={4.0, 4.0, 4.0, 5.0, 10.0, ...};

我希望能够遍历这个数组列表并访问数据点信息。我不知道该怎么做,特别是因为路径长度不同。我正在考虑这样的伪代码:

i=0;
n=0;
if i< numPaths:
    if n < pathLengths[i]:
        x_tot = x'[i]'[n]
        y_tot = x'[i]'[n]
    n++
    i++

其中'[i]'是引号,因为这些数组的名称是字符串。

4

5 回答 5

5

C 不是反射语言。x0被调用x0x1被调用的事实x1已被编译器丢弃。因此,一段代码无法执行“查找具有名称的数组”的操作x1,这实际上是您的代码将尝试执行的操作。C 的预处理器也可能有点过于生硬,无法在编译期间干净利落地执行此操作。

所以你能做的最好的事情是:

int *xs[] = {x0, x1, x2, x3};

for(int c < numPaths)
{
    int *thisX = xs[c];

    ... read from thisX[0], thisX[1], etc...
}

所以你所做的就是告诉编译器获取 x0、x1、x2 等的地址,并将它们放入一个数组中。这样,您可以根据索引查找数组的地址,然后从那里访问数组。

于 2013-05-07T00:59:11.317 回答
2

好的,正如@Tommy 指出的那样,您使用的语法在 C 中是不可能的,因为它不是一种自反语言;我将尝试帮助您按照应该在 C 中完成的方式进行设置,并且可以以动态方式使用;

你真正想做的是建立一个结构(我称之为一个点,但你可以称之为任何东西),如下所示:

结构点 { 双 x; 双 y; };

现在,您可以轻松地使用此结构构建多个数组:

struct point array0[] = { { 4.0, 11.0 }, { 4.0 , 11.0 }, ... };
struct point array1[] = { { 224.0, 2.0 }, { 224.0, 2.0 }, { }, ... };
/* etc... */

是的,您可以将它们放在多行上,以使语法比我的更漂亮:-)

这将让您以这种方式获取任何给定数组的长度:

size_t length_array0 = sizeof(array0) / sizeof(struct point);

但是,这对您的情况仍然没有用,因为您无法以编程方式访问正确的数组;这将需要相当多的设置才能正确完成。在软件中进行静态操作是一件很痛苦的事情,最好设置一组函数来处理点、地图和地图数组,并从文件中读取地图:

正确的方法是构建一堆函数和结构来处理每个组件并构建所有内容。

这是一种可能的方法:

我们需要一些基本的库:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>

让我们在地图中设置一个基本点和它们的集合

struct point { double x, y; };

struct map { 
    size_t count;           /* number of points in this map */
    struct point *points;   /* array of points in the map */
}; 

现在让我们创建一些函数来分配和释放它们

struct map * map_init(size_t count)
{
        struct map *m = (struct map *) malloc(sizeof (struct map));
        if ( !m )
                return NULL;
        m->count = count;
        m->point = (struct point *) malloc (count * sizeof(struct point));
        if ( !m->point ) {
                free(m);
                m = NULL;
        }
        return m;
}


void map_free(struct map *m)
{
        if ( m ) {
                if ( m->points )
                        free (m->points);
                free(m);
        }
}

以及一些用于在特定索引处向分配的地图添加新点的函数:

struct point *map_set_point(struct map *m, int index, struct point *p)
{
    if ( !m )
        return NULL;

    if ( index < m->count ) {
        m->points[index].x = p->x;
        m->points[index].y = p->y;
        return &m->points[index];
    }

    return NULL;
}

struct point *map_set_point_xy(struct map *m, int index, double x, double y)
{
    struct point p;
    p.x = x;
    p.y = y;
    return map_set_point(m, index, &p);
}

无需对整个代码进行索引范围检查就能够在索引处获得一个点也是一个好主意,因此我们为此编写了一个包装器

struct point *map_get_point(struct map *m, int index)
{

    if ( !m || index < 0 || index >= m->count ) {
        return NULL;
    }

    return &m->points[index];
}

为了完整性,我们对地图中的点数做同样的事情:

size_t map_get_count(struct map *m)
{
    if ( m ) 
        return m->count;

    return ((size_t)-1);
}

能够遍历地图中的所有点而不必每次都设置一个 for 循环也很好,因此我们创建了一个回调函数,可以遍历地图中的所有点并调用其中一个我们可以稍后定义的函数

typedef int (*point_callback_func_t)(struct point *p);

int for_each_point_call(struct map *m, point_callback_func_t f, int *error)
{
    int k;
    int rv; /* return value from call back function */
    for (k = 0; k < m->count; k++) {
        if ((rv = f(&m->points[k])) != 0 ) {
            if (error != NULL) 
                *error =rv;
            break;
        }
    }
    return (k - m->count); /* 
                * if we go through all of the points this will be zero 
                * otherwise it will be a negative number  indicating how far 
                * we were able to go in the loop
                */
}

现在我们有了一张地图,让我们创建一组它们

struct mapset {
    size_t count;       /* number of maps in this set */
    struct map **maps;  /* a NULL terminated array of maps in this set */
};

但是我们将如何初始化这样一个复杂的东西呢?硬编码并不是一个好主意,如果我们可以从文本文件中读取这些东西会很好,所以让我们创建一个代码库来从文件加载地图:

/* 
 * The read_maps_from_file  reads a text file of the format:

 MAP
 <M>
 <x1>, <y1>
 <x2>, <y2>
  ...
 <xM>, <yM>

 MAP
 <N>
 <x1>, <y1>
 <x2>, <y2>
  ...
 <xN>, <yN>


 and so on and can return a struct mapset filled with the map 
 coordinates

 A file with 3 maps would be:

--CUT-HERE--
 MAP
 3
 5.5, 2.2
 -3.5, 5.9
 2.0, -125.0

 MAP
 5
 2.2, -89.0
 551, 223.5
 7.5, -8.9
 7.8, 6.9
 4.3, -9.9

 MAP
 1
 2.5, 0.3

--CUT-HERE-- 

*/

如果 load_mapset 出现错误,我们需要能够释放地图集;您应该先阅读该功能;但是我们首先声明了它,以便可以从 load_mapset 函数中调用它。

void free_mapset(struct mapset *set) {
    int k;
    if ( set ) {
        if ( set->maps ) {
            for(k = 0; k < set->count; k++) {
                map_free(set->maps[k]);
            }
        }
        free(set);
    }
}

因此,让我们看看从文件中加载地图:

struct mapset *load_mapset(const char *filename)
{
    FILE * fp;
    struct mapset *set;
    size_t mapcnt = 0; /* number of maps in this set */

    char buf[1024]; /* line buffer */

    struct map *tmpmap;
    size_t tmpcnt;

    struct map **tmp_maps_arr;

    double x, y;

    int k;

    set = (struct mapset*) malloc(sizeof(struct mapset)); 

    if ( !set )
        goto build_error;

    set->count = 0;
    set->maps = NULL;

    fp = fopen("somefile.txt", "r");

    while(!feof(fp)) {

        fgets(buf, sizeof(buf), fp); /* read a line */

        if ( strcmp ( buf, "MAP") != 0 )  /* look for keyword 'MAP' */
            continue; /* nope, let's reloop */

        /* found 'MAP' read the next line to get the count */

        fgets(buf, sizeof(buf), fp); 

        if (feof(fp)) 
            goto build_error;

        sscanf(buf, "%lu", &tmpcnt); /* number of points in this map */

        tmpmap = map_init(tmpcnt);   /*  make a tmpmap of tmpcnt points */

        if ( !tmpmap )
            goto build_error; 

        for ( k = 0; k < tmpcnt; k++ ) {
            fgets(buf, sizeof(buf), fp);
            if (feof(fp)) 
                goto build_error;

            sscanf(buf, "%lf , %lf", &x, &y);
            map_set_point_xy(tmpmap, k, x, y); /* add x, y to index k */
        }

        /* try to increase the size of maps array */
        tmp_maps_arr= (struct map **) realloc(set->maps, sizeof(struct map *) * (1+set->count));
        if ( !tmp_maps_arr ) 
            goto build_error;

        set->maps  = tmp_maps_arr;
        set->maps[set->count] = tmpmap; /* save the pointer to the map */
        set->count++;
        tmpmap = NULL;
    }

    return set;

build_error:
    free_mapset(set);
    if (tmpmap) 
        map_free(tmpmap);

    return NULL;
}

并且这就是我们处理点、地图和地图集的库代码的结尾;

您可以从以下网址获取此代码的完整副本:http: //pastebin.com/i2m624yX

代码应该按原样编译并且应该可以工作(虽然我没有做太多检查,让我知道它对你有多好,如果没有,我们会看看会发生什么)

关于在 load_setmap 函数中使用 GOTO 的注意事项

此功能使用 goto 来摆脱因任何原因无法构建正确地图的位置;在任何清教徒结构程序员因为使用 goto 而跳下我的喉咙之前,我希望您检查代码并验证它确实是使用其中给出的方法来编程错误处理的最干净的方法

进一步说明

这段代码发生了很多事情。但这是工作代码;应该作为一种通用方法。有更多有趣的方法可以解决链表等问题,但我也希望您采用结构化方法,而不是其他任何方法;

有趣的一点是 iterate_over_map 函数,它以函数指针作为参数,可以遍历所有点并回调您自己的函数;如果您不明白那里发生了什么,请在此处给我留言,我会详细说明;但是请研究一下,这是一种合理的方法,可以在 C 语言中进行设置,一旦您完成每个函数就可以轻松理解;并且大多数功能的结构及其用途是不言自明的。

另一个注意事项:我还没有费心创建原型和单独的标题,因为我希望您看到构建逻辑的流程

代码应该很容易从上到下阅读,并具有逻辑构建;我将结构分散到代码中,以使它们靠近处理它们的函数;通常,您会将它们放在自己的文件中,并在其他地方包含相应的头文件,但这会脱离我希望传达的逻辑构建。这可以在别处学到。

如果您感到困惑,请弹出一个便条。

于 2013-05-07T02:50:40.433 回答
0

您可以使用数组数组:

numPaths = 4;
pathLengths[] = {12, 11, 13, 10};
int x0[] ={4.0, 4.0, ...}; 
int x1[] ={224.0, 224.0, ...};
. . .
int *xs[] = {x0, x1, x2, x3};
int *ys[] = {y0, y1, y2, y3};

int i, j;
for (i = 0; i < numPaths; ++i){
    for (j = 0; j< pathLenghts[i] ++j){
        x_tot = xs[i][j];
        y_tot = ys[i][j];
    }
}
于 2013-05-07T01:02:00.183 回答
0

除了单独的数组x0x1等之外,还有一个结构数组,其中包含每个数组的大小和地址:

int x0[] ={4.0, 4.0, ...};
int x1[] ={224.0, 224.0, ...};
int x2[] ={446.0, 446.0, 446.0, ...};
int x3[] ={598.0, 598.0, ...};

#define ARRAY_SIZE(n) (sizeof(n) / sizeof(*n))

struct {
    int* array;
    size_t length;
} x[] = {
    {x0, ARRAY_SIZE(x0)},
    {x1, ARRAY_SIZE(x1)},
    {x2, ARRAY_SIZE(x2)},
    {x3, ARRAY_SIZE(x3)}
};

然后,您可以遍历x数组并访问每个单独的数组及其大小。

于 2013-05-07T01:02:34.683 回答
0
numPaths[] = 4;
pathLengths[] = {12, 11, 13, 10};
/* int x0[] ={4.0, 4.0, ...}; ... */
int **pairs = {x0, y0, x1, y1, x2, y2, x3, y3};
for (int i = 0; i < 4; i++)
    process_pair(&x_tot, &y_tot, pairs[i*2], pairs[i*2+1], pathLengths[i]);

void process_pair(int *x_tot, int *y_tot, int *x, int *y, int n) {
  for (int i = 0; i < n; i++) {
    x_tot[0] += x[i];
    y_tot[0] += y[i];
  }
}
于 2013-05-07T01:05:10.133 回答