[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 349
  • Last Modified:

will call to free() and then malloc again reinit my string?

I have a string declared and used as follows:

char* array
array = (char*)malloc(1024 * sizeof(char *));

I then do a bunch of strcat(array, "somestring");

and then I called free, and then malloc it again, to try to get a clean buffer:

free(array)
array = (char*)malloc(1024 * sizeof(char *));

then do some more strcat to it again

and I noticed that each time the results are inconsistent...sometimes I'd get nice clean lines as I would expect, but other times I'd get duplicate lines (ie the old stuff plus new stuff).

So then my question is, by calling free, I'm just freeing the memory...I'm not really cleaning out the buffer huh? How would I completely clean out the buffer then so that old stuff don't linger around the 2nd time around?

thanx!
0
jade03
Asked:
jade03
  • 5
  • 5
  • 3
  • +2
2 Solutions
 
skypalaeCommented:
Hi jade03,

dont clean the memory when freeing, but when allocating.

array = (char *) calloc (1024, sizeof (char)) ; // your sizeof (char*) is ERROR !!

Cheers! S.
0
 
skypalaeCommented:
one more .. if you want to clean the string buffer, you can do it in couple more ways (no need to free/alloc)

strcpy (array, "") ;
or
array[0] = '\0' ;

but it will reset the first byte only. the rest of array will stay unchanged
0
 
manav_mathurCommented:
malloc() - The malloc() function allocates space for an object. malloc() returns a pointer to a block whose size is specified by size and whose *value is indeterminate*

calloc() - The calloc() function allocates space for an array of nelem elements of size elsize. The *space is initialized to zero*.

realloc() - The realloc() function changes the size of the object pointed to by ptr to the size specified by size, and returns a pointer to the possibly moved block. The *contents are unchanged up to the lesser of the new and old sizes*. If ptr is null, realloc() behaves like malloc() for the specified size. If size is zero (0) and ptr is not a null pointer, the object pointed to is freed.

Use whichever you deem suitable

Manav
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
aib_42Commented:
First of all, your array is an array of chars, multiplying the number of elements by sizeof(char *) is a mistake. You should multiply it by sizeof(char), which is equal to 1 by definition.

Secondly, there are two things you should know about malloc/free:
You don't have any control over what happens to a memory block after you free it. For all you know, the data there is lost.
You don't have any knowledge about what a malloc()ed memory block initially contains. For all you know, it could be anything.
0
 
manav_mathurCommented:
aib_42

>You don't have any control over what happens to a memory block after you free it. For all you know, the data there is lost.
Thats exactly why he/she asked the question in the first place.

>You don't have any knowledge about what a malloc()ed memory block initially contains. For all you know, it could be anything.
and it differs from my answer by....??

Manav
0
 
baboo_Commented:
The sizeof a char is one byte, so with

array =  (char*) calloc( 1024, sizeof(char) );

you get 1024 one-byte segments of memory.  But sizeof( char* ) or, indeed, the sizeof ANY pointer: sizeof( void* ), sizeof( int* ), sizeof( foo* ), is the same as the sizeof an int, which is implementation-specific, but we'll say it's 4 bytes (because that's pretty common).  So with:

array = (char*) calloc( 1024, sizeof(char*) );

you get a character array with 4096 (1024 x 4) elements.  I suspect that the cast to (char*) is only required so that the compiler knows how you want to address the elements - as chars, not as ints.  If you use skypalae's solution (which you should because it's right), you shouldn't need the (char*) cast when you're allocating.  It'd look like this:

array = calloc( 1024, sizeof(char) );

baboo_
0
 
baboo_Commented:
Here's another way to clear the array after you've malloc'ed it:

memset( array, 0, 1024*sizeof(char) );

(my personal favorite)  (don't know why...)

baboo_
0
 
jade03Author Commented:
Thanx, guys! Wow...I'm gaining much insight from all your inputs...

A few quick clarifications, for skypalae and baboo:

1)  I should use "calloc" instead of "malloc" because calloc automatically sets the fields to "0" for me?
2)  And in using calloc, I don't need to call "memset"?
3)  baboo, I'm still a bit fuzzy on the difference between "a character array with 4096 elements" and "1024 one-byte segments of memory"

If I had declared my array as char** array THEN I would use array = (char*) calloc( 1024, sizeof(char*) ) ?
0
 
manav_mathurCommented:
jade03,

1) there's a dfference between a char and a char *. the size of a 'char' is 1 byte and that is what sizeof returns.
On the other hand, the size of a char*(a pointer to char) requires 4 bytes(thats because the 4-byte memory has to hold a memory location, not a character). Hence size(char *) returns 4 bytes. Multiply it by 4 and you get 4096 elements.

sizeof(char) returns 1. multiply by 1024 and you get 1024 bytes. The function calloc() returns a character pointer to those 1024 bytes.
malloc() simply returns a pointer(not a character pointer) so you have to typecast it using (char *) to tell the compiler that this memory block will be used to store character arrays.

