Sign in to follow this  
DMINATOR

C and struct pointers

Recommended Posts

Well everything was working fine as supposed to be, but once i started using struct pointers i encountered a problem here is sample code i made to demonstrate my problem

#include <stdio.h>
#define TESTSTR "testing"


typedef struct TEST TEST;


//just for testing
struct TEST
{
   char* somestring;
   int someint;

};


//our test variable
TEST* test1;
TEST* test2;
TEST* test3;

int main()
{
    //this would be the main structure
	test1 = (TEST*)malloc(sizeof(TEST));

	//assigning values to first variable
    test1->someint = 10;
	test1->somestring = (char*)malloc(sizeof(TEST) * (sizeof(TESTSTR) + 1) );
	sprintf(test1->somestring,"%s",TESTSTR);

    test2 = test1;
	test3 = test1;

	//just testing some variables

	printf("struct1=%s\tstruct2=%s\tstruct3=%s\n",test1->somestring,test2->somestring,test3->somestring);
    
	//freeing first variable
	free(test1->somestring);
	free(test1);
	test1 = NULL;


	printf("struct1=%s\tstruct2=%s\tstruct3=%s\n",test1->somestring,test2->somestring,test3->somestring);

	return 0;
}



As I understand the problem is that test2 and test3 refer to test1 fields, but as test1 is freed the they are also freed . My question is : How can i save the test2 and test3 data intached but still freeing test1. Tnx in advance

Share this post


Link to post
Share on other sites
You are declaring 3 pointers (3 longs) that point to a struct in memory. They all point to the same memory location, free one of them, then they all are freed.

What you want is to create a temporary clone of the struct, and have test2 and test3 pointing at it. Its just effectively the same code, as with test1.

Share this post


Link to post
Share on other sites
test2 and test3 are both pointing to the memory allocated for test1. To copy them, you'll need to allocate memory for both test2 and test3 and perform a memcpy (or otherwise) to copy the data of test1 into each of the other two.


TEST* test1;
TEST* test2;

// test1 is a POINTER to a memory block allocated by malloc
test1 = (TEST*)malloc(sizeof(TEST));

// test2 now points to the same memory area as test1. Freeing either test2 or test1 will free the memory for both (as they point to the same memory).

test2 = test1;

// The same is true if you alter any of the memory
test2->someint = 10; // this will change both test1 and test2's int as they point to the same memory

// To maintain independent data, you need to allocate memory for each struct
test2 = (TEST*)malloc(sizeof(TEST));
// Copy the data in test1 into test2
memcpy( test2, test1, sizeof(TEST) );

// YOu are now free to alter the memory as you see fit - but remember that each will need to be free'd separately

free( test1 );
free( test2 );





Edit: 'pointering' ?! I think I must have made that word up [grin]

Share this post


Link to post
Share on other sites
if i was you, i'd make a function that actually copied the data from pointer to another and not just assign them to each other.

something like this:

void actualPointerCopy (TEST **src, TEST **dest) {

//maybe memcpy would work here, i'm not sure.

*dest->someInt = *src->someInt;
strcpy(*dest->somestring, *src->somestring);
}

int main ()
{
actualPointerCopy (&test1, &test2);
}

Share this post


Link to post
Share on other sites
Quote:
Original post by DMINATOR
Well everything was working fine as supposed to be, but once i started using struct pointers i encountered a problem here is sample code i made to demonstrate my problem

*** Source Snippet Removed ***

As I understand the problem is that test2 and test3 refer to test1 fields, but as test1 is freed the they are also freed .

My question is :

How can i save the test2 and test3 data intached but still freeing test1.

Tnx in advance


Technically, since test2 and test3 all point to test1, you don't have to free test1. Freeing any of the three will acomplish the same thing, because they _are_ the same thing.

If you want to free test1 but keep test2 and test3, then you will have to make copies of test1 and assign them to test2 and test3.

Also, why this?:
test1->somestring = (char*)malloc(sizeof(TEST) * (sizeof(TESTSTR) + 1) );

If you are allocating memory for a string, then you should probably just need this:
test1->somestring = (char*) malloc(sizeof(char) * strlen(TESTSTR) + 1);

This is the size of one character times the number of characters plus one for the trailing NUL (zero) character, as standard C strings are "zero terminated."

The size of TEST doesn't have anything to do with the size of the string. Technically, in your example sizeof(TESTSTR) works because you've defined TESTSTR as an array implicitly at compile time. However, you should get in the habit of testing string lengths with the approprate strlen function. The sizeof operator will not work if you use it on test1->something because you allocated the space it at runtime with malloc. So for consistency it is easier (IMO) to stick with strlen for all strings.

