我无法创建和访问结构指针作为数组。这是一个家庭作业问题,但这只是我对操作的误解。
我的头文件(我无法更改并且必须以这种方式实现)包含:
typedef struct gw_struct GW;
extern GW *gw_build(int nrows, int ncols, int pop, int rnd);
在实现文件中,我实现了两个声明
#include <stdio.h>
#include "gw.h"
#include <stdlib.h>
struct gw_struct {
int Alive;
int row;
int column;
int id;
};
GW *gw_build(int nrows, int ncols, int pop, int rnd){
GW* list = NULL;
int rows = nrows;
int cols = ncols;
for(nrows = 0; nrows < rows; nrows++){
for(ncols = 0; ncols < cols; ncols++){
GW *nn = malloc(sizeof *nn);
if (nn == NULL){
break;
}
list = nn;
}
}
return list;
}
最后我的测试文件包含:
#include <stdio.h>
#include "gw.h"
#include <stdlib.h>
int main (){
GW* World = gw_build(50, 50, 34, 1);
World[0][0] -> Alive = 2; //Can't get this to work
}
最后,我用
编译我的程序gcc -c gw.c
gcc gw.o main.c
似乎已经创建了结构指针,但我不能像数组那样访问它。
我试图以多种方式解决这个问题。我最初将变量世界初始化为
GW* World[50][50] = gw_build(50,50,34,1);
我在gw_build函数中使用“list”尝试了相同的操作,但它返回了初始化错误。
没有循环并且正在进行
GW* list[nrows][ncols];
也不允许,因为您不能将变量作为大小字段。
我可以创建,恶意攻击和访问
GW* World[50][50];
在main函数本身,一切正常,但是一旦我尝试通过从gw_build函数返回来设置它,它根本不起作用。因此,我尝试更改返回类型,但再次导致返回错误无效。
感谢任何指导,谢谢!
答案 0 :(得分:2)
您偶然发现了必须从简单的2d
数组中模拟 1d
数组的挑战。如果您查看给出的函数声明,则GW *gw_build(...)
会告诉您gw_build
将返回array
struct GW
。理想情况下,您可以通过创建array of pointers to struct GW
来简化操作,但显然,部分任务是让您使用简单的struct数组。
这简化了分配,但使索引变得复杂。这意味着,您对gw_build
的声明可能只是:
GW *gw_build(int nrows, int ncols, int pop, int rnd){
GW *list = calloc (nrows * ncols, sizeof *list);
if (!list) {
fprintf (stderr, "gw_build() error: virtual memory exhausted.\n");
return NULL;
}
return list;
}
但接下来的挑战是填充和引用每个,特别是如果你想要一个伪二维表示。赋值实际上是理解指针和索引操作的练习。谈论这个的最好方法就是举例。 (注意:下面,我已在gw_struct
中加入了gw.h
的声明,但如果您不能这样做,请将声明放在每个声明中源文件)
#ifndef _gw_header_
#define _gw_header_ 1
typedef struct gw_struct GW;
struct gw_struct {
int Alive;
int row;
int column;
int id;
};
extern GW *gw_build(int nrows, int ncols, int pop, int rnd);
#endif
#ifdef _gw_header_
只是控制头文件包含的一个示例。它确保gw.h
仅包括一次。如果您无法添加到头文件,则可以废弃它。
源文件gw.c
只需要分配nrows * ncols
个结构,所以它可以简单如下:
#include <stdio.h>
#include <stdlib.h>
#include "gw.h"
GW *gw_build(int nrows, int ncols, int pop, int rnd){
GW *list = calloc (nrows * ncols, sizeof *list);
if (!list) {
fprintf (stderr, "gw_build() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return list;
}
既标准又不多讨论。真正的工作包含在包含main()
的源文件中,您将填充并使用gw_build
返回的数组。
#include <stdio.h>
#include "gw.h"
#define ROWS 10
#define COLS 10
int main (void) {
GW *world = gw_build (ROWS, COLS, 34, 1);
int i, j;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
(world + i * ROWS + j)->Alive = (i*ROWS + j) % 3;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
printf (" world[%2d][%2d] : %d\n", i, j, (world + i*ROWS + j)->Alive);
return 0;
}
(例如,我根据索引值填充Alive
的{{1}}之间的值)
当您从0-2
收到已分配的数组时,您必须从数组的开头按gw_build
管理填充和使用。您可以简单地使用(offset
),但这将使用伪二维索引失败。诀窍是简单地找到一种使用2D数组语法计算和引用每个偏移的方法。如果您在上面注意到,0 < index < (nrows*ncols)
访问每个结构的偏移量。这允许i * ROWS + j
的伪{2D}引用位于场景array[i][j]
后面代表i
和i * nrows
只是该地址的附加偏移量。
您还可以选择使用j
运算符来引用上面显示的单元格,或者您可以编写使用->
运算符进行结构成员引用的等效表单。替代方案如下所示:
.
查看两者并告诉我您是否有疑问。我已使用两个#include <stdio.h>
#include "gw.h"
#define ROWS 10
#define COLS 10
int main (void) {
GW *world = gw_build (ROWS, COLS, 34, 1);
int i, j;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
world[i * ROWS + j].Alive = (i * ROWS + j) % 3;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
printf (" world[%2d][%2d] : %d\n", i, j, world[i * ROWS + j].Alive);
return 0;
}
语句来修复#define
和nrows
示例。编译并运行代码,您将看到输出:
ncols
答案 1 :(得分:1)
在引擎盖下,二维数组只是一维数组。通过在引用元素时进行一些数学运算,可以将一维数组视为二维数组。
查看这篇文章了解一些好的细节
答案 2 :(得分:0)
extern GW *gw_build(int nrows, int ncols, int pop, int rnd);
这意味着gw_build返回指向一维数组的指针。
您要实现的是二维数组:
World[0][0] -> Alive = 2
无论如何,初始化二维数组的方法是:
gw *world[r];
for (i=0; i<r; i++)
world[i] = (int *)malloc(rowsize * sizeof(gw));
现在,调用gw_build列次数,因为gw_build只能返回一行。
for(i=0;i<row;i++)
world[i] = gw_build();
答案 3 :(得分:0)
正如basav在他/她answer中所指出的,创建者函数的定义允许仅返回指向1D数组的指针。
然而,您可以使用讨厌的铸造锤来返回2D阵列:
#include <stdio.h>
#include <stdlib.h>
struct gw_struct
{
int Alive;
int row;
int column;
int id;
};
typedef struct gw_struct GW;
#define ROWS 50
#define COLS 50
GW * gw_build(int nrows, int ncols, int pop, int rnd)
{
GW * pgw = malloc(nrows * ncols * sizeof *pgw);
/* To access the array members do: */
{
GW (*world)[ncols] = (GW (*)[ncols]) pgw; /* "Dirty" casting here. */
world[0][0].row = 0;
world[0][0].column = 0;
...
}
return pgw;
}
int main(void)
{
GW (*world)[COLS] = (GW (*)[COLS]) gw_build(ROWS, COLS, 34, 1); /* "Dirty" casting here. */
world[0][0].Alive = 2;
world[0][1].Alive = 2;
world[1][0].Alive = 2;
world[1][1].Alive = 2;
world[2][0].Alive = 2;
world[2][1].Alive = 2;
...
free(world);
return 0;
}
basav 解决方案的不同之处在于您最终得到了一个线性数组,即所有元素都放在 one 内存块。
注意:摆脱&#34;脏&#34;你可以使用另一个技巧,即引入一个临时的void
指针。
为此,请替换此
GW (*world)[COLS] = (GW (*)[COLS]) gw_build(ROWS, COLS, 34, 1);
通过
GW (*world)[COLS] = NULL;
{
void * p = gw_build(ROWS, COLS, 34, 1);
world = p;
}
最后的注释:我上面展示的技巧并不好看。不要在绿地上这样做。我刚刚展示了如何绕过破碎的规范。