Click to See Complete Forum and Search --> : Passing array of struct as reference


elireu
October 11th, 2005, 04:39 PM
Hi there,
I'm trying to pass a pointer to struct to a function , the function has to process and store data in the array. This is the code, when running the program it crushes. I don't want to return the pointer (like: return MyArrayPtr), I need to point the passed pointer to the new memory address.
Thanks, Eli

#include <stdio.h>
#include <malloc.h>

typedef struct
{
char name[80];
int id;
}MyStruct;

int MyFunc(MyStruct *MyPtr);

void main()
{
int i;
MyStruct *MyPtr = NULL;

MyFunc(MyPtr);

for(i=0;i<100;i++)
{
printf("Name: %s, id: %d\n",MyPtr[i].name, MyPtr[i].id );
}
}

int MyFunc(MyStruct *MyPtr)
{
int i;

MyStruct *MyArrayPtr = (MyStruct*)malloc(sizeof(MyStruct)*100);

for(i=0;i<100;i++)
{
MyPtr[i].id = i;
sprintf(MyPtr[i].name, "Eli-%d", i);
}
MyPtr = MyArrayPtr;
return 0;
}

Siddhartha
October 11th, 2005, 04:46 PM
[ redirected ]

Regards,
Siddhartha

MrViggy
October 11th, 2005, 05:01 PM
The problem is in your function declaration. You need to pass the pointer by reference, so that you can return the proper value to the caller:
int MyFunc(MyStruct* &MyPtr)
This way, the calling function will get the proper pointer back. Also, don't forget a call to 'free' after the for loop in your main program, to release the memory you allocated.

Viggy

Paul McKenzie
October 11th, 2005, 05:06 PM
Hi there,
I'm trying to pass a pointer to struct to a function , the function has to process and store data in the array. This is the code, when running the program it crushes.You are changing the value of the pointer within the function. The pointer is local to the function, therefore you don't see the new value on return. It's as if you did this:

void foo(int i)
{
i = 10;
}

int main()
{
j = 6;
foo( j );
}

Is the value of j on return 10? Or is it still 6? Of course it's still 6. The same rule applies to pointers:

void foo(int *pLocal)
{
pLocal = new int [10];
}

int main()
{
int *p=NULL;
foo( p );
}

Is the value of p what was assigned in foo(), or is it still NULL? It is still NULL.

In general to change 'x' in a function and have the changes remain when you return, you pass a pointer or reference to 'x'. Since 'x' is a pointer itself, either pass a pointer to pointer, or pass a reference to pointer.

void foo(int **pLocal) // pointer to pointer
{
*pLocal = new int [10];
}

int main()
{
int *p=NULL;
foo( &p );
}

or

void foo(int *& pLocal) // reference to pointer
{
pLocal = new int [10];
}

int main()
{
int *p=NULL;
foo( p );
}

Regards,

Paul McKenzie

elireu
October 12th, 2005, 10:30 AM
The first code: void foo(int **pLocal) crushes, though, the second code:
void foo(int *& pLocal) works well in .cpp file but doesn't pass compilation in a .c file.
error C2143: syntax error : missing ')' before '&'
error C2143: syntax error : missing '{' before '&'
error C2059: syntax error : '&'
error C2059: syntax error : ')'

Thanks
Eli

MrViggy
October 12th, 2005, 11:18 AM
Are you writing a C or C++ program?

Viggy

SuperKoko
October 12th, 2005, 11:26 AM
The first code: void foo(int **pLocal) crushes, though, the second code:

What is the exact code you used?
Are you sure to have correctly assigned the *pLocal pointer, like that:

*pLocal=MyArrayPtr;

And not like that:

pLocal=MyArrayPtr; // incorrect - and will at least generate a compilation warning for a C++ compiler!

elireu
October 12th, 2005, 11:37 AM
I'm writing "C" and compiling with VC 6. The following code passes compilation but crushes in run time.

Thanks, Eli
---------------------------
#include <stdio.h>
#include <malloc.h>

typedef struct
{
char name[80];
int id;
}MyStruct;

int MyFunc(MyStruct **MyPtr);

void main()
{
int i;

MyStruct *MyPtr = NULL;

MyFunc(&MyPtr);

for(i=0;i<100;i++)
{
printf("Name: %s, id: %d\n",MyPtr[i].name, MyPtr[i].id );
}
free(MyPtr);

}

int MyFunc(MyStruct **MyArrayPtr)
{
int i;

*MyArrayPtr = malloc(sizeof(MyStruct)*100);

for(i=0;i<100;i++)
{
MyArrayPtr[i]->id = i;
sprintf(MyArrayPtr[i]->name, "Eli-%d", i);
}
return 0;
}

Rigel
October 12th, 2005, 12:14 PM
Use this one.


#include <stdio.h>
#include <malloc.h>
typedef struct
{
char name[80];
int id;
}MyStruct;

int MyFunc(MyStruct *&MyArrayPtr)
{
int i;
MyArrayPtr = (MyStruct*) malloc(sizeof(MyStruct)*100);
for(i=0;i<100;i++)
{
MyArrayPtr[i].id = i;
sprintf(MyArrayPtr[i].name, "Eli-%d", i);
}
return 0;
}

