multi dimension array initialization using pointers

Discussion in 'C Programming' started by natkw1@yahoo.com.au, Oct 8, 2005.

  1. Guest

    Hi,

    I'm attempting to understand the use of pointers(at least grasp how
    pointers work). I've read the FAQ on
    http://www.eskimo.com/~scs/C-faq/s6.html on pointers and arrays but I'm
    still a bit lost.

    I written the following code to try to understand it but it's not
    working:

    #include <stdio.h>
    #include <ctype.h>

    #define MAXROW 2
    #define MAXCOL 5

    void init_array(char *data[MAXROW]);
    void print_array(char *data[MAXROW]);


    int main ()
    {
    char *array_ptr[MAXROW];

    init_array(array_ptr);
    print_array(array_ptr);
    return 0;
    }

    void init_array(char *data[MAXROW])
    {
    int row, col;

    for (row=0; row<MAXROW; row++)
    {
    for (col=0; col<MAXCOL; col++)
    {
    (data[row] + col) = '\0';
    }
    }
    }

    void print_array(char *data[MAXROW])
    {
    int row, col;

    for (row=0; row<MAXROW; row++)
    {
    for (col=0; col<MAXCOL; col++)
    {
    printf("%c",*(data[row] + col));
    }
    }
    printf("\n");
    }

    When I try to compile it with gcc, there is a warning
    a3.c: In function `init_array':
    a3.c:29: invalid lvalue in assignment

    Can anyone tell me what the warning means ?
    What I am doing wrong ?

    Nat
     
    , Oct 8, 2005
    #1
    1. Advertising

  2. pete Guest

    wrote:
    >
    > Hi,
    >
    > I'm attempting to understand the use of pointers(at least grasp how
    > pointers work). I've read the FAQ on
    > http://www.eskimo.com/~scs/C-faq/s6.html on pointers and arrays but I'm
    > still a bit lost.
    >
    > I written the following code to try to understand it but it's not
    > working:
    >
    > #include <stdio.h>
    > #include <ctype.h>
    >
    > #define MAXROW 2
    > #define MAXCOL 5
    >
    > void init_array(char *data[MAXROW]);
    > void print_array(char *data[MAXROW]);
    >
    > int main ()
    > {
    > char *array_ptr[MAXROW];
    >
    > init_array(array_ptr);
    > print_array(array_ptr);
    > return 0;
    > }
    >
    > void init_array(char *data[MAXROW])
    > {
    > int row, col;
    >
    > for (row=0; row<MAXROW; row++)
    > {
    > for (col=0; col<MAXCOL; col++)
    > {
    > (data[row] + col) = '\0';
    > }
    > }
    > }
    >
    > void print_array(char *data[MAXROW])
    > {
    > int row, col;
    >
    > for (row=0; row<MAXROW; row++)
    > {
    > for (col=0; col<MAXCOL; col++)
    > {
    > printf("%c",*(data[row] + col));
    > }
    > }
    > printf("\n");
    > }
    >
    > When I try to compile it with gcc, there is a warning
    > a3.c: In function `init_array':
    > a3.c:29: invalid lvalue in assignment
    >
    > Can anyone tell me what the warning means ?
    > What I am doing wrong ?


    /* BEGIN new.c */

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

    #define MAXROW 2
    #define MAXCOL 5

    void init_array(char **data);
    void print_array(char **data);
    void free_array(char **data);

    int main (void)
    {
    char *array_ptr[MAXROW];

    init_array(array_ptr);
    print_array(array_ptr);
    free_array(array_ptr);
    return 0;
    }

    void init_array(char **data)
    {
    int row;

    for (row = 0; row < MAXROW; row++) {
    data[row] = malloc(MAXCOL);
    if (data[row] == NULL) {
    puts("malloc");
    exit(EXIT_FAILURE);
    }
    assert(MAXCOL >= sizeof "data");
    strcpy(data[row], "data");
    }
    }

    void print_array(char **data)
    {
    int row;

    for (row = 0; row < MAXROW; row++) {
    fputs(data[row], stdout);
    }
    putchar('\n');
    }

    void free_array(char **data)
    {
    int row;

    for (row = 0; row < MAXROW; row++) {
    free(data[row]);
    }
    }

    /* END new.c */


    --
    pete
     
    pete, Oct 8, 2005
    #2
    1. Advertising

  3. On 8 Oct 2005 00:02:35 -0700
    wrote:

    > #define MAXROW 2
    > #define MAXCOL 5


    Why not const int MAXROW = 2; ?

    > void init_array(char *data[MAXROW])
    > {
    > int row, col;
    >
    > for (row=0; row<MAXROW; row++)
    > {
    > for (col=0; col<MAXCOL; col++)
    > {
    > (data[row] + col) = '\0';


    This won't work. Should be:
    data[row + col] = '\0';

    > }
    > }
    > }


    data's got 5 (0..4) char* elements. You are trying to access elements
    0..9 in this for loop, which of course won't work out well.

    Same in here:

    > void print_array(char *data[MAXROW])
    > {
    > int row, col;
    >
    > for (row=0; row<MAXROW; row++)
    > {
    > for (col=0; col<MAXCOL; col++)
    > {
    > printf("%c",*(data[row] + col));


    This won't work. Should be:
    printf("%c",data[row + col]);

    > }
    > }
    > printf("\n");
    > }


    Either change your array declaration to char *array_ptr[MAXROW*MAXCOL];
    or leave the second for-loops out.

    BTW: void print_array(char *data[MAXROW]) is really bad style. You
    should rather supply the number of elements in the array as the second
    argument: void print_array(char **data, int elements)
    Call with print_array(data, MAXCOL*MAXROW);

    best regards / Gruß
    Moritz Beller
    --
    web http://www.4momo.de
    mail momo dot beller at t-online dot de
    gpg http://gpg.notlong.com
     
    Moritz Beller, Oct 8, 2005
    #3
  4. Michael Mair Guest

    Moritz Beller wrote:
    > On 8 Oct 2005 00:02:35 -0700
    > wrote:
    >
    >>#define MAXROW 2
    >>#define MAXCOL 5

    >
    > Why not const int MAXROW = 2; ?


    Because in C, const does not generate compile time constants.
    So, for pre-C99 C, you cannot use it for array sizes at
    declaration. Or case labels.
    You are talking about another language, maybe C++.

    Cheers
    Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
     
    Michael Mair, Oct 8, 2005
    #4
  5. Guest

    I tried the suggestion of using data[row + col] in both functions but
    when compiling, I now get an message in the init_array function,

    warning: assignment makes pointer from integer without a cast

    void init_array(char *data[MAXROW])
    {
    int row, col;

    for (row=0; row<MAXROW; row++)
    {
    for (col=0; col<MAXCOL; col++)
    {
    data[row + col] = '\0';
    }
    }
    }

    I had also tested changing my array declaration to
    char *array_ptr[MAXROW*MAXCOL]but the same warning comes up.

    But when I use data[row][col] instead of (data[row] + col) or data[row
    +col] it works.
    I'm more confused.
    So when does the pointers "bits and pieces" get used in the function ??


    Nat
     
    , Oct 8, 2005
    #5
  6. Michael Mair Guest

    Please quote a sufficient amount of context -- it is not guaranteed
    that people see any other message from this thread before this one.
    Also, this was Moritz Beller's suggestion, not mine.

    wrote:
    > I tried the suggestion of using data[row + col] in both functions but
    > when compiling, I now get an message in the init_array function,
    >
    > warning: assignment makes pointer from integer without a cast
    >
    > void init_array(char *data[MAXROW])
    > {
    > int row, col;
    >
    > for (row=0; row<MAXROW; row++)
    > {
    > for (col=0; col<MAXCOL; col++)
    > {
    > data[row + col] = '\0';


    You have to pass an array of char, not an array of pointers to
    char. data is of the wrong type for that. If you have a parameter
    char *data (instead of char *data[MAXROW])for the function and
    data points to a storage area of at least MAXROW*MAXCOL bytes, then
    data[row*MAXCOL + col] = '\0';
    may be what you are looking for.

    > }
    > }
    > }
    >
    > I had also tested changing my array declaration to
    > char *array_ptr[MAXROW*MAXCOL]but the same warning comes up.


    See above.

    > But when I use data[row][col] instead of (data[row] + col) or data[row
    > +col] it works.
    > I'm more confused.
    > So when does the pointers "bits and pieces" get used in the function ??


    a is effectively a+i, so the former two are the same. The latter,
    though, cannot be true.
    However, without context I am too lazy trying to guess what you
    originally wanted to achieve and thus cannot help you with your
    problem.


    -Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
     
    Michael Mair, Oct 8, 2005
    #6
  7. On 8 Oct 2005 04:43:42 -0700
    wrote:

    > But when I use data[row][col]


    This could compile, but will usually seg fault! You cannot assign
    anything but an array of chars to data[row]! data[row][col] = '\0';
    will not work at all, as long as you don't have an array assigend to
    data[row], whose size is at least col+1!

    I give you an exmaple to understand things easier: You declare data to
    be a one-dimensional array of type char*! It's not a multidimensional
    array after all! So data[0] is effectivley pointing to a pointer to
    char.

    You virtually assgin data[0][n] in the for loop, thereby dereferencing
    this very pointer. You cannot assign data[0][n] with a character,
    though, as it's at this moment just a pointer of char that you have
    declared. This pointer should usually point to another array of char!
    Then (as mentioned above) data[0][n] is entriley valid.

    (data[row] + col) or data[row+col] are all just de-referencing once.
    When being printed, they should return the whole string (*(test + row *
    col) is equal to data[row]).

    If that's what you are trying to achieve, then declare char
    *array_ptr[MAXROW] to be char *array_ptr[MAXROW][MAXCOL] and your
    program will perhaps work.

    data[row + col] = '\0'; ->
    **(data + row * col) = '\0'; or, yet easier:
    data[row][col]

    best regards / Gruß
    Moritz Beller
    --
    web http://www.4momo.de
    mail momo dot beller at t-online dot de
    gpg http://gpg.notlong.com
     
    Moritz Beller, Oct 8, 2005
    #7
  8. On 8 Oct 2005 00:02:35 -0700, wrote:

    >Hi,
    >
    >I'm attempting to understand the use of pointers(at least grasp how
    >pointers work). I've read the FAQ on
    >http://www.eskimo.com/~scs/C-faq/s6.html on pointers and arrays but I'm
    >still a bit lost.
    >
    >I written the following code to try to understand it but it's not
    >working:
    >
    >#include <stdio.h>
    >#include <ctype.h>
    >
    >#define MAXROW 2
    >#define MAXCOL 5
    >
    >void init_array(char *data[MAXROW]);
    >void print_array(char *data[MAXROW]);
    >
    >
    >int main ()
    >{
    > char *array_ptr[MAXROW];


    array_ptr is an array of MAXROW pointers to char. If we assume for
    discussion that a pointer to char is 4 bytes, then you have a block of
    memory MAXROW*4 bytes long reserved for this array. However, these
    bytes are not initialized. Their value is indeterminate.
    Colloquially, none of the pointers actually point anywhere yet because
    they have not been initialized.

    >
    > init_array(array_ptr);


    Normally, evaluating an initialized object would cause undefined
    behavior. However, an expression of type array has the special
    property that in most contexts, including this one, evaluating the
    expression produces a value equal to the address of the first element
    with type pointer to element type. So the use of array_ptr here is
    well defined and exactly equivalent to &array_ptr[0].

    > print_array(array_ptr);
    > return 0;
    >}
    >
    >void init_array(char *data[MAXROW])
    >{
    > int row, col;
    >
    > for (row=0; row<MAXROW; row++)
    > {
    > for (col=0; col<MAXCOL; col++)
    > {
    > (data[row] + col) = '\0';


    Here is where you get into trouble. Consider the iteration when row
    is 0.

    data[0] is the first pointer in array_ptr from main. You never
    initialized this pointer to point anywhere. Attempting to evaluate an
    indeterminate value invokes undefined behavior.

    Consider the code segment
    int i;
    i = i + 1;
    Because i is not initialized, there is no previous value to add 1 to
    and this invokes the same undefined behavior. However, with either
    int i = 5;
    i = i + 1;
    or
    int i;
    i = 5;
    ...
    i = i + 1;
    there is a previous value of i to add 1 to and both result in i having
    the value 6.

    The same situation is true for you pointer. In order for this
    expression to evaluate properly, you must first assign it a value. In
    this case, that value must be the address of a char. Since you intend
    to use this pointer to reference a row of the matrix, it needs to
    point to the first of a sequence MAXCOL char. There are two common
    approaches for this:

    One is to allocate space dynamically:
    data[0] = malloc(MAXCOL * *data[0]);

    The other is to define an array of char and use the address of
    the array:
    char row0[MAXCOL];
    ...
    data[0] = row0;

    Now that data[0] evaluates properly, we address the rest of the
    expression. On the first iteration, col is also 0. data[0] has type
    pointer to char and 0 has type int so this is an example of pointer
    arithmetic. The expression evaluates to the address 0 bytes past the
    char that data[0] points to and has type pointer to char.

    So your are attempting to assign the character '\0' (which is
    really an int) to an l-value that has type pointer. Normally,
    attempting to assign an int to a pointer is a syntax error and would
    result in a diagnostic about incompatible types. However, any integer
    expression that evaluates to 0, as '\0' does, is recognized as a valid
    NULL pointer constant which can be assigned to a pointer to char.

    So while you don't have that syntax error, this would not do what
    you want. The error message you receive is telling you that the
    expression on the left of your assignment statement is not acceptable
    as the recipient of a value. You want to assign the character '\0' to
    the char that your pointer expression points to. To do this, you need
    to dereference the pointer because you want to manipulate the object
    it points to.

    The dereference operator (*) would work
    *(data[row] + col) = '\0';
    but the normal C idiom for this is
    data[row][col] = '\0';
    > }
    > }
    >}
    >
    >void print_array(char *data[MAXROW])
    >{
    > int row, col;
    >
    > for (row=0; row<MAXROW; row++)
    > {
    > for (col=0; col<MAXCOL; col++)
    > {
    > printf("%c",*(data[row] + col));


    You have used the dereference operator properly here.

    If you correct the problems with array_ptr not being initialized
    properly, you will still have a problem printing this way. Your
    entire matrix is filled with '\0'. This is normally not a printable
    or displayable character. Attempting to print it with %c will prove
    very unsatisfactory.

    You could print it with %d (and get 0) or you could choose to
    initialize the matrix with printable characters.

    > }
    > }
    > printf("\n");


    You probably want this up one line so it executes at the end of every
    row and not just at the end of the matrix.

    >}
    >
    >When I try to compile it with gcc, there is a warning
    >a3.c: In function `init_array':
    >a3.c:29: invalid lvalue in assignment


    (data[row]+col) does not define an object that can receive a value.

    >
    >Can anyone tell me what the warning means ?
    >What I am doing wrong ?
    >
    >Nat



    <<Remove the del for email>>
     
    Barry Schwarz, Oct 8, 2005
    #8
  9. writes:
    > Hi,
    >
    > I'm attempting to understand the use of pointers(at least grasp how
    > pointers work). I've read the FAQ on
    > http://www.eskimo.com/~scs/C-faq/s6.html on pointers and arrays but I'm
    > still a bit lost.
    >
    > I written the following code to try to understand it but it's not
    > working:
    >
    > #include <stdio.h>
    > #include <ctype.h>
    >
    > #define MAXROW 2
    > #define MAXCOL 5
    >
    > void init_array(char *data[MAXROW]);
    > void print_array(char *data[MAXROW]);

    [snip]

    These function declaration are likely to cause confusion. They appear
    to declare data as an array parameter, of type "array 10 of pointer to
    char", but in fact C doesn't have array parameters. Since array names
    are implicitly converted to pointers in most contexts, the language
    allows you to declare something that *appears* to be an array
    parameter, but it's adjusted to be a pointer parameter. The MAXROW
    between the brackets is ignored.

    It's better to declare your functions as

    void init_array(char *data[]);
    void print_array(char *data[]);

    or even as

    void init_array(char **data);
    void print_array(char **data);

    --
    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, Oct 8, 2005
    #9
  10. Guest

    Thank you everyone for explaining pointer usage to a C newbie. The in
    depth explanation of where my simple code was wrong has been extremely
    helpful.

    Following the suggestions made, I changed the way I declared my
    function, allocated an initial block of memory, used deferencing
    operator correctly and everything works.

    Nat
     
    , Oct 9, 2005
    #10
  11. Chris Torek Guest

    In article <>
    Barry Schwarz <> wrote:
    [good explanation, almost entirely deleted: need a one-line correction]
    > One is to allocate space dynamically:
    > data[0] = malloc(MAXCOL * *data[0]);


    You mean:

    data[0] = malloc(MAXCOL * sizeof *data[0]);

    which has the general "comp.lang.c-approved" form:

    p = malloc(N * sizeof *p);

    (In this case, of course, sizeof *data[0] is just 1, but the general
    form always works.)
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
     
    Chris Torek, Oct 9, 2005
    #11
  12. On 9 Oct 2005 03:23:30 GMT, Chris Torek <> wrote:

    >In article <>
    >Barry Schwarz <> wrote:
    >[good explanation, almost entirely deleted: need a one-line correction]
    >> One is to allocate space dynamically:
    >> data[0] = malloc(MAXCOL * *data[0]);

    >
    >You mean:
    >
    > data[0] = malloc(MAXCOL * sizeof *data[0]);
    >
    >which has the general "comp.lang.c-approved" form:
    >
    > p = malloc(N * sizeof *p);
    >
    >(In this case, of course, sizeof *data[0] is just 1, but the general
    >form always works.)


    I'm always amazed that, even after I proof read, I still words out.

    Thx.


    <<Remove the del for email>>
     
    Barry Schwarz, Oct 9, 2005
    #12
  13. Thad Smith Guest

    Keith Thompson wrote:
    > writes:
    >
    >>#define MAXROW 2
    >>#define MAXCOL 5
    >>
    >>void init_array(char *data[MAXROW]);
    >>void print_array(char *data[MAXROW]);

    >
    > These function declaration are likely to cause confusion. They appear
    > to declare data as an array parameter, of type "array 10 of pointer to

    ^^ 2
    > char", but in fact C doesn't have array parameters. Since array names
    > are implicitly converted to pointers in most contexts, the language
    > allows you to declare something that *appears* to be an array
    > parameter, but it's adjusted to be a pointer parameter. The MAXROW
    > between the brackets is ignored.


    While that's true, such declarations are an easy way to document that
    the functions expect a pointer to an input array of at least MAXROW
    elements. In other words, the user is normally expected to write
    something like

    char *mydata[MAXROW];

    init_array (mydata);

    > It's better to declare your functions as
    >
    > void init_array(char *data[]);
    > void print_array(char *data[]);
    >
    > or even as
    >
    > void init_array(char **data);
    > void print_array(char **data);


    and then document that the data array must have at least MAXROW entries.
    That's fine, but the first declaration is another, arguably simpler,
    way to specify this. To be rigorous, such usage should be documented in
    the style guide as having such meaning.

    Thad
     
    Thad Smith, Oct 10, 2005
    #13
    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. Makiyo
    Replies:
    3
    Views:
    537
    Richard Heathfield
    Feb 22, 2004
  2. Replies:
    11
    Views:
    529
    Alexei A. Frounze
    Sep 29, 2005
  3. DiAvOl
    Replies:
    17
    Views:
    580
    John Bode
    Jan 7, 2008
  4. Replies:
    5
    Views:
    4,235
    CBFalconer
    Dec 29, 2008
  5. Luuk
    Replies:
    15
    Views:
    836
    Nobody
    Feb 11, 2010
Loading...

Share This Page