Newbie: learning to use malloc().

Discussion in 'C Programming' started by Longfellow, Jul 16, 2006.

  1. Longfellow

    Longfellow Guest

    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
     
    Longfellow, Jul 16, 2006
    #1
    1. Advertising

  2. Longfellow

    Ian Collins Guest

    Longfellow wrote:
    > 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!

    --
    Ian Collins.
     
    Ian Collins, Jul 16, 2006
    #2
    1. Advertising

  3. Longfellow said:

    <snip>
    >
    > 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)

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, Jul 16, 2006
    #3
  4. Longfellow

    Longfellow Guest

    On 2006-07-16, Ian Collins <> wrote:

    >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!


    On 2006-07-16, Richard Heathfield <> wrote:
    > Longfellow said:
    >
    ><snip>
    >>
    >> 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)


    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
     
    Longfellow, Jul 16, 2006
    #4
  5. Longfellow

    Ian Collins Guest

    Longfellow wrote:
    > On 2006-07-16, Ian Collins <> wrote:
    >
    >
    >>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.

    --
    Ian Collins.
     
    Ian Collins, Jul 16, 2006
    #5
  6. Longfellow said:

    > On 2006-07-16, Ian Collins <> wrote:
    >
    >>You are changing the type of buffer from a pointer to char to an array
    >>of 80 char.

    >
    > 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).

    <snip>

    > On 2006-07-16, Richard Heathfield <> wrote:
    >> Longfellow said:
    >>
    >><snip>
    >>>
    >>> 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)

    >
    > 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?

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

    >
    > 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.

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, Jul 16, 2006
    #6
  7. Longfellow

    Bill Pursell Guest

    Longfellow wrote:

    > 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.
     
    Bill Pursell, Jul 16, 2006
    #7
  8. Longfellow wrote:
    > 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?
     
    lovecreatesbeauty, Jul 16, 2006
    #8
  9. On 16 Jul 2006 08:24:35 -0700, "lovecreatesbeauty"
    <> wrote:

    >
    >Longfellow wrote:
    >> 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?


    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
     
    Barry Schwarz, Jul 17, 2006
    #9
  10. Longfellow

    Longfellow Guest

    On 2006-07-16, Bill Pursell <> wrote:
    >
    > 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
     
    Longfellow, Jul 17, 2006
    #10
  11. Longfellow

    Old Wolf Guest

    Longfellow wrote:
    > 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
     
    Old Wolf, Jul 17, 2006
    #11
  12. Longfellow <> writes:
    > On 2006-07-16, Bill Pursell <> wrote:
    >>
    >> 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.


    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.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Jul 17, 2006
    #12
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John
    Replies:
    13
    Views:
    732
  2. ravi
    Replies:
    0
    Views:
    479
  3. Peter
    Replies:
    34
    Views:
    2,051
    Richard Tobin
    Oct 22, 2004
  4. porting non-malloc code to malloc

    , Feb 18, 2005, in forum: C Programming
    Replies:
    3
    Views:
    501
    Walter Roberson
    Feb 19, 2005
  5. Andrey Popp

    [I'm learning C]: Learning to use ucontext

    Andrey Popp, Jan 29, 2012, in forum: C Programming
    Replies:
    5
    Views:
    806
    Keith Thompson
    Jan 31, 2012
Loading...

Share This Page