在单独的函数中创建指向数组的struct指针

时间:2015-10-04 03:27:45

标签: c function multidimensional-array data-structures parameter-passing

我无法创建和访问结构指针作为数组。这是一个家庭作业问题,但这只是我对操作的误解。

我的头文件(我无法更改并且必须以这种方式实现)包含:

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函数返回来设置它,它根本不起作用。因此,我尝试更改返回类型,但再次导致返回错误无效。

感谢任何指导,谢谢!

4 个答案:

答案 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]后面代表ii * 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; } 语句来修复#definenrows示例。编译并运行代码,您将看到输出:

ncols

答案 1 :(得分:1)

在引擎盖下,二维数组只是一维数组。通过在引用元素时进行一些数学运算,可以将一维数组视为二维数组。

查看这篇文章了解一些好的细节

Performance of 2-dimensional array vs 1-dimensional array

答案 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;
  }

最后的注释:我上面展示的技巧并不好看。不要在绿地上这样做。我刚刚展示了如何绕过破碎的规范。