迭代C中的许多数组

时间:2013-05-07 00:51:39

标签: c arrays loops multidimensional-array

我有一个包含许多数组的头文件。每个阵列对(即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]'在引号中,因为这些数组的名称是字符串。

5 个答案:

答案 0 :(得分:6)

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等的地址,并将它们放入一个数组中。这样你就可以根据索引查找数组的地址,然后从那里访问数组。

答案 1 :(得分:3)

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

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

struct point {    双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出错时释放一个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;
}

AND这是我们用于处理点,地图和地图集的库代码的结尾;;

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

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

关于在load_setmap函数中使用GOTO的注释

这个函数使用gotos离开它无法构建的坐标 适当的地图无论出于何种原在任何清教徒结构程序员之前 跳过我的喉咙使用gotos我希望你检查代码 并验证它确实是最干净的编程方式  使用其中给出的方法进行错误处理

进一步说明

此代码中有很多内容;但这是有效的代码;应该作为一种通用的方法..有更多有趣的方法来处理链接列表等问题,但我希望你也是一个结构化的方法,而不是其他任何东西;

一个兴趣点是iterate_over_map函数,它将一个函数指针作为一个参数,可以遍历所有的点并回调你自己的函数;如果你不明白发生了什么,请在这里给我留言,我会详细说明;但请研究一下,这是一种合理的方式来设置C中的东西,一旦你完成每个功能就很容易理解;大多数功能的结构及其用途都是不言自明的。

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

代码应该通过逻辑构​​建从上到下轻松阅读;我将结构分散到代码中,以使它们接近处理它们的函数;通常你会把它们放在他们自己的文件中,并在其他地方有相应的头文件,但是这会从我希望传达的逻辑构建中消失。这可以在其他地方学到。

如果你感到困惑,请弹出一张便条。

答案 2 :(得分: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];
    }
}

答案 3 :(得分: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数组并访问每个单独的数组及其大小。

答案 4 :(得分: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];
  }
}