int main()
{
int i;
MyStruct *MyPtr = NULL;
MyFunc(MyPtr);
for(i=0;i<100;i++)
{
printf("Name: %s, id: %d\n",MyPtr[i].name, MyPtr[i].id );
}
free(MyPtr);
return 0;
}

Paul McKenzie
October 12th, 2005, 12:34 PM
First, it's int main() not void main().

Second, assuming T is a type, the reason why it crashes is that you cannot process a passed in T** as an array type using [] without all the information about the underlying T*. This is one of the pitfalls that C and C++ programmers come acrosss, and that is believing that a function can handle all the pointer indirections safely when passed a T** or T***, or T****, etc. without further information. The only thing that is guaranteed to work is when you pass a T* (single indirection). References are different animals, which is why they work.

When you pass a T**, you're passing only a pointer. The calling function has no information beyond this (it doesn't know the T* part of T**, i.e. number of elements). The called function only knows about T**, but within the called function, you are accessing it as if it also knows about T* in your loop.

So the only thing you can do is to create the pointer and pass it back to the caller. Don't try to access it using [] within the calling function.

Regards,

Paul McKenzie

elireu
October 12th, 2005, 12:57 PM
Eventually, I got this code working. Is it safe enough ?
Thanks, Eli
------------------------
#include <stdio.h>
#include <malloc.h>

typedef struct
{
char name[80];
int id;
}MyStruct;

int MyFunc(MyStruct **ArrayPtr);

void main()
{
int i;

MyStruct *MyPtr = NULL;

MyFunc(&MyPtr);

for(i=0;i<100;i++)
{
printf("Name: %s, id: %d\n",MyPtr[i].name, MyPtr[i].id );
}
free(MyPtr);

}

int MyFunc(MyStruct **ArrayPtr)
{
int i;
MyStruct *MyArrayPtr;

MyArrayPtr = malloc(sizeof(MyStruct)*100);

for(i=0;i<100;i++)
{
MyArrayPtr[i].id = i;
sprintf(MyArrayPtr[i].name, "Eli-%d", i);
}
*ArrayPtr = MyArrayPtr;
return 0;
}

Paul McKenzie
October 12th, 2005, 01:13 PM
Yes, this should work. Also, please use code tags when posting. All of your code is aligned on the left side of the page, making it very difficult to read what you've posted.

The difference in your second version is that you are creating the data "from scratch" from a local MyStruct*, and then explicitly assigning the pointer passed in to the allocated memory that the local pointer is pointing to. You are not creating it from the passed in MyStruct** (which as I stated, the called function is clueless about the underlying MyStruct* when passed a MyStruct**).

Regards,

Paul McKenzie

elireu
October 12th, 2005, 02:04 PM
I just copy and past my code and it looks well aligned. what do you mean by 'code tags' ?

Thanks very much for the help
Eli

Paul McKenzie
October 12th, 2005, 02:08 PM
I just copy and past my code and it looks well aligned. what do you mean by 'code tags' ?

Thanks very much for the help
Eli
Here is your original code:

#include <stdio.h>
#include <malloc.h>

typedef struct
{
char name[80];
int id;
}MyStruct;

int MyFunc(MyStruct **ArrayPtr);

void main()
{
int i;

MyStruct *MyPtr = NULL;

MyFunc(&MyPtr);

for(i=0;i<100;i++)
{
printf("Name: %s, id: %d\n",MyPtr[i].name, MyPtr[i].id );
}
free(MyPtr);

}

Now look at this:

#include <stdio.h>
#include <malloc.h>

typedef struct
{
char name[80];
int id;
}MyStruct;

int MyFunc(MyStruct **ArrayPtr);

void main()
{
int i;

MyStruct *MyPtr = NULL;

MyFunc(&MyPtr);

for (i=0;i<100;i++)
{
printf("Name: %s, id: %d\n",MyPtr[i].name, MyPtr[i].id );
}
free(MyPtr);
}

See the difference? The way you use code tags is to enclose your code in

[ c o d e ] and [ / c o d e ] blocks (remove the spaces).

Regards,

Paul McKenzie

SuperKoko
October 12th, 2005, 02:37 PM
MyArrayPtr[i]->id = i;
sprintf(MyArrayPtr[i]->name, "Eli-%d", i);


Here is the bug!
MyArrayPtr is a valid block of 4 bytes which is a pointer to the malloced block.
So, (*MyArrayPtr) is valid, but MyArrayPtr is invalid for i>0
In fact, you use MyArrayPtr like if it was a pointer to an array of pointers to structs, but it is a pointer to a pointer to an array of structs.

The correct code is:
[code]
(*MyArrayPtr)[i].id = i;
sprintf((*MyArrayPtr)[i].name, "Eli-%d", i);
[code]
It is just some basic pointer arithmetic : [i]dereferencing then indexing, is not the same that indexing then dereferencing.

However your new code:

int MyFunc(MyStruct **ArrayPtr)
{
int i;
MyStruct *MyArrayPtr;

MyArrayPtr = malloc(sizeof(MyStruct)*100);

for(i=0;i<100;i++)
{
MyArrayPtr[i].id = i;
sprintf(MyArrayPtr[i].name, "Eli-%d", i);
}
*ArrayPtr = MyArrayPtr;
return 0;
}



Works perfectly, and is easier to write and read for non-experienced programmers.
Is easier to optimize for the compiler, so it will probably run faster.