我有一个包含许多数组的头文件。每个阵列对(即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]'
在引号中,因为这些数组的名称是字符串。
答案 0 :(得分:6)
C不是反思性语言。 x0
被称为x0
和x1
被称为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(虽然我没有做太多检查,让我知道它对你有多好,如果不是,我们会看到会发生什么)
这个函数使用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)
除了单个数组x0
,x1
等之外,还有一个结构数组,其中包含每个数组的大小和地址:
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];
}
}