2) no u do not need to call memset usually. Only in the special case when you want to initialize the memory with something other than 0. Please refrain from use calloc() to initialize char ** because calloc initializes with zeroes, *not a NULL*. your pointers will still be invalid if you do not initialize them.

3) If I had declared my array as char** array THEN I would use array = (char*) calloc( 1024, sizeof(char*) )

right. Thats because in this case you are not creating a memory segment which should hold characters, but rather creating a segment which should hold pointers. if you want to store 1 pointer, u'd need 4 bytes. this is given by sizeof(char *). if you want to store 1024 memory pointers, multiply iy by 1024. Hence your array will point to the start of a memory segment of 4096 bytes, in which *each* 4 bytes hold a *memory address* which points to a location where a character is/can be stored.


any other issues?? let us know

Manav
0
 
baboo_Commented:
1)  I should use "calloc" instead of "malloc" because calloc automatically sets the fields to "0" for me?
2)  And in using calloc, I don't need to call "memset"?

Yes to both.

3)  baboo, I'm still a bit fuzzy on the difference between "a character array with 4096 elements" and "1024 one-byte segments of memory"

OK - here's how calloc (and, actually, all the malloc/calloc/blah-blah-alloc functions work).  We'll talk about calloc specifically, since it's the one you'll be using.

So the idea is this:  Whenever you want to store data, you need memory in which to store it.  Sometimes, C will do this automatically without you having to explicitly ask for it.   An example of this is when you create a variable, like an int or char:

int baboo;

This line says: "Hey computer, I'm going to need to store a number.  So, find me 4 bytes of memory that's not being used.  And I want you to remember that whenever I use the word "baboo" in my program, that I'm talking about the number that's stored in those 4 bytes.  I don't care WHERE you put it, and I really don't care about the actual address of it in memory - I want YOU to take care of all that for me.  I just want to be able to get to the number - the data itself."

By the way, why does this necessarily mean that I want 4 bytes of memory?  Well, that's how big the primitive type "int" is - 4 bytes.  Here's what some of the other primitive types and their sizes in bytes:

char means 1 byte
short means 2 bytes
int means 4 bytes
long means 8 bytes

(Now, to be really nitpicky, I should point out that, for different computer architectures, in the C programming language, "int" might not mean 4 bytes - it might be 2 or 8, but for most (like Intel/AMD/Mac) it does mean 4 bytes.  So, for the purposes of our discussion, int always means 4 bytes.)  

So what about pointers then?  When you DECLARE a pointer variable, you're saying, "Hey computer:  I'm going to be storing a memory ADDRESS.  I need you to find me enough unused memory to store the address.  I don't care where you find it, or where it actually is.  Just find me enough memory to store an address.  Oh, and remember that whenever I use the variable name, I really mean this memory address."

So, how big is a memory address in C?  It's the same size as an int - in our case, 4 bytes.  So, oddly enough, all of the following DECLARATIONS are allocating the same amount of memory:

char* charPointer;
int* intPointer;
long* longPointer;

Each of these are actualy just a 4-byte int!  So why, then, does it matter what "kind" of pointer it is?  I mean, if ALL memory addresses are 4 bytes long, why does it matter if I have a char* pointer versus a long* pointer?  (we're going to get to that a bit later... For now, just remember that ALL pointer variables are just ints, adn they store an ADDRESS).

So I've DECLARED my pointer variable - let's call it:

char* babooPointer;

I have 4 bytes of unused space that I can use to store a memory address.  So what address do I use?  Can I just pick one?  Could I just cross my fingers, and hope that, say, address 123456 is not being used, and do this?

babooPointer = 123456;

Hmm...  You could, but it'd be like buying a plane ticket, and just deciding, arbitrarily, that you're going to sit in seat 14C.  Now, there might ALREADY be someone assigned to that seat, or the airline might end up selling a ticket and assigning 14C to someone else, and there's no way they could know that you had, in your mind, decided that you'd be using 14C.  It's just better to ask the ticket agent to assign you a seat, because they're the ones that keep track of ALL the seating assignments, and make sure that each passenger has their own seat.

So, how do we "ask C for a seat?"  malloc/calloc, of course!  Instead of arbitrarily picking an address, we can ask C (the ticket agent), "Hey!  I want to store some data.  Find me some free memory that's big enough for my data, and once you've found it, tell me the address (well, put it into my pointer variable, actually)."  Here's how you do that:

char* babooPointer = malloc( sizeof( char ) );

In this statement, you're asking, "I want one byte" (remember, that's the sizeof a char...).  

OK, so what if I want to store a bunch of things that are the same type?  Do I need to have a bunch of different variables, one for each piece of data?  Of course not!  You use an array!  And these are the things C needs to know to implement an array:

1) Where the array starts (a memory ADDRESS)
2) How big (in bytes) the individual items are - that way, I can just skip from the start (which I know, because of item #1) to any item in the array, since I know how far to skip each time (i.e., the size of each element).
3) How much unused memory I need to store the array

