Why does this work?

R

Randy Graham

While reviewing someone else's c++ code recently I was horrified to find
something like this:
(example only)

A.

char a[10];
memset(&a, 0, 10);
memcy(&a, "hello", 6);


Of course this is wrong, and should be

B.

char a[10];
memset(a, 0, 10);
memcy(a, "hello", 6);

When I brought this up with the author, he insisted he had always done
this and it worked.
When I tried it with VC++ 8.0 to show him he was nuts, it did in fact
compile and appear to function correctly.

Why would this work, passing a pointer to the pointer to the char array
(A.) when the pointer should be passed (B.).

A. is clearly wrong.

I don't get it.

-Randy
 
S

Szabolcs

Randy said:
Why would this work, passing a pointer to the pointer to the char array
(A.) when the pointer should be passed (B.).

A. is clearly wrong.

I noticed this too some time ago. While I am not familiar with the
standard (i.e. don't take me too seriously), it seems that arrays are
*not* pointers, and they do not always behave in the same way.

E.g. if we have

int a[10];
int *b = a;

then sizeof a == sizeof(int)*10, while sizeof b == sizeof(int *).

Functions seem to behave similarly: it is not necessary to dereference a
function pointer when calling it, and just writing 'func' instead of
'&func' is sufficient when taking a function pointer.

Szabolcs
 
R

Randy Graham

Szabolcs said:
I noticed this too some time ago. While I am not familiar with the
standard (i.e. don't take me too seriously), it seems that arrays are
*not* pointers, and they do not always behave in the same way.

E.g. if we have

int a[10];
int *b = a;

then sizeof a == sizeof(int)*10, while sizeof b == sizeof(int *).

'a' is certainly a pointer to the beginning of the char array.

-Randy
 
S

Szabolcs

Randy said:
Szabolcs said:
I noticed this too some time ago. While I am not familiar with the
standard (i.e. don't take me too seriously), it seems that arrays are
*not* pointers, and they do not always behave in the same way.

E.g. if we have

int a[10];
int *b = a;

then sizeof a == sizeof(int)*10, while sizeof b == sizeof(int *).

'a' is certainly a pointer to the beginning of the char array.

-Randy

Let's say that most of the time it *behaves* like a pointer. But arrays
and pointers are still different types.

If 'a' would be a pointer-to-int then 'sizeof a' should be sizeof(int *)

Another example where they behave differently:

char a[3][3];

Here no array of pointer-to-char (whose elements in turn point to
strings) will be allocated, only a contiguous block of 3*3 bytes.

If
char **b;
would be used instead, then that extra array of (char *)'s would need to
exist in memory (in addition to the 3 string-of-chars).

In fact
char **b = a;
is illegal here.

Szabolcs
 
S

Szabolcs

Randy said:
'a' is certainly a pointer to the beginning of the char array.

-Randy

Just think about it like this:

The array can be automatically converted to a pointer to its first
element, in the same way as an int can be used in a context where a
float is required.

The standard says:

| 4.2 - Array-to-pointer conversion [conv.array]
|
| -1- An lvalue or rvalue of type ``array of N T'' or ``array of unknown
| bound of T'' can be converted to an rvalue of type ``pointer to T.''
| The result is a pointer to the first element of the array.
 
A

Alf P. Steinbach

* Randy Graham:
While reviewing someone else's c++ code recently I was horrified to find
something like this:
(example only)

A.

char a[10];
memset(&a, 0, 10);
memcy(&a, "hello", 6);


Of course this is wrong, and should be

B.

char a[10];
memset(a, 0, 10);
memcy(a, "hello", 6);

It doesn't matter, except B is slightly less worse stylistically.

In A a pointer to the array is passed, in B a pointer to the first
element (which happens to be at the same address as the array) is
passed, so in both cases the same address is passed.

The way to do what this code does, is

C.
char a[10] = "hello";
 
J

Jerry Coffin

While reviewing someone else's c++ code recently I was horrified to find
something like this:
(example only)

A.

char a[10];
memset(&a, 0, 10);
memcy(&a, "hello", 6);


Of course this is wrong, and should be

B.

char a[10];
memset(a, 0, 10);
memcy(a, "hello", 6);

[Presumably the 'memcy' was really meant to be 'memcpy' in both cases. ]

In this case it doesn't really make any difference. The name of an array
is not converted to a pointer to the first element of the array when
it's an operand of the & operator or sizeof operator. That means by
using the &, you're not taking the address of an address -- you're
taking the address of the array (e.g. see $6.3.2.1/3 of the C99
standard).

You get an address of the same value either way, but the types of the
two are different from each other. Without the '&', the pointer is of
type 'pointer to char', but with it, the pointer is of type 'pointer to
array of 5 characters'. Since you're passing the result to memset,
however, it makes no difference, because either way it's converted to
'pointer to void' as part of calling the function.

You can, however, distinguish between the two usages when you want to.
For example, using function overloading so they don't get converted to
void * during the function call:

#include <iostream>

void show_size(char *x) {
std::cout
<< "Pointer to char:\t"
<< static_cast<void *>(x) << '\t'
<< static_cast<void *>(x+1) << '\n';
}

const int size = 1234;

typedef char array[size];

void show_size(array *x) {
std::cout
<< "Pointer to array:\t"
<< static_cast<void *>(x) << '\t'
<< static_cast<void *>(x+1) << '\n';
}

int main() {
array x;

show_size(x); // matches 'char *'
show_size(&x); // matches 'array *'
return 0;
}

Result on my machine:

Pointer to char: 0012FA0C 0012FA0D
Pointer to array: 0012FA0C 0012FEDE

Of course, when/if you run this, you should expect different values, and
quite possibly a somewhat different format as well, since formatting for
pointers varies. OTOH, you'll (usually) see something close enough to be
recognizable -- differences of 1 and 1234 (0x4D2) on the two lines.
 
P

Pete Becker

Randy said:
int a[10];

'a' is certainly a pointer to the beginning of the char array.

If that was true then sizeof(a) would be equal to sizeof(int*),
but it isn't. Thus clearly 'a' is not an int*.

The name of an array decays into a pointer to its first element in all
contexts except as the argument to sizeof, typeid, and maybe a couple
of others that I don't have the energy to look up now. So in almost all
situations, the name 'a' has type pointer-to-int, but in sizeof(a) it
does not.
 
P

Phlip

Pete said:
The name of an array decays into a pointer to its first element in all
contexts except as the argument to sizeof, typeid, and maybe a couple of
others that I don't have the energy to look up now.

Including carefully written template argument contexts...
 
R

Randy Graham

Pete said:
Randy said:
int a[10];

'a' is certainly a pointer to the beginning of the char array.

If that was true then sizeof(a) would be equal to sizeof(int*),
but it isn't. Thus clearly 'a' is not an int*.

The name of an array decays into a pointer to its first element in all
contexts except as the argument to sizeof, typeid, and maybe a couple of
others that I don't have the energy to look up now. So in almost all
situations, the name 'a' has type pointer-to-int, but in sizeof(a) it
does not.

Thanks Pete, that's how I've always understood it since starting with
'C' in 1986.
I still don't understand why passing a or &a are equivalent for the
mem??? functions in my example.
 
P

Phlip

Randy said:
Thanks Pete, that's how I've always understood it since starting with 'C'
in 1986.
I still don't understand why passing a or &a are equivalent for the mem???
functions in my example.

Is it because they use void *?

Or because IIRC classic C allows &a as an alias for a?
 
T

Thomas J. Gritzan

Randy said:
Pete said:
Randy Graham wrote:
int a[10];

'a' is certainly a pointer to the beginning of the char array.

If that was true then sizeof(a) would be equal to sizeof(int*),
but it isn't. Thus clearly 'a' is not an int*.

The name of an array decays into a pointer to its first element in all
contexts except as the argument to sizeof, typeid, and maybe a couple
of others that I don't have the energy to look up now. So in almost
all situations, the name 'a' has type pointer-to-int, but in sizeof(a)
it does not.

Thanks Pete, that's how I've always understood it since starting with
'C' in 1986.
I still don't understand why passing a or &a are equivalent for the
mem??? functions in my example.

In &a the array name also doesn't decay to a pointer, so &a has type
pointer to array of int and not pointer to pointer to int.

Since pointer to first element has the same value as pointer to array, but
with another type, and the mem... functions get this converted to void*, it
works in both ways.
 
R

Randy Graham

Ok, I think I get it, although it still seems wrong to me.

Thanks to all who replied !!
 
J

James Kanze

int a[10];
'a' is certainly a pointer to the beginning of the char array.
If that was true then sizeof(a) would be equal to sizeof(int*),
but it isn't. Thus clearly 'a' is not an int*.
[/QUOTE]
The name of an array decays into a pointer to its first element in all
contexts except as the argument to sizeof, typeid, and maybe a couple
of others that I don't have the energy to look up now. So in almost all
situations, the name 'a' has type pointer-to-int, but in sizeof(a) it
does not.

Come now, Pete. That's very sloppy wording, and you certainly
know better. The name 'a' (on its own) has type int[]. Period.
In most contexts, an expression of type int[] does convert to an
int*, but there are more than a few (taking the address of a is
one, binding it to a reference is another) where it doesn't.
And the fact that the expression will implicitly convert to
another type doesn't mean that it has that type. In a statement
like:
double d = 1 ;
you wouldn't say that the expression '1' has type double, would
you?

There are far too many postings claiming that arrays and
pointers are the same thing. Please don't add to the confusion.
There's an implicit conversion, not really any different than
the implicit conversion of int to double, except that it happens
to apply in a lot of very frequent cases.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top