好的,正如@Tommy指出的那样,你使用的语法在C语言中是不可能的,因为它不是一种反射性语言。我将尝试帮助您以C语言应该使用的方式进行设置,并可以以动态方式使用;
您真正想做的是设置一个结构体(我称其为点,但您可以称其为任何内容),如下所示:
struct point {
double x;
double y;
};
现在,您可以轻松地建立多个由此结构体构建的数组:
struct point array0[] = { { 4.0, 11.0 }, { 4.0 , 11.0 }, ... };
struct point array1[] = { { 224.0, 2.0 }, { 224.0, 2.0 }, { }, ... };
是的,你可以将它们放在多行上,使语法比我的更美观 :-)
这将让你以这种方式获取任何给定数组的长度:
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;
struct point *points;
};
现在让我们创建一些函数来分配和释放它们。
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;
for (k = 0; k < m->count; k++) {
if ((rv = f(&m->points[k])) != 0 ) {
if (error != NULL)
*error =rv;
break;
}
}
return (k - m->count);
}
现在我们已经有了一张地图,让我们创建一组它们。
struct mapset {
size_t count; /* number of maps in this set */
struct map **maps; /* a NULL terminated array of maps in this set */
};
但是我们如何初始化这样一个复杂的东西呢?硬编码并不是一个好主意,如果我们能够从文本文件中读取这些信息,那就更好了。因此,让我们创建一个代码库来从文件中加载地图:
如果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;
char buf[1024];
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);
if ( strcmp ( buf, "MAP") != 0 )
continue;
fgets(buf, sizeof(buf), fp);
if (feof(fp))
goto build_error;
sscanf(buf, "%lu", &tmpcnt);
tmpmap = map_init(tmpcnt);
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);
}
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;
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中设置易于遵循的事情的合理方法,一旦你通过每个函数,大多数函数和它们的使用结构都是不言自明的。
另一个注意点:我还没有创建原型和单独的头文件,因为我希望你看到逻辑的建立过程。
代码应该可以很容易地从上到下阅读并形成逻辑。我将结构分散在代码中以将它们靠近处理它们的函数;通常,你会将这些放在自己的文件中,并有相应的头文件用于包含其他地方,但这会减弱我希望传达的逻辑建立。这可以在其他地方学到。
如果你感到困惑,请给我留言。