help understanding character arrays

Discussion in 'C Programming' started by dj, May 19, 2004.

  1. dj

    dj Guest

    I've read section 6 of the FAQ, but still am a bit confused...
    Please refer to the comments in the following
    code for my questions:
    -----------------------------------------------------------
    #include <stdlib.h>
    #include <stdio.h>
    #include <memory.h>


    #define L_DATE 8

    typedef struct
    {
    char date1[L_DATE];
    char date2[L_DATE];
    } my_record_t;

    my_record_t my_rec;

    void my_func(void);

    int main(void)
    {
    char my_char[L_DATE];
    memcpy(my_rec.date1, "20040101", L_DATE);
    memcpy(my_rec.date2, "20040202", L_DATE);

    /*
    ** I understand that "my_char" is the same as
    ** "&my_char[0]", but what about "&my_char"?
    ** I was surprised to find out that
    ** "my_char" == "&my_char"! (that is an exclamation,
    ** not a "not").
    */
    printf("my_char = %p -> %p\n", &my_char, my_char );

    /*
    ** I'm wondering if this is "defined" behavior, or if
    ** it just happens to work like this on my system?
    **
    ** I'm asking because I saw some code which uses this
    ** "&my_char" in a memcpy, similar to what is done in
    ** my_func(), and I'm wondering if it is ok or not.
    */
    printf("before: date1 = %.*s, date2 = %.*s\n",
    L_DATE, my_rec.date1, L_DATE, my_rec.date2 );
    my_func();
    printf("after: date1 = %.*s, date2 = %.*s\n",
    L_DATE, my_rec.date1, L_DATE, my_rec.date2 );

    return EXIT_SUCCESS;
    }

    void my_func(void)
    {
    char local_date[L_DATE] = "19700101";
    my_record_t *rec_p = &my_rec;

    /*
    ** this doesn't look right to me, but it
    ** seems to work...
    */
    memcpy( &rec_p->date2, &local_date, L_DATE );
    }
    --------------------------------------------------------


    any help or comments are appreciated.

    thanks,

    -dj
     
    dj, May 19, 2004
    #1
    1. Advertising

  2. On Tue, 18 May 2004, dj wrote:
    >
    > #include <stdlib.h>
    > #include <stdio.h>
    > #include <memory.h>


    Non-standard header. You mean #include <string.h>, which is where
    the standard functions like 'memcpy' and 'memmove' live.

    > #define L_DATE 8
    >
    > typedef struct
    > {
    > char date1[L_DATE];
    > char date2[L_DATE];
    > } my_record_t;
    >
    > my_record_t my_rec;
    >
    > void my_func(void);
    >
    > int main(void)
    > {
    > char my_char[L_DATE];
    > memcpy(my_rec.date1, "20040101", L_DATE);
    > memcpy(my_rec.date2, "20040202", L_DATE);


    This is not relevant to your question, but better style would
    be to write:
    strncpy(my_rec.date1, "20040101", sizeof my_rec.date1);
    if you mean to fill 'my_rec.date1' with data from a string.
    Using 'memcpy' is okay, but it leaves the possibility that
    some maintainer will come along and change the date string to
    a shorter one, like this:
    memcpy(my_rec.date1, "0000", L_DATE); /* just zeroes for now */
    and then the code will break horrifically. 'strncpy' has its
    own pitfalls, of course, but they're pitfalls more suited to
    this task than are the pitfalls of 'memcpy'.

    > /*
    > ** I understand that "my_char" is the same as
    > ** "&my_char[0]", but what about "&my_char"?


    '&mychar' is the address of 'mychar'. Since (the object) 'mychar'
    is an array of 8 chars, (the expression) '&mychar' is a pointer to an
    array[8] of char. The expression 'mychar', on the other hand, is
    what you get when the object 'mychar' "decays" to a pointer to its
    first element: a pointer to char.
    The address of the array is the same as the address of its first
    element, by definition. But the two expressions have different types:
    one is a pointer to char and the other is a pointer to an array.
    This is known in these parts as "The Rule," and I expect you can
    Google for it. Look for Chris Torek's posts.

    > ** I was surprised to find out that
    > ** "my_char" == "&my_char"! (that is an exclamation,
    > ** not a "not").


    The value is the same; the type is not.

    > */
    > printf("my_char = %p -> %p\n", &my_char, my_char );


    Using "%p" is a good way to experiment, but don't expect it
    to produce definitive answers. Especially not if you invoke
    undefined behavior by forgetting the casts:

    printf("my_char = %p -> %p\n", (void*)&my_char, (void*)my_char);

    If you don't understand the line above, then that would be a sign
    that you should not be messing with this stuff yet.

    > /*
    > ** I'm wondering if this is "defined" behavior, or if
    > ** it just happens to work like this on my system?
    > **
    > ** I'm asking because I saw some code which uses this
    > ** "&my_char" in a memcpy, similar to what is done in
    > ** my_func(), and I'm wondering if it is ok or not.
    > */


    It is. But IMHO it's more clear (and less typing!) to use
    the unadorned 'my_char'. Adding superfluous '&'s to the source
    code is just obfuscation in this case.

    <snip>
    > memcpy( &rec_p->date2, &local_date, L_DATE );


    Better IMHO:
    memcpy(rec_p->date2, local_date, sizeof local_date);

    HTH,
    -Arthur
     
    Arthur J. O'Dwyer, May 19, 2004
    #2
    1. Advertising

  3. "dj" <> wrote in message news:p...
    > I've read section 6 of the FAQ, but still am a bit confused...
    > Please refer to the comments in the following
    > code for my questions:
    > -----------------------------------------------------------
    > #include <stdlib.h>
    > #include <stdio.h>
    > #include <memory.h>
    >
    >
    > #define L_DATE 8
    >
    > typedef struct
    > {
    > char date1[L_DATE];
    > char date2[L_DATE];
    > } my_record_t;
    >
    > my_record_t my_rec;
    >
    > void my_func(void);
    >
    > int main(void)
    > {
    > char my_char[L_DATE];
    > memcpy(my_rec.date1, "20040101", L_DATE);
    > memcpy(my_rec.date2, "20040202", L_DATE);
    >
    > /*
    > ** I understand that "my_char" is the same as
    > ** "&my_char[0]", but what about "&my_char"?
    > ** I was surprised to find out that
    > ** "my_char" == "&my_char"! (that is an exclamation,
    > ** not a "not").
    > */


    A simple example should be helpful for you to understand the difference between
    `my_char' and `&my_char'. Their values, thought numerically, are same but their
    semantic meanings are not.

    The address-of operator when applied to an object yields a pointer to (the
    location of) that object. For example,

    int a, *p;
    p = &a;

    &a yields the address of the integer object a. An address can be represented by
    a pointer. In other words, a pointer is an object which can store the lvalue of
    a compatible object. So the declaration,

    int *p;

    says that p is pointer to an int, and can store the lvalue of a (&a).
    Similarly the declaration,

    char my_char[L_DATE];

    says my_char is an array of char. And, the address-of operator would yield the
    address of the array object as it did for the integer object above. Now, what
    should be the pointer type to store the address of the array? Let us build the
    declaration of pointer to an array of char:

    The basic type of pointer is `char', and the pointer declaration is

    char *ptr;

    but, this not a pointer to an array; it is, but, pointer to a char. So, a
    pointer to the array is:

    char (*ptr)[L_DATE];

    Now, the address can be taken.

    ptr = &my_char;


    Save my English, I think the above points are OK. Another point, I think,
    is using identifiers beginning with "L_" is reserved (but, I'm not sure).

    What Mr. Arthur was saying about "The Rule" is here:
    http://web.torek.net/torek/c/expr.html#therule

    [..]
    > any help or comments are appreciated.
    >
    > thanks,
    >
    > -dj
    >


    --
    "Thinking should become your capital asset, no matter whatever
    ups and downs you come across in your life."
    - Dr. APJ Abdul Kalam, The President of India
     
    Vijay Kumar R Zanvar, May 19, 2004
    #3
  4. On Tue, 18 May 2004 23:29:12 GMT, dj <>
    wrote:

    >I've read section 6 of the FAQ, but still am a bit confused...
    >Please refer to the comments in the following
    >code for my questions:
    >-----------------------------------------------------------
    >#include <stdlib.h>
    >#include <stdio.h>
    >#include <memory.h>
    >
    >
    >#define L_DATE 8
    >
    >typedef struct
    >{
    > char date1[L_DATE];
    > char date2[L_DATE];
    >} my_record_t;
    >
    >my_record_t my_rec;
    >
    >void my_func(void);
    >
    >int main(void)
    >{
    > char my_char[L_DATE];
    > memcpy(my_rec.date1, "20040101", L_DATE);


    It doesn't affect your code but I wanted to emphasize that
    my_rec.date1 does not contain a string at this point because the
    terminating '\0' was not included in the count of characters to be
    copied.

    > memcpy(my_rec.date2, "20040202", L_DATE);
    >
    > /*
    > ** I understand that "my_char" is the same as
    > ** "&my_char[0]", but what about "&my_char"?
    > ** I was surprised to find out that
    > ** "my_char" == "&my_char"! (that is an exclamation,
    > ** not a "not").


    They only appear to be the same because you use memcpy in my_func.
    Others have explained the difference. You can see it for yourself by
    changing the calls to memcpy to strncpy. memcpy works because its
    pointer parameters are pointers to void which are compatible with any
    pointer type while strncpy's pointer parameters are pointers to char
    which are not compatible with pointers to array of char.

    > */
    > printf("my_char = %p -> %p\n", &my_char, my_char );
    >
    > /*
    > ** I'm wondering if this is "defined" behavior, or if
    > ** it just happens to work like this on my system?
    > **
    > ** I'm asking because I saw some code which uses this
    > ** "&my_char" in a memcpy, similar to what is done in
    > ** my_func(), and I'm wondering if it is ok or not.
    > */
    > printf("before: date1 = %.*s, date2 = %.*s\n",
    > L_DATE, my_rec.date1, L_DATE, my_rec.date2 );
    > my_func();
    > printf("after: date1 = %.*s, date2 = %.*s\n",
    > L_DATE, my_rec.date1, L_DATE, my_rec.date2 );
    >
    > return EXIT_SUCCESS;
    >}
    >
    >void my_func(void)
    >{
    > char local_date[L_DATE] = "19700101";
    > my_record_t *rec_p = &my_rec;
    >
    > /*
    > ** this doesn't look right to me, but it
    > ** seems to work...
    > */
    > memcpy( &rec_p->date2, &local_date, L_DATE );
    >}
    >--------------------------------------------------------
    >
    >
    >any help or comments are appreciated.
    >
    >thanks,
    >
    >-dj




    <<Remove the del for email>>
     
    Barry Schwarz, May 23, 2004
    #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. venkatagmail
    Replies:
    11
    Views:
    715
    James Kanze
    Oct 3, 2007
  2. Philipp
    Replies:
    21
    Views:
    1,189
    Philipp
    Jan 20, 2009
  3. Replies:
    4
    Views:
    103
  4. Christopher T King

    Understanding Arrays and enumeration

    Christopher T King, Aug 13, 2004, in forum: Javascript
    Replies:
    3
    Views:
    102
    Christopher T King
    Aug 14, 2004
  5. MG
    Replies:
    5
    Views:
    202
    Thomas 'PointedEars' Lahn
    Apr 16, 2010
Loading...

Share This Page