help understanding character arrays

D

dj

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
 
A

Arthur J. O'Dwyer

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

which is where said:
#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.

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

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

HTH,
-Arthur
 
V

Vijay Kumar R Zanvar

dj said:
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

[..]
 
B

Barry Schwarz

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

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

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top