如何在C语言中的struct中创建动态数组?

时间:2013-01-13 19:44:34

标签: c arrays struct

我目前在win7 64bit上使用VS2008 Express,使用C(非C ++)和OpenGL。有这个软件3d引擎,我已经编写了一段时间,并有时间从文件加载对象。最大的变化是从结构中的静态数组(完成和灰尘)转移到结构中的动态数组(痛苦)。

结构如下:

// the structure for handling an object
struct ObjectHolder
{
    int iVertexCount;     //number of vertices of object being loaded 

    //float fVerticeStore[48];  //actual vertex data read from file
                                     //changing to dynamic
                                    //this works but is not scalable

    //my dynamic array test
    float *fpVerticeStore = NULL;   //should be dynamic

};

好的,然后我在初始化引擎时调用了一个函数。

  1. 它实例化struct
  2. 打开包含对象数据的文件
  3. 然后将数据读取到动态数组
  4. 沿途测试任意错误
  5. void weLoad_file_objects_to_memory()
    {
    
        int i = 0; 
    
        ifstream indata; // nuf said
    
        int num1, num2, num3; // variables to hold vertex data
        char tag[2];          // tag holds the abbreviation of the data type being loaded
                            //such as vc = vertexcount, v = vertex, l = line
                            //mildly similar to .obj format 
    
        indata.open("construct.dat"); // opens the file
    
        if(!indata) 
        { // file couldn't be opened
                cerr << "Error: file could not be opened" << endl;
        exit(1);
    
        }
    
        struct ObjectHolder weConstructObject;  //struct instantiated here
    
        indata >> tag;   //tag simply tests for type of data in file
    
        if ( tag == "vc") 
        {
            indata >> weConstructObject.iVertexCount;
    
            //set size of dynamic array ie: the Vertex Store 
    
            //first try using "new" does not work
            //weConstructObject.fpVerticeStore = new int[weConstructObject.iVertexCount]; 
    
            //second try using malloc does not work
            weConstructObject.fpVerticeStore = (float*) malloc(32 * sizeof(float));
        }
        else
        {
            MessageBox(NULL,"Vertex Count Error!","VERTEX COUNT ERROR",MB_OK|MB_ICONEXCLAMATION);
            //break;
        }
    
    
        //read in vertex data from file
        while ( !indata.eof() ) 
        { // keep reading until end-of-file
        indata >> tag >> num1 >> num2 >> num3;
    
        if (tag == "v") 
        {
            weConstructObject.fpVerticeStore[i++] = float(num1);
            weConstructObject.fpVerticeStore[i++] = float(num2);
            weConstructObject.fpVerticeStore[i++] = float(num3);
        }
        else
        {
            MessageBox(NULL,"Vertex Store Error!","STORE ERROR",MB_OK|MB_ICONEXCLAMATION);
            //break;
        }
    
    }
       indata.close();
       //cout << "End-of-file reached.." << endl;
       //return 0;
    
    } 
    

    关闭发动机时,以下情况适用

    // Delete all dynamic arrays
    delete [] weConstructObject.fpVerticeStore; // When done, free memory pointed to.
    weConstructObject.fpVerticeStore = NULL; // Clear to prevent using invalid memory reference.
    

    construct.dat看起来像

    vc 16
    v -20 0 20
    v -10 0 20
    ...
    

    这个问题有很多版本,很令人困惑。我喜欢保持我的代码简单。任何人都可以弄清楚为什么我会遇到编译错误?

    only static const integral data members can be initialized within a class
    

4 个答案:

答案 0 :(得分:0)

您至少有一个问题,编译器抱怨这个问题:

// the structure for handling an object
struct ObjectHolder
{
    int iVertexCount;     //number of vertices of object being loaded 

    //float fVerticeStore[48];  //actual vertex data read from file
                                     //changing to dynamic
                                    //this works but is not scalable

    //my dynamic array test
    float *fpVerticeStore; // = NULL;   //should be dynamic
    //You cannot initialize inside the definition of the struct.  

};

struct ObjectHolder objHolder;
objHolder.fpVerticeStore = (float*) malloc(32 * sizeof(float)); //allocate memory

// do stuff

free(objHolder.fpVerticeStore); //Free memory

此外,在C中,您必须使用malloc动态分配内存,并free再次释放内存。在C ++中,您分别使用newdelete

另一个问题是:

if (tag == "v") 

你有一个char数组,所以如果你想检查元素的值是什么,你需要索引数组并进行比较,如下所示:

if (tag[0] == 'v') { }

