Newbie: learning to use malloc().

L

Longfellow

I'm finally going to try to understand dynamic allocation of memory.
I've always just declared arrays (foo[xx]), but that's too limiting now.
I've looked at K&R2 (7.8.5 Storage Management: about 3/4 of a page, no
examples, just prototypes). D&D: half a page followed by some
warnings. C Traps and Pitfalls, and Expert C Programming: the standard
gotchas. And finally, comp.lang.c faq: a whole section on memory
allocation (7.x) with lots of wrong ways explained.

Nowhere that I can wrap my head around: clear examples of the Right Way
(tm). And, yes, I may well be in my *dense* period. :)

So this code:

#include <stdio.h>
#include <stdlib.h>

int main (void)
{
char *buffer;

if ((buffer = malloc(80)) == NULL) return 1;
printf("sizeof buffer is %d\n", sizeof buffer);

free(buffer);

return 0;
}

It compiles and runs:
sizeof buffer is 4

If I insert code to read from stdin (using fgets), printing the input to
the screen yields exactly three characters (three plus '\0', I presume).

OTOH, if I 's/char *buffer;/char buffer[80];/', and delete the 'if ((...'
and 'free(...' lines, I get "sizeof buffer is 80".

Obviously, I'm clueless here. Would someone point me to a venue where a
knowledgeable person would be more than willing to patiently explain
enough of what I don't know so that I can bootstrap my knowledge with
practice? I hesitate to ask that here, but would be delighted if
someone would offer same!

Thanks for reading,

Longfellow
 
I

Ian Collins

Longfellow said:
I'm finally going to try to understand dynamic allocation of memory.
I've always just declared arrays (foo[xx]), but that's too limiting now.
I've looked at K&R2 (7.8.5 Storage Management: about 3/4 of a page, no
examples, just prototypes). D&D: half a page followed by some
warnings. C Traps and Pitfalls, and Expert C Programming: the standard
gotchas. And finally, comp.lang.c faq: a whole section on memory
allocation (7.x) with lots of wrong ways explained.

Nowhere that I can wrap my head around: clear examples of the Right Way
(tm). And, yes, I may well be in my *dense* period. :)

So this code:

#include <stdio.h>
#include <stdlib.h>

int main (void)
{
char *buffer;

if ((buffer = malloc(80)) == NULL) return 1;
printf("sizeof buffer is %d\n", sizeof buffer);

free(buffer);

return 0;
}

It compiles and runs:
sizeof buffer is 4

If I insert code to read from stdin (using fgets), printing the input to
the screen yields exactly three characters (three plus '\0', I presume).

OTOH, if I 's/char *buffer;/char buffer[80];/', and delete the 'if ((...'
and 'free(...' lines, I get "sizeof buffer is 80".
You are changing the type of buffer from a pointer to char to an array
of 80 char.

sizeof(char*) is 4 on your system and sizeof(char[80]) is 80.

Now's a good time to start using the standard return values from main,
EXIT_SUCCESS and EXIT_FAILURE.

Good luck!
 
R

Richard Heathfield

Longfellow said:

It compiles and runs:
sizeof buffer is 4

If I insert code to read from stdin (using fgets), printing the input to
the screen yields exactly three characters (three plus '\0', I presume).

When you use a fixed size array with fgets, the canonical technique is:

if(fgets(buf, sizeof buf, fp) != NULL)

C knows how big the array is, so that's fine.

But now that you're using a pointer into a dynamically allocated memory
block, you have to remember for yourself how big that block is.

size_t bufsize = 80;
char *buffer = malloc(bufsize * sizeof *buffer);
if(buffer != NULL)
{
if(fgets(buffer, bufsize, fp) != NULL)
 
L

Longfellow

You are changing the type of buffer from a pointer to char to an array
of 80 char.

Yes, though actually the reverse. The array I understand, the pointer I
don't
sizeof(char*) is 4 on your system and sizeof(char[80]) is 80.

Okay, here's a test program:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
char *p;

printf("sizeof char is %d\n", sizeof(char));
printf("sizeof char * is %d\n", sizeof p);

return 0;
}

This yields:

sizeof char is 1
sizeof char * is 4

If I have this straight, sizeof char is defined as 1 byte, or so I have
often read. Standard does not guarantee this, IIUC; it's implementation
dependant?

sizeof a char * (character pointer?) is 4 bytes on this system (32 bit
processor?).
Now's a good time to start using the standard return values from main,
EXIT_SUCCESS and EXIT_FAILURE.

Yes, I use these already, although not in example code.
Good luck!

Thank you!


Longfellow said:



