Re: (newbie) question concerning memory allocation

Discussion in 'C Programming' started by Ben Bacarisse, Sep 29, 2012.

  1. lipska the kat <> writes:

    > Ubuntu Linux 12.04 LTS 64bit
    > gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
    > /bin/bash
    >
    > Hi
    >
    > I'm a raw beginner at C so please excuse me if
    > the answer to my question is obvious.
    >
    > I have the following program called
    > pointers.c It compiles and if I run it
    > thusly:
    >
    > $pointers 3
    >
    > I get the expected output
    >
    > 1 2 3


    As you've now found out, correct output is no indicator that a program
    is correct. It's a very good idea to start thinking about programs by
    making logical inferences from the source. You don't need a formal
    systems for this; you can go a long way with some very informal rules.

    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int main(int argc, char *argv[]){
    >
    > struct foo{
    > int bar;
    > long baz;
    > };
    >
    > int x = 0;
    >
    > if(argc > 1){
    > x = atoi(argv[1]);
    > }


    (aside: for test programs like this I tend to write

    int x = argc > 1 ? atoi(argv[1]) : 0;

    because it's so short and it keeps the default value (0) close.)

    > struct foo **foos;
    > struct foo **bars;
    >
    > int i;


    You are mixing declarations and statements. This is permitted in modern
    C, but I would then go further and put the declaration of i into the for
    statement itself:

    for (int i = 0; i < x; i++) ...

    > /* create foos*/
    > for(i = 0; i < x; i++){
    > *foos = malloc(sizeof(struct foo));


    Form what you write below, you know what's wrong here, yes?

    I like to use this pattern for malloc calls: p = malloc(n * sizeof *p);
    so that there is no need to check the you are using the right type in
    the sizeof expression. When the number is obviously 1, I omit it.:

    *foos = malloc(sizeof **foos);

    > (*foos)->bar = i + 1;
    > (*foos)->baz = i + 2;
    > ++foos;
    > }
    >
    > /* set foos back to the first foo */
    > foos-=x;


    Changing foos gives you more work to do. I'd write it like this:

    for (int i = 0; i < x; i++) {
    foos = malloc(sizeof *foos);
    foos->bar = i + 1;
    foos->baz = i + 2;
    }

    > /* print foos */
    > for(i = 0; i < x; i++){
    > printf("%d ", foos->bar);
    > }
    >
    > printf("\n");
    >
    > return 0;
    > }
    >
    > This is all well and good, however if I use gdb with a suitable break
    > to look at the values for foos and bars
    > I get the following
    >
    > (gdb) print/x foos
    > $1 = 0x7fffffffe1f0
    > (gdb) print/x bars
    > $2 = <optimized out>
    >
    > fair enough, I'm not using bars
    >
    > If I change the code so that it reads
    >
    > struct foo **foos;
    > struct foo **bars;
    > bars = foos;
    >
    > I get a seg fault when I run the program
    >
    > If I put a break just before the assignment
    >
    > bars = foos;
    >
    > and print the values of foos and bars
    > I get the following
    >
    > (gdb) print/x foos
    > $1 = 0x4004f0
    > (gdb) print/x bars
    > $2 = 0x7fffffffe1f0
    >
    > now when I assign the value in foos to bars
    > and run the program it seg faults at the line
    >
    > *foos = malloc(sizeof(struct foo));
    >
    > I think I understand why the segfault occurs
    > it's because I'm trying to access unavailable memory
    >
    > The question is, why does declaring a second pointer to the array of
    > pointers


    They are not pointers to arrays, despite what people say. They are
    pointers to pointers. A pointer to an array can be declared (and can be
    very useful) but it looks quote different). A good way to talk about
    such a thing is as a pointer to the first element of an array.

    > to foo cause the first pointer (foos) be be allocated an
    > unavailable memory slot.


    Altering the source code will likely alter what code gcc generates, but
    when a program does something as unpredictable as accessing memory
    through an uninitialised pointer it seems pointless to try to dig out
    exactly why it behaves differently.

    If gcc can no longer removes the other pointer, where foos lies in
    memory may well change and what "happens to be there" is likely to be
    different. This is a guess, but I don't think finding out is likely to
    be very interesting or useful.

    Bu the way, I can't recommend valgrind enough, especially while
    learning. Don't do anything else before installing it! Compile with -g
    and "valgrind ./program 3" says:

    ==14141== Use of uninitialised value of size 8
    ==14141== at 0x400620: main (x.c:24)

    and so on. I never leave home without it (home == emacs of course).

    --
    Ben.
     
    Ben Bacarisse, Sep 29, 2012
    #1
    1. Advertising

  2. lipska the kat <> writes:

    > On 29/09/12 14:11, Ben Bacarisse wrote:
    >> lipska the kat<> writes:
    >>

    > [snip]
    >
    >>> The question is, why does declaring a second pointer to the array of
    >>> pointers

    >>
    >> They are not pointers to arrays, despite what people say. They are
    >> pointers to pointers. A pointer to an array can be declared (and can be
    >> very useful) but it looks quote different). A good way to talk about
    >> such a thing is as a pointer to the first element of an array.

    >
    > I'm just trying to get my head around this whole pointers to arrays
    > thing, If I manage to create a data structure rooted at **foos
    > I can access the instances using array indexing despite the fact that
    > no array initialization code darkens my doorstep. I'm just accepting
    > this at the moment and hoping the subconscious processor in my head
    > will do the rest.


    A pointer to an array looks like this:

    int (*ap)[10];

    and you could set ap like this:

    int ar[10];
    ap = &ar;

    but it is very common to say that after

    int *ip = ar;

    ip "points to the array" ar. Most of the time it doesn't matter,
    but ip really just points to one element of the array (the first).

    Have you seen the C faq? In particular 6.13:
    http://c-faq.com/aryptr/ptrtoarray.html

    <snip>
    --
    Ben.
     
    Ben Bacarisse, Sep 29, 2012
    #2
    1. Advertising

  3. Ben Bacarisse <> writes:
    [...]
    > Have you seen the C faq? In particular 6.13:
    > http://c-faq.com/aryptr/ptrtoarray.html


    I recommend reading all of section 6. The relationship between arrays
    and pointers in C can be very confusion; that FAQ section explains it
    better than anything else I've seen. The whole FAQ is an excellent
    resource.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Sep 29, 2012
    #3
  4. On Sep 29, 8:11 am, Ben Bacarisse <> wrote:
    > lipska the kat <> writes:

    (...)
    > >    /* create foos*/
    > >    for(i = 0; i < x; i++){
    > >            *foos = malloc(sizeof(struct foo));

    >
    > Form what you write below, you know what's wrong here, yes?
    >


    Considering that the OP had difficulties with the dereferencing
    syntax, in addition to what you say below ...


    > I like to use this pattern for malloc calls: p = malloc(n * sizeof *p);
    > so that there is no need to check the you are using the right type in
    > the sizeof expression.  When the number is obviously 1, I omit it.:
    >
    >   *foos = malloc(sizeof **foos);
    >


    .... I would elaborate that the sizeof expression is evaluated at
    compile time and there isn't any dereferencing involved.

    Writing malloc like above is idiomatic usage and good from a software
    engineering perspective; but I find that it is quite difficult to
    explain it to someone learning C. YMMV.

    - Anand
     
    Anand Hariharan, Oct 10, 2012
    #4
    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. =?Utf-8?B?RmxhY2s=?=

    Newbie question concerning page load event

    =?Utf-8?B?RmxhY2s=?=, May 17, 2005, in forum: ASP .Net
    Replies:
    3
    Views:
    522
    TDAVISJR
    May 17, 2005
  2. Ken
    Replies:
    24
    Views:
    3,953
    Ben Bacarisse
    Nov 30, 2006
  3. chris
    Replies:
    6
    Views:
    1,033
    chris
    Oct 28, 2005
  4. Eric Sosman
    Replies:
    6
    Views:
    300
    Phil Carmody
    Oct 10, 2012
  5. Joe Pfeiffer

    Re: (newbie) question concerning memory allocation

    Joe Pfeiffer, Sep 29, 2012, in forum: C Programming
    Replies:
    0
    Views:
    304
    Joe Pfeiffer
    Sep 29, 2012
Loading...

Share This Page