在C ++中,你永远不会这样做:

 while ( !indata.eof() ) 
 { // keep reading until end-of-file
  indata >> tag >> num1 >> num2 >> num3;

相反,你最好这样做:

 while ( indata >> tag >> num1 >> num2 >> num3 ) {}

答案 1 :(得分:0)

您可以在结构中声明一个指针,并使用malloc()设置其初始大小,然后在代码中从输入文件中读取的部分中包含if语句,必要时将realloc()。

初始内存分配

//When comparing a string to a pointer you MUST use strcmp()
if (strcmp(tag, "vc")==0) 
{
    //You should not need to typecast your pointer as float pointer unless it is
    //declared as something else i.e. char int
    weConstructObject.fpVerticeStore = (float*) malloc(32 * sizeof(float));

    //You should instead allocate your memory this way note that I allocate
    //size+1 the +1 being for the NULL terminating character. So the usable space of
    //in your array is size not size-1.
    int size = 32;
    weConstructObject.fpVerticeStore = malloc(sizeof(float)*size+1)
    if(weConstructObject.fpVerticeStore == NULL)
    {
      //Error
    }
}
else
{
    MessageBox(NULL,"Vertex Count Error!","VERTEXCOUNTERROR",MB_OK|MB_ICONEXCLAMATION);
    //break;
}
int size = 32;
weConstructObject.fpVerticeStore = malloc(sizeof(float)*size+1)

必要时重新分配内存

while(!indata.eof())
{
   indata >> tag >> num1 >> num2 >> num3; 
   if(i >= size) //i should represent your current index in the array
   {
     size *= 2;
     float *tmp = realloc(weConstructObject.fpVerticeStore, sizeof(float)*size+1)
     if (tmp == NULL)
     {
        //Error
     }
     else
     {
       weConstructObject.fpVerticeStore = tmp;
       //You should now have size*2 usable space in your array.
     }
   }
   //You don't have to use strcmp() here if you know where the character constant v
   //will be located in your array i.e if (tag[0] == 'v')
   if (strcmp(tag, "v")==0)
   {
     weConstructObject.fpVerticeStore[i++] = float(num1);
     weConstructObject.fpVerticeStore[i++] = float(num2);
     weConstructObject.fpVerticeStore[i++] = float(num3);
   }
   else
   {
     MessageBox(NULL,"Vertex Store Error!","STORE ERROR",MB_OK|MB_ICONEXCLAMATION);
     //break;
   }
}

答案 2 :(得分:0)

如果在结构中只需要一个动态数组,则可以选择使用“struct hack”(原始形式或C99形式)

struct ObjectHolder
{
    int iVertexCount;
    float fpVerticeStore[]; /* use `[1]` for C89/90 */
};


int iVertexCount;
...
struct ObjectHolder *p = malloc(offsetof(ObjectHolder, fpVerticeStore) + 
  iVertexCount * sizeof *p->fpVerticeStore);
p->iVertexCount = iVertexCount;
...

或独立动态分配的数组

struct ObjectHolder
{
    int iVertexCount;
    float *fpVerticeStore;
};


ObjectHolder holder;
...
holder.fpVerticeStore = 
  malloc(holder.iVertexCount * sizeof *holder.fpVerticeStore);

请注意,在第一种情况下,必须动态分配包含嵌入数组的整个ObjectHolder,这意味着在知道确切的数组大小之前,不能预先创建ObjectHolder。在第二种方法中,ObjectHolder本身的分配方式完全无关紧要。

此外,在第二种方法中,可能根本不需要动态分配,假设它符合您对阵列生命周期的要求

struct ObjectHolder
{
    int iVertexCount;
    float *fpVerticeStore;
};


ObjectHolder holder;
...
float vertices[holder.iVertexCount];
holder.fpVerticeStore = vertices;

选择更符合您要求的方法。

答案 3 :(得分:0)

Chaps,非常感谢。我有它的工作。但是我决定使用AndreyT的第二个例子。原因是灵活性和独立性。我需要在代码中的另一个位置进行结构声明,因此需要(如AndreyT所称)一个独立的动态分配数组。

我对AndreyT的代码做了一个修复。 malloc生成错误,因此需要一个(float *)在它之前。非常感谢AndreyT和其他用户评论。

如果你需要这个有用的功能,这是可编辑的代码:享受!

李在Sourceforge的WorldEngin项目

#include <windows.h>    
//file handler
#include <iostream>
    using std::cerr;
    using std::cout;
    using std::endl;

#include <fstream>
    using std::ifstream;

#include <cstdlib> // for exit function
//end file handler


struct ObjectHolder
{
    int iVertexCount;
    float *fpVerticeStore;
};

ObjectHolder holder;

//float vertices[holder.iVertexCount];


int main(void)
{
    ifstream indata; // nuf said

float num1, num2, num3; // variables to hold vertex data
char tag[2];          // tag holds the abbreviation of the data type being loaded
                    //such as vc = vertexcount, v = vertex, l = line
                    //mildly similar to .obj format 

indata.open("construct.dat"); // opens the file
 if(!indata) 
{ // file couldn't be opened
        cerr << "Error: file could not be opened" << endl;
exit(1);

}
indata >> tag;   //tag simply tests for type of data in file

if (strcmp(tag, "c")==0) 
{
    indata >> holder.iVertexCount;

    //holder.fpVerticeStore = vertices;
    holder.fpVerticeStore = (float*)malloc(holder.iVertexCount * sizeof *holder.fpVerticeStore);
}
else
{
    MessageBox(NULL,LPCSTR("Vertex Count Error!"),LPCSTR("VERTEX COUNT ERROR"),MB_OK|MB_ICONEXCLAMATION);
    //break;
}

 printf("vertex count %d\n", holder.iVertexCount);
int j = 1;
//read in vertex data from file
while ( !indata.eof() ) 
{ // keep reading until end-of-file
    indata >> tag >> num1 >> num2 >> num3;
    int i = 0;
    if (strcmp(tag, "v")==0) 
    {
        printf("vertex %d", j++);

        holder.fpVerticeStore[i++] = num1;
        printf(" %f", holder.fpVerticeStore[i - 1]);

        holder.fpVerticeStore[i++] = num2;
        printf(" %f", holder.fpVerticeStore[i - 1]);

        holder.fpVerticeStore[i++] = num3;
        printf(" %f\n", holder.fpVerticeStore[i - 1]);
    }
    else
    {
        MessageBox(NULL,LPCSTR("Vertex Store Error!"),LPCSTR("STORE ERROR"),MB_OK|MB_ICONEXCLAMATION);
        //break;
    }

}
indata.close();

//return 0;
}