Here's how you tell C each of these items - this example is the creation of an array of 10 chars, named babooPointer.

char*   babooPointer   =     malloc(    sizeof(char) * 10    );
 ^                 ^                                              ^
  |                  |                                               |
 #2                #1                                            #3

a-HA!!  So that's why it matters what "type" the pointer is!  The only reason that int* is different from char* is different from long* is when it comes to accessing the data they point to.  And #3, the amount of unused memory needed, is simply the number of bytes you want for your array.  So, since sizeof(char) == 1 byte, and I know I want 10 chars, couldn't I just say:

char* babooPointer = malloc( 10 );

Yeah, you could, but it'd be a lot less clear...  Now, malloc is your "all-purpose" memory allocator.  It really doesn't care what you're using the memory for at all.  All it does is find a piece of unused memory that's as many bytes long as you said you wanted, and then return the address of the first byte.  \

calloc is slightly different - you have to tell calloc 2 separate things:

1) How many individual items you need in your array
2) the size of each item

and calloc finds the unused memory (all of it), makes it all 0's, and returns the address of the first byte.  To make an array of 10 ints using calloc, we'd do this:

int* babooPtr = calloc( 10, sizeof(int) );
 ^                                 ^         ^
  |                                   \         \_______
Tells C how to access       Says "I need       \
the array (i.e. - "when       10 items"          Says "... and each of those
I say I want babooPtr[2],                           items should be 4 bytes long".
just start at the address
contained in babooPtr,
and move forward 8
bytes - that is, go past
the first two 4-byte ints)


I think the answer to your third question should be easy to see now...

calloc( 1024, sizeof(char) );

This says "Find me enough unused memory to store 1024 chars (which are 1 byte each)".  This gets you 1024 bytes.


calloc( 1024, sizeof(char*) );

And this says, "Find me enough unused memory to store 1024 pointers (which are 4 bytes each)."  This gets you 1024 * 4 = 4096 bytes.

Now, calloc/malloc don't care what you're going to use the memory for - they just find it, and return the address to the first byte.  The thing that determines how you'll access the memory is the type of the variable you use to store the ADDRESS!!!

For example,

char* array = calloc( 1024, sizeof(char) );

gives you enough memory so that you can access elements

array[0]   to    array[1023]

and

char* array = calloc( 1024, sizeof(char*) );

gives you enough memory to access

array[0]    to     array[4095]

You'd probably have to do this last one like this:

char* array = (char*) calloc( 1024, sizeof(char*) );

This is called a "typecast," or "cast."  All it does is it tells the C compiler, "Hey, this may look stupid, but I know what I'm doing here, so ignore it and compile away."  In this case, it's saying, "Yeah, I know I asked for memory for 1024 4-byte pointers, but I really do intend to use the 4096 bytes as an array of single-byte chars."

Finally, your last question:

"If I had declared my array as char** array THEN I would use array = (char*) calloc( 1024, sizeof(char*) ) ?"

Almost - you don't ever need the cast in front of calloc or malloc unless you're doing something funky.  Here's what you'd do in this last case:

char** array = calloc( 1024, sizeof(char*) );

All you're saying is, "I want enough memory for an array of 1024 pointers.  Put the address of the first byte in the variable named 'array'."

Whew.  I apologize if any of this is too basic to help you, but I wanted to make sure everything was covered.

baboo_


0
 
baboo_Commented:
manav said:

>Please refrain from use calloc() to initialize char ** because calloc initializes with zeroes, *not a NULL*. your >pointers will still be invalid if you do not initialize them.

manav, so you know, NULL == 0

I don't see why it makes a difference if you zero the memory or not.  Whether it contains gibberish, or all zeroes, you *still* have to initialize it.  As a matter of fact, since NULL == 0, I'd almost say that it'd be preferable to calloc arrays of pointers so that you'd be sure that, in the case of a programming error, that you could catch uninitialized pointer arrays by comparing to NULL.

baboo_
0
 
jade03Author Commented:
baboo, manav_mathur, you guys are incredible! Thanx for elaborating it into such details for me. I can REALLY see the big picture now. :)

To express my appreciation for your taking the time to explain it so well and in detailed for me, I'd like to increase the point value for this question, and then split it between the two of you. This thing won't let me use the new points if I just do a "split points" now. So let me increase first by doing a submit, then do a split...

0
 
jade03Author Commented:
Happy Thanksgiving, guys! :)

jade03
0
 
manav_mathurCommented:
to you too jade03

Cheers,
Manav
0
 
baboo_Commented:
jade03

happy thanksgiving to you too.

baboo_
0
 
manav_mathurCommented:
baboo_,

you ever thought about writing a book in C?? I've seen plenty of books which put me to sleep the moment I get past the first few pages....

you on the other hand have a very exciting mthodology.....talking to your PC

you could even name your book as "Hey computer"

very nice explanation!!

Manav
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 5
  • 5
  • 3
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now