Share this post


Link to post
Share on other sites
Quote:
Original post by evolutional
test2 and test3 are both pointering to the memory allocated for test1. To copy them, you'll need to allocate memory for both test2 and test3 and perform a memcpy (or otherwise) to copy the data of test1 into each of the other two.

*** Source Snippet Removed ***

i was thinking about memcpy, but i thought it acted kinda "funky" when it came to copying data from pointer to pointer?

Share this post


Link to post
Share on other sites
I can't say I've had any problems with memcpy myself, but as you showed, copying each data member individually would resolve any issues should they crop up.

Edit: One thing I missed was the string assignment, in which case you're right, memcpy wouldn't be adequate - you'd need strcpy (as others have pointed out) as memcpy would just copy the string pointer across.

Share this post


Link to post
Share on other sites
Quote:
Original post by DMINATOR
Well everything was working fine as supposed to be, but once i started using struct pointers i encountered a problem here is sample code i made to demonstrate my problem

*** Source Snippet Removed ***

As I understand the problem is that test2 and test3 refer to test1 fields, but as test1 is freed the they are also freed .

My question is :

How can i save the test2 and test3 data intached but still freeing test1.

Tnx in advance


You'll have to create another struct. Something like:

test2 = malloc(sizeof *test2);
memcpy(test2, test1, sizeof *test2);
test2->somestring = malloc(strlen(test1->somestring)+1);
strcpy(test2->somestring, test1->somestring);

memcpy() is appropriate since we are certain that test1 and test2 don't overlap. strcpy() is appropriate since we know test2->somestring is large enough. memmove() and strncpy() would also make good choices, but I think memcpy() and strcpy() are better in this case.

Note also some style changes. Using "sizeof *var" instead of "sizeof(type)" makes it more robust. Also, not casting malloc() makes it more robust. If your compiler complains, you're compiling in C++, in which case you should be using new/delete instead of malloc()/free().

Share this post


Link to post
Share on other sites
Quote:
Original post by Alpha_ProgDes
i was thinking about memcpy, but i thought it acted kinda "funky" when it came to copying data from pointer to pointer?


Only if the data they point to overlap (e.g. shifting the elements of an array). memmove() has to do the right thing even if they overlap, which means it has to check which direction to copy the memory from. memcpy() can avoid the check and, if one direction is faster, will likely use that direction (I used to here it was faster to decrement through a for loop than increment? Personally, don't even know if that'd be related).

Also, memcpy() will only copy the pointer to the malloc()'d string. Since the OP free()'d this string, it's probably appropriate to copy it also.

Share this post


Link to post
Share on other sites
Quote:
Original post by evolutional
test2 and test3 are both pointering to the memory allocated for test1. To copy them, you'll need to allocate memory for both test2 and test3 and perform a memcpy (or otherwise) to copy the data of test1 into each of the other two.

*** Source Snippet Removed ***


The "somestring" member of test is also dynamically allocated. So, you are going to have to remember to deallocate this too _before_ you free test1.

free(test1->somestring);
free(test1);

Consider this:

/* copying test1 */
test2 = (TEST *) malloc(sizeof(TEST));
memcpy(test2, test1, sizeof(TEST));
/* freeing test1 */
free(test1->somestring);
free(test1);

You will have a problem here because you have not made a copy of somestring. When you make the copy of test1 you also need to copy somestring:

/* copying test1 */
test2 = (TEST *) malloc(sizeof(TEST));
memcpy(test2, test1, sizeof(TEST));
test2->somestring = (char *) malloc(sizeof(char) * strlen(test1->somestring) + 1);
strcpy(test2->something, test1->something);

/* freeing test1 */
free(test1->somestring);
free(test1);

Your best bet would be to write a dedicated function to making copies and deallocation of TEST structs.


TEST* cpytest(TEST* src)
{
TEST* dest = NULL;

dest = (TEST*) malloc(sizeof(TEST));
if(dest == NULL) {
fprintf(stderr, "Could not allocate for copy of TEST\n");
exit(1);
}
memcpy(dest, src, sizeof(TEST));
dest->somestring = (char*) malloc(sizeof(char) * strlen(src->somestring) + 1);
if(dest->something == NULL) {
fprintf(stderr, "Could not allocate for copy of string\n");
exit(1);
}
strcpy(dest->somestring, src->somestring);

return dest;
}

void freetest(TEST* test)
{
free(test->somestring);
free(test);

return;
}

Share this post


Link to post
Share on other sites
Thanks' all of you for the replyes, Well i got it working and my struct is almost functional, no memory leaks were found, but still I am going to debug it for a while. Still i am not complitly satisfyed with my code, it may have some hidden supprises :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this