Reputation: 85
I'm learning about pointer and dynamic array in C, but I'm not clear about pointer in C. I would appreciated if anyone could verify my understanding of the following codes based on the below information:
/*Struct*/
typedef struct {
int *pInt;
}newStruct
/*Functions*/
newStruct *createMyStruct() {
//codes
}
void printNewStruct(newStruct *pStruct) {
//codes
}
Please verify:
int *pInt
: this is an array of type int that's in the structnewStruct *createMyStruct
: a function that's named createMyStruct
. createMyStruct
is a pointer that points to newStruct
and create a copy of the newStruct
. newStruct *pStruct
: pStruct
is the same as createMyStruct
(?)Question:
1) When I use malloc
in a function (e.g. createMyStruct
function from above code) to allocate memory, where would I have to free this memory? Inside the function itself or in main
? If in main
, why in main
? I thought the memory has to be freed right away after it has been used.
My apology if my above statements aren't clear...I'm still really confuse about pointer and malloc
. Please verify/explain in simple terms for a Newbie.
Upvotes: 0
Views: 285
Reputation: 76395
Ok, I'm not going to give you a 1on1 pointer guide (I'm not planning to write a book), but here's the quick guide, based on your assumptions/questions:
int *pInt
: this is an array of type int that's in the struct"It Might be, pInt
is a pointer to an integer. It needn't be an array. An array is a pointer, but a pointer isn't always an array. Right, an array is -of course- an array, but the way you access it in C is through either an array variable or a pointer.
The differences are clearly explained here
Basically: an array is a continuous block of memory, an array variable often (well, always save for 3 cases listed on the page I linked to above) decays into a pointer. Read the why's and how's, to get a clear understanding of the differences and similarities between pointers and arrays.
If you understand why one of the following snippets is not allowed and the other one is, you're there:
char *str = "Read only";
printf("%c\n", str[2]);//prints a from (0=>r, 1=>e, 3=> a...)
str[2] = 'q';//ILLEGAL
//BUT:
char str[] = "Read only";
str[2] = 'q';//perfectly legal...
printf("%c\n", str[2]);//prints q!
Why is this? Simple. In both cases, the literall "Read only"
is stored in read-only memory. The difference is that, by assigning this string to a pointer(char *str
), we're assigning the read-only mem address to the variable, so we can't change the memory it points to (that's what read-only means).
In the second case, the string literal is stored in the same read-only memory, but because we're assigning it to an array, it's values are copied to newly allocated stack memory, and we can write to that.
So, a pointer points to some chunk of data in memory. This memory can be writable or not, the memory address could be the address of part of an array or it could be a single int (like it is in your case), You could even have pointers that point to several pointers, and each of these pointers could, essentially, point to different places in memory (ie not a continuous block).
Anyway, consider this:
int i = 123;
int arr[3] = {1,2,3};//array
int *iPtr = &i;//iPtr contains the mem address of i
printf("%d\n", *iPtr);//prints 123
iPtr = arr;//iPtr points to the same as arr (note no & operator)
printf("%d\n", *iPtr);//prints 1
//now probably a mindfuck for you now, but:
printf("%d\n", *(iPtr+1));//prints 2!
The last bit is just to show what pointers are: it's a location in memory, big enough to accomodate an int
, so if I take that space in memory, and do +1
, I'm accessing that chunk of memory right next to the one my pointer points to. In memory, this might look something like this:
| 0x0f0 | 0x0f2 | 0x0f4 | 0x0f6 | //mem address
| *iPtr | iPtr + 1 | iPtr + 2 | iPtr + 3 | //access via pointer
That's why pointers can be dangerous. In the code above, iPtr
points to the first of 3 ints (as defined in the arr
array), but if I access *(iPtr+4)
, I'm accessing memory that is out of bounds. You are accessing memory that was not claimed/initialized, or owned by something else. This can, and probably will lead to unexpected behaviour... but I have seen this used to get some extra randomization...
newStruct *createMyStruct
: a function that's named createMyStruct. createMyStruct is a pointer that points to newStruct and create a copy of the newStruct."You lost me here, this is a function definition. The function is indeed called createMyStruct
, and it returns a pointer to something of the type newStruct
. That's it, just like int some_function()
is a function that returns an int
newStruct *pStruct
: pStruct is the same as createMyStruct (?)"No, pStruct
is a pointer to a newStruct
, and pStruct
is a function argument, not a function, which createMyStruct
is.
On calling free:
You call free
on variables that are stored in memory allocated from the heap, when you don't need them anymore. If they go out of scope, you can't free them anymore, so you have to dellocate the memory when you still have a variable that points to it, but you shouldn't deallocate anything you might need later on in the program:
char *str = calloc(11, sizeof(char));
free(str);
//I can't use str here anymore
But:
int main()
{
void some_function();
some_function();
//I can't free str here, mem-leak immanent!
return 0;
}
void some_function()
{
char *str = calloc(11, sizeof(char));
//do stuff, but no calls to free
}
in this case, free(str);
should have been the last statement in some_function
. If some_function
would've been char *some_function()
and we'd have written this:
int main()
{
char *return_val = NULL;
char *some_function();
return_val = some_function();
printf("%s was returned by some_function\n", return_val);
//the allocated memory is accessible here
//And it has to be freed before main returns, so:
free(return_val);//deallocate!
return 0;
}
char *some_function()
{
char *str = calloc(11, sizeof(char));
//do stuff, but no calls to free
return str;//return char pointer
}
it ended with return str
, then you'd have to call free
in the main
function, as it has a pointer to the allocated memory.
That's it, in a nutshell...
Upvotes: 1
Reputation: 5289
int *pInt - it's just a pointer to some possibly existing array (there's no space to put data in, it could point later to some place in memory to be used as array of ints, if you set it)
newStruct *createMyStruct: a function that's named createMyStruct. This is correct.
createMyStruct is a pointer that points to newStruct and create a copy of the newStruct
No, it's the pointer to the function (or the function name), but the function returns a pointer (newStruct*) to your structure, if you implement the function right you'll get allocated and initialized structure ready to use
newStruct *pStruct - it's not the same as createMyStruct, pStruct will be uninitialized pointer,createMyStruct is your function
Here is how you would use your structure and methods:
int main()
{
newStruct *pStruct = NULL; // nothing there yet
pStruct = createMyStruct();
if(pStruct==NULL) { printf("error"); }
pStruct->pInt[0] = 123;
...
free(pStruct->pInt); // you have to free the array in your struct too
free(pStruct);
return 0;
}
If you're wondering where to put the free, look at the example main function... The pStruct is declared and initialized at the beginning of main and free'd at it's end. For the most of the time, it's sufficient to free the memory at the same level (function) you did originally allocate it.
Upvotes: 0
Reputation: 4096
Ok, let's try to clarify this:
1) int *pInt
is a pointer to an Integer. This MAY point to the first value of an array, but it doesn't have to.
2) newStruct *createMyStruct()
is a function that has a return value of a pointer to a newStruct structure. Most likely you want to malloc
in this function and have it return the pointer.
3) newStruct *pStruct
means that the input parameter for this function is a pointer to a newStruct structure, in this case named pStruct (I assume you know how to handle parameters in C)
As for your question: It kinda depends on when you no longer need the memory allocated. If you were to free
it in the createMyStruct()
function, you would basically return a pointer to an invalid location (causing undefined behaviour if you try to dereference it). Generally you should free
the memory you allocated only when you are completely sure you no longer require whatever you allocated. You can either do it in your main
or write your own function which you call.
Upvotes: 3
Reputation: 47609
1 - if you malloc
memory, you have to free it. It doesn't matter where. You should do it when you are no longer using the memory. It doesn't have to be immediately, but you should probably do it when you know you can, otherwise you have to remember to free it later.
You said
I thought the memory has to be freed right away after it has been used.
That's just advice. But it's very good advice. You could never free it, and keep using memory. You might run out of memory or your program might crash. C will not help you, the best thing you can do is stick to advice.
That's vague advice, but only you, the programmer, know the best place to do it. It's not easy, but memory management isn't easy.
2 - You need to remember how big the array is, because C will not check if you malloc(3)
but access struct.pInt[4]
. You could store this size as a variable in the struct.
Upvotes: 1