Click to See Complete Forum and Search --> : Writing to a struct in an array


AndrewJenkins
August 1st, 2002, 02:57 AM
I have a structure in which there is another structure which has an array of 512 pointers to it.. if that made no sense:

struct TREEFILE
{
char *name;
struct FILEINFO
{
char *field;
char *key;
char *value;
}*fileInfo[512];
};

What I want to do is assign values to that substructure with the array being at any one of those 512, once again if that made no sense.. lets say Ive already set int arrayLine to be 0:

strcpy(tFile.fileInfo[arrayLine]->key, "_FIELD_");
strcpy(tFile.fileInfo[arrayLine]->key, "_KEY_");
strcpy(tFile.fileInfo[arrayLine]->key, "_VALUE_");

This compiles all well and fine, but as soon as the program runs I get an illegal opperation... and those lines, well any one by itself is causing the problem. Ive also figured out that I only get problems when I try to add a value to that sub-structure. So this works:

tFile.fileInfo[arrayLine]->key;
/* But this wont */
strcpy(tFile.fileInfo[arrayLine]->key, "_VALUE_");

Im lead to believe my problem could be allocating the right amount of memory, or some problem with writing to memory.
Sorry that this may be tough to understand, but its 4am :)
If anyone has any ideas or answers thatd be great. Thanks.

Elrond
August 1st, 2002, 03:58 AM
You need to reserve memory for every single char* in which you want to write. And as long as you don't reserve memory, you'd better make all of it point to NULL.

You need a constructor for your structure that will NULL all pointers at the creation of the object.

Then you'd better use a member function of your structure to assign values instead of a direct use of strcpy. This way you will be able to handle the memory assignment.

Your asignment function should be something like:

AssignKey(int arrayLine, char newkey[])
{
if(tFile.fileInfo[arrayLine] == NULL)
{
tFile.fileInfo[arrayLine] = new FILEINFO;
tFile.fileInfo[arrayLine]->field = NULL;
tFile.fileInfo[arrayLine]->key = NULL;
tFile.fileInfo[arrayLine]->value = NULL;
}

if(tFile.fileInfo[arrayLine]->key != NULL)
delete [] tFile.fileInfo[arrayLine]->key;

tFile.fileInfo[arrayLine]->key = new char[strlen(newkey)+1];
strcpy(tFile.fileInfo[arrayLine]->key, newkey);


}

Just for your information, I have written that without testing anything, it requires that at least the memory for your array object was reserved in the constructor. If you want to go with this,, make sure that everything is ok, this is just a starting point.

Graham
August 1st, 2002, 03:58 AM
You appear to have two missing memory allocations:

1) For each entry in fileInfo, you need to allocate enough memory for a FILEINFO structure, and

2) For each (allocated) FILEINFO structure, you need to allocate memory for the field, key and value fields.

I suspect that 2) is the root of your problem.

Oh, and don't forget that "name" also needs memory allocated for it.

AndrewJenkins
August 1st, 2002, 10:34 AM
Alright, I gotcha, one more question... Im still new with structures, so how do I add a constructor and destructor. I dont see how it can be exactly like you would with classes. Would you have to just call that allocate memory function before you do anything wiht that structure?

Elrond
August 1st, 2002, 10:42 AM
A structure is a class with its member public instead of private by default.

You can add a constructor to a structure exactly as you would add a constructor in a class:


struct TREEFILE
{
char *name;
struct FILEINFO
{
char *field;
char *key;
char *value;
}*fileInfo[512];

TREEFILE();
~TREEFILE();
};


TREEFILE::TREEFILE()
{
int i;
for( i=0; i<512; i++)
fileInfo[i] = NULL;
}

TREEFILE::~TREEFILE()
{
int i;
for( i=0; i<521; i++)
{
if( fileInfo[i] )
{
if( fileInfo[i]->field ) delete [] fileInfo[i]->field;
if( fileInfo[i]->key ) delete [] fileInfo[i]->key;
if( fileInfo[i]->value ) delete [] fileInfo[i]->value;
delete fileInfo[i];
}
}
}

I think that's it.

AndrewJenkins
August 1st, 2002, 10:47 AM
Well crap, thats easy :) Thanks man.

AndrewJenkins
August 1st, 2002, 11:17 AM
Hmn, well, I got it to write, but in the deconstructor where it deletes all the allocated memory... the program crashes.

keyser_soze@usa
August 1st, 2002, 12:36 PM
the for loop in the destructor is taking you out of bounds (521 instead of 512)

-KS

AndrewJenkins
August 1st, 2002, 05:50 PM
Ya, I got that, but Ive narrowed it down to this specific line

delete fileInfo[i];

Why wouldnt it be able to delete the entire part of the array?

Graham
August 2nd, 2002, 04:52 AM
#include <string>
#include <vector>

struct TREEFILE
{
struct FILEINFO
{
std::string field;
std::string key;
std::string value;
};

std::string name;
std::vector<FILEINFO> fileInfo;
};

No memory problems with that version. No constructors or destructors needed. Not restricted 512 elements in the vector, or wasted space if less than 512 are needed.

Elrond
August 2nd, 2002, 04:56 AM
It depends how you allocated the memory.

May be a delete [] fileInfo will be more appropriate after the loop.

AndrewJenkins
August 2nd, 2002, 09:28 AM
Alright, thanks guys...
Graham: Im trying to stay away from any of those classes and take the hard way out ;)
Actually Im trying to get a better understanding of how memory allocation is handled.

Graham
August 2nd, 2002, 09:59 AM
Well, I just hope that doing what you're doing will help to convince you that there is a better way..... ;)

Sam Hobbs
August 2nd, 2002, 07:35 PM
In the following:

strcpy(tFile.fileInfo[arrayLine]->key, "_FIELD_");
strcpy(tFile.fileInfo[arrayLine]->key, "_KEY_");
strcpy(tFile.fileInfo[arrayLine]->key, "_VALUE_");

The data you are copying from are constants. The destination is specifed using ponters, as others have indicated. You need to have storage for the strings pointed to. Yet in the case of constants the memory will already exist. So you might be able to do:

tFile.fileInfo[arrayLine]->key = "_FIELD_";
tFile.fileInfo[arrayLine]->key = "_KEY_";
tFile.fileInfo[arrayLine]->key = "_VALUE_";

That sets the pointers to the address of the string constants. This would not work if you need to change the strings.

Alternatively something such as the following would work:

tFile.fileInfo[arrayLine]->key = new char[8];
strcpy(tFile.fileInfo[arrayLine]->key, "_FIELD_");
tFile.fileInfo[arrayLine]->key = new char[6];
strcpy(tFile.fileInfo[arrayLine]->key, "_KEY_");
tFile.fileInfo[arrayLine]->key = new char[8];
strcpy(tFile.fileInfo[arrayLine]->key, "_VALUE_");
// Use the strings, then when you are through:
delete [] tFile.fileInfo[arrayLine]->key;
delete [] tFile.fileInfo[arrayLine]->key;
delete [] tFile.fileInfo[arrayLine]->key;


Doing fancy things like constructors and destructors is probably worthwhile but probably are also not necessary.