When you use a fixed size array with fgets, the canonical technique is:

if(fgets(buf, sizeof buf, fp) != NULL)

fgets with error checking?
C knows how big the array is, so that's fine.

Yes, it does because it is specified in the parameter passed to fgets()?
But now that you're using a pointer into a dynamically allocated memory
block, you have to remember for yourself how big that block is.

size_t bufsize = 80;
char *buffer = malloc(bufsize * sizeof *buffer);
if(buffer != NULL)
{
if(fgets(buffer, bufsize, fp) != NULL)
Okay, declaring and defining bufsize sets the stage for malloc() in the
same way that buffer[80] would do for an array?

Then the pointer to buffer is assigned a memory allocation of bufsize
multiplied by the size of a character pointer (here, *buffer). Ian
stated that a character pointer would be 4 bytes for my system, and the
little test program above verifies this. So malloc() is reserving 320
bytes?

I note the error checking above, and use it as a matter of course (it's
in the templates I've worked up).

Have I got it straight so far? If so, on to realloc() and calloc()...

Thanks for your lucid explanation, sir; yet another one and I appreciate it.

Longfellow
 
I

Ian Collins

Longfellow said:
You are changing the type of buffer from a pointer to char to an array
of 80 char.


Yes, though actually the reverse. The array I understand, the pointer I
don't

sizeof(char*) is 4 on your system and sizeof(char[80]) is 80.


Okay, here's a test program:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
char *p;

printf("sizeof char is %d\n", sizeof(char));
printf("sizeof char * is %d\n", sizeof p);

return 0;
}

This yields:

sizeof char is 1
sizeof char * is 4

If I have this straight, sizeof char is defined as 1 byte, or so I have
often read. Standard does not guarantee this, IIUC; it's implementation
dependant?
sizeof char is always 1, the size of a byte isn't defined.
sizeof a char * (character pointer?) is 4 bytes on this system (32 bit
processor?).
Correct. It's possible, but unlikely that a pointer size isn't 32 bits
on a 32 bit CPU.
But now that you're using a pointer into a dynamically allocated memory
block, you have to remember for yourself how big that block is.

size_t bufsize = 80;
char *buffer = malloc(bufsize * sizeof *buffer);
if(buffer != NULL)
{
if(fgets(buffer, bufsize, fp) != NULL)

Okay, declaring and defining bufsize sets the stage for malloc() in the
same way that buffer[80] would do for an array?
No, it just enables you to remember the size of the buffer you have
allocated. It is also good style not to use so called magic numbers
like 80 in your code.
Then the pointer to buffer is assigned a memory allocation of bufsize
multiplied by the size of a character pointer (here, *buffer). Ian
stated that a character pointer would be 4 bytes for my system, and the
little test program above verifies this. So malloc() is reserving 320
bytes?
NO! Notice Richard wrote "sizeof *buffer", that is the sizeof char.
 
R

Richard Heathfield

Longfellow said:
Yes, though actually the reverse.

Quite so.
The array I understand, the pointer I don't

A pointer is just a value that refers to the location in memory of an object
or a function. In this case, it points to the lowest byte in a block of
memory that you allocated via malloc.
sizeof(char*) is 4 on your system and sizeof(char[80]) is 80.

Okay, here's a test program:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
char *p;

printf("sizeof char is %d\n", sizeof(char));
printf("sizeof char * is %d\n", sizeof p);

return 0;
}

This yields:

sizeof char is 1
sizeof char * is 4

Yes. Note that sizeof *p will be 1 in this case, since p points to a char.
If I have this straight, sizeof char is defined as 1 byte, or so I have
often read. Standard does not guarantee this, IIUC; it's implementation
dependant?

The Standard guarantees that a char is exactly one byte in size, and it
further guarantees that a byte is at least 8 bits wide (although it may be
wider, and is wider on some systems).

fgets with error checking?

Absolutely. What's the point in trying to get some data from a stream if you
can't tell whether you succeeded?
Yes, it does because it is specified in the parameter passed to fgets()?

C knows how big the array is because you defined its dimension when you
defined the array itself. Yes, fgets knows how big the array is because you
told it.
But now that you're using a pointer into a dynamically allocated memory
block, you have to remember for yourself how big that block is.

size_t bufsize = 80;
char *buffer = malloc(bufsize * sizeof *buffer);
if(buffer != NULL)
{
if(fgets(buffer, bufsize, fp) != NULL)
Okay, declaring and defining bufsize sets the stage for malloc() in the
same way that buffer[80] would do for an array?

Well, no - it's just a handy way for your program to record the buffer size
without having hard-coded 80s all over the place. With a fixed-size array
you can use sizeof, but when you move to malloc, it still makes sense to
track the array size but sizeof won't tell you - it'll tell you the size of
the pointer instead - so you need to track it yourself. That's why I
introduced bufsize.
Then the pointer to buffer is assigned a memory allocation of bufsize
multiplied by the size of a character pointer (here, *buffer).

No, sizeof buffer would be the size of a character pointer; sizeof *buffer
is the size of the thing pointed to by buffer - i.e. the size of a single
char.
Ian
stated that a character pointer would be 4 bytes for my system,

Possibly he's right, but there's no point in relying on a particular size.
In any case, it's irrelevant; sizeof *buffer is 1, not 4, no matter how big
your pointers are.
and the
little test program above verifies this. So malloc() is reserving 320
bytes?

No, 80 * 1 is 80, not 320.
 
B

Bill Pursell

Longfellow said:
Okay, here's a test program:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
char *p;

printf("sizeof char is %d\n", sizeof(char));
printf("sizeof char * is %d\n", sizeof p);

return 0;
}

This yields:

sizeof char is 1
sizeof char * is 4

Then the pointer to buffer is assigned a memory allocation of bufsize
multiplied by the size of a character pointer (here, *buffer). Ian
stated that a character pointer would be 4 bytes for my system, and the
little test program above verifies this. So malloc() is reserving 320
bytes?

No. Malloc reserved 80 bytes, but the address of that buffer
is 4 bytes in size. If you write:

char *p = malloc(sizeof *p * 80); /* you get 80 bytes*/
char *q = malloc(sizeof q *80); /* get 320 bytes*/

Usually, you want the first. In fact, doing the
second is really obfuscatory, since the malloc
implies that you are allocating
space for 80 pointers, rather than 80 chars.
Assigning that space to a char * rather than
a char ** is really confusing.
 
L

lovecreatesbeauty

Longfellow said:
int main (void)
{
char *buffer;

if ((buffer = malloc(80)) == NULL) return 1;
printf("sizeof buffer is %d\n", sizeof buffer);

The code was evaluating the size of a pointer that was a link to the
space allocated. Use this one:
printf("sizeof buffer is %d\n", 80);

for that size was specified explicitly in literal. So why is it lost?
 
B

Barry Schwarz

The code was evaluating the size of a pointer that was a link to the
space allocated. Use this one:
printf("sizeof buffer is %d\n", 80);

for that size was specified explicitly in literal. So why is it lost?

Why is what lost? Nothing was lost. The fact that 80 bytes were
requested is not an attribute of buffer but of the call to malloc.
malloc does not return anything other than an address.


Remove del for email
 
L

Longfellow

Longfellow wrote:
<snip all>

Okay, thanks all for this thread, which is now a text file I can study.

Obviously, there's a lot of background I need to assimilate. With this
as a context, I'll dive back into K&R2 once again. The "point" seems to
be that I now need to differentiate pointers from arrays.

Next time I come back, I'll have a series of statements that reflect my
then current understanding. This is like debugging by reading compiler
errors: I introduce my "understanding" here, and you guys do the -Wall
-ansi -pedantic. When I get them past the last "NO! (whatever I don't
understand)", I'll write them up as part of my own tutorial for myself.
;)

Somehow I doubt that there is any one text on the C language that even
approaches the usefulness of this forum, for which I thank you all once
again.

Longfellow
 
O

Old Wolf

Longfellow said:
Obviously, there's a lot of background I need to assimilate. With this
as a context, I'll dive back into K&R2 once again. The "point" seems to
be that I now need to differentiate pointers from arrays.

Somehow I doubt that there is any one text on the C language that even
approaches the usefulness of this forum, for which I thank you all once
again.

There is one:
http://c-faq.com/aryptr/index.html
 
K

Keith Thompson

Longfellow said:
<snip all>

Okay, thanks all for this thread, which is now a text file I can study.

Obviously, there's a lot of background I need to assimilate. With this
as a context, I'll dive back into K&R2 once again. The "point" seems to
be that I now need to differentiate pointers from arrays.

Yes, very much so.

Read section 6 of the comp.lang.c FAQ, <http://www.c-faq.com/>.

The read the rest of it.

Don't expect to understand it all on the first reading; be prepared to
go back a few times.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

malloc 40
Adding adressing of IPv6 to program 1
malloc 11
[I'm learning C]: Learning to use ucontext 5
MALLOC problem 25
malloc and maximum size 56
to malloc or not to malloc? 5
using my own malloc() 14

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top