Click to See Complete Forum and Search --> : Passing the Address of the Pointer for an Array of Structures


June 28th, 1999, 10:42 AM
Hello,

I have a question. I have an array of structures that I allocate in main() and then pass the address of the pointer to a function. In the function I use the address to change on of the attributes in one of the arrays. When I return to the main() the attribute that I changed is incorrect - unititliaized ?? In the sample code below you see that I have tryed this will an integer (just to prove that my brain is working) and a simple array using malloc (this works) and then with my array of structs (this fails). Any comments would be appreciated. Sorry that we are not using C++ ... so sad ... I am writting for NT and Unix ... bla bla bla

// the structures
struct filenames
{
char szName[NAME_LEN];
int nIndex;
};

struct control
{
int nCurrentRecord;
int nTotalRecords;
};

// the function prototype
void TestFunction(struct filenames **, struct control *, int *);



// main
main()
{

// the simple int that we will pass
int nTest = 0;
int nTemp = 0;

// these are the pointer that we pass
struct control *pControl = NULL;
struct filenames *pFilenames = NULL;

// allocate memory for the array of structs
pFilenames = (struct filenames *)calloc( 1, sizeof(struct filenames));

// alocate memory for an array
pControl = (struct control *)malloc(sizeof(struct control));

// set the initial data
nTest = 99;
pControl->nCurrentRecord = 567;
pFilenames->nIndex = 9876;


// call the TestFunction passing the address of the array of structs, a pointer to a struct and the address of the int
TestFunction(&pFilenames, pControl, &nTest);

// on return we have access the data that has changed
// this should be 88 ... and it is
nTemp = nTest;
// this should be 4567 ... and it is
nTemp = pControl->nCurrentRecord;
// this should be 123 ... and it is not - uninitailized
nTemp = pFilenames->nIndex;

}



void TestFunction(struct filenames **pFilenames, struct control *pControl, int *nTest)
{

// change the value of nTest using the address of the integer
*nTest = 88;

// change the value of nIndex using the dereferenced address of the array of structs
(*(*pFilenames)).nIndex = 123;

// change the value of nCurrentRecord using the pointer passed in
pControl->nCurrentRecord = 4567;

return;
}

Paul McKenzie
June 28th, 1999, 11:15 AM
In C++, the name of the array serves the purpose of being the address of the first element of the array. Instead of passing a pointer to the first element of the array, you passed the address of the array itself (which is not the same as the address of the first element of the array). For your purposes, there is a better way of doing what you want to do.

Since you already created the array of structures in main(), all you need is to pass the address of the first element. Once TestFunction() knows the address of the first element, it will know where every element is, since *(struct + n) or struct[n]is always element n of the array of structures. Here are the changes:

In main():
// call the TestFunction passing the address of the array of structs, a pointer to a struct and the address of the int
TestFunction(pFilenames, pControl, &nTest); <<--Note that the "&" from pFileNames has been removed.

In TestFunction():
void TestFunction(struct filenames *pFilenames, struct control *pControl, int *nTest) <<--Note only one "*" on pFileNames
{

// change the value of nTest using the address of the integer
*nTest = 88;

// change the value of nIndex using the dereferenced address of the array of structs
pFileNames[whatever].nIndex = 123; <<--"whatever is the index number of the structure that you want to change.

// change the value of nCurrentRecord using the pointer passed in
pControl->nCurrentRecord = 4567;

return;
}

The one reason for passing a pointer to an array (as you did in your code using "**" ) is if TestFunction() allocated the array of structures and passed back a pointer to the new array. In that case, you would want to pass the address of the array, since TestFunction() is returning a new "*array".

Regards,

Paul McKenzie

June 28th, 1999, 11:36 AM
Hi Paul - Thanks for the response.

I implemented your changes. They do not seem to work as desired. I am setting a value to pFilenames->nIndex in main() and then I pass the pointer to the array into TestFunction() as you recommended then I do not see the correct value in nIndex that I set in main. I think that I do need to pass the address to the array of structures in some way ???

In the end ... as you mentioned at the end of your comments ... I would like to allocate this array in main() and then grow the array using calloc() in some other function, so I will need a way to pass the address of the array of structs around. Any suggestions.

Thanks
Chris Macgowan

Paul McKenzie
June 28th, 1999, 01:32 PM
What you want to do is something that is done all the time. You do not need to pass the address of the structure, the name is all that you need. (I've been doing this a looonnnnnnggg time, trust me! :-() )

First are you sure that you made the changes?

Second, you are passing a pointer to the start of the array. Look in your debugger to verify this. If you wanted to access a particular element of this array in TestFunction() you must prototype the function to accept a pointer to a struct filename (only one "*"). One of the following (assuming that the array is p and "whatever" is the index) is done within TestFunction() to access the element:

- add "whatever" (like in a loop or something) to the pointer p and then you can say p->nIndex.

- dereference the pointer starting at the base and using whatever as the offset (say p[whatever].nIndex or (p + whatever)->nIndex or (*(p+whatever)).nIndex )

The calloc() that you want to call from another function can be done in a number of ways. Here are two (not tested, but should work):

// Now we use the "**"! This method is responsible for taking the original pointer and assigning the new memory
void GetMeMore(struct filenames**pOld, int n)
{
*pOld = calloc(*pOld, (n * sizeof(struct filename));
}

OR
// Return a pointer to the calloc() memory. Our caller will be responsible for assigning the return value in this case:
struct filename *GetMeMore(struct filename *p, int n)
{
return calloc(p, (n * sizeof(struct filename));
}

Also, it is always better to use "typedef struct" in your definition of the structures rather than just "struct". By using a typedef, you save yourself typing the word "struct" everywhere:

typedef struct tagfilenames
{
...
} filenames;


Regards,

Paul McKenzie

Paul McKenzie
June 28th, 1999, 02:03 PM
Sorry about the calloc(). I was thinking realloc() instead. The calloc() should be written like this

void GetMeMore(struct filename**pOld, int n)
{
*pOld = (struct filename *)calloc(n, sizeof(struct filename));
}

OR

struct filename *GetMeMore(int n)
{
return (struct filename *)calloc(n, sizeof(struct filename));
}

Regards,

Paul McKenzie

June 29th, 1999, 02:16 PM
Paul -

Thanks for the HELP !!
In case you are checking ... I am still working on things ... making progress
Thanks again for your Help!
Chris Macgowan