Using &array with scanf

K

Keith Thompson

Mark McIntyre said:
There's little point debating with such people. Give them the
information, explain exactly once why its incorrect to do it
otherwise, and walk away. If still they clean their gun while loaded,
eventually Darwin will come to your rescue.

Natural selection is very much like undefined behavior; there's no
reason to assume it will work to your benefit. The gun he's cleaning
is just as likely to be pointed at your head. More relevantly, you're
like to have to use the code he writes.

Elsethread, I suggested several possibilities for demonstrating that
the "it works for me" approach doesn't work. If *those* don't work,
he may be impervious to reason. Deciding when to give up and accept
this, either by walking away or by somehow preventing his bad code
from affecting anything, is left as an exercise.

But people can sometimes surprise you by turning around becoming
reasonable when you least expect it (see "undefined behavior").
 
D

Dik T. Winter

> Ah, now that's my problem. I made a beeline to that very paragraph to
> prove my point, and the result was a quickie program much like the
> following. He was trying to tell me through the output of the program
> that array and &array result in the same address, and the type doesn't
> matter because scanf will treat the same address like a pointer to
> char, and the type mismatch is irrelevant.

Note the difference:
> > > char array[20];
> > > scanf("%19s", &array);
....
> printf("%p\n%p\n", (void*)&array, (void*)array);

Here &array and array are cast to (void *). So although originally
&array and array may have had different representations, after the
cast they are the some. So this proves exactly nothing. The original
would have been correct if you had written:
scanf("%19s", (char *)&array);
I do not know whether there are, or have been, machines that use different
representations for char pointers and pointers to an array of chars, but
it is conceivable.
 
D

Dik T. Winter

> On a machine where hardware addresses point to words, it's plausible
> that a byte pointer (char*) will have a different representation than
> a word pointer (such as int*); a word pointer could be a machine
> address, while a byte pointer could be a machine address plus an
> offset specifying one byte within the word. (The C compilers on Cray
> vector machines almost do this, but they put the offset into the
> otherwise unused high-order bits of the word pointer.)

The C compiler for the Data General did precisely what you wrote. That
is, a byte pointer would have the byte address in all 32 bits, a word
pointer would have a word address in the lowest 31 bits. And in a byte
pointer the lowest bit indicates the byte in a word.

And on both implementations when c is a char pointer, (char *)(int *)c
may lose information. (Ever tried to implement the original source of
the Bourne shell on such a machine?)

On the other hand, on both implementations a pointer to an array of
chars can not be a word pointer. (There are no padding bytes
between elements of an array.) So on those implementations the
representation of char * and char *[20] is the same. Consider
char a[5][5],
&(a[1]) must be a pointer to the array starting at the fifth byte, and so
can not be a word pointer. And it is the fifth byte because there is no
padding.

But this does *not* say that the pointers can not have different
representations, although I do not know of a system where that is
indeed the case.
 
D

Dik T. Winter

> For a machine on which the type matters, find a 1960s era PR1ME, or
> perhaps even a 1980s Data General MV/10000 (aka Eclipse). (I am not
> sure whether the type "pointer to array N of char" on the Eclipse
> uses a word pointer, but if it does, the &array-with-scanf call will
> in fact fail.)

See my other article. It can not use a word pointer for a pointer to
array N of char, because there is no padding between elements of
arrays.
 
K

Keith Thompson

Dik T. Winter said:
The C compiler for the Data General did precisely what you wrote. That
is, a byte pointer would have the byte address in all 32 bits, a word
pointer would have a word address in the lowest 31 bits. And in a byte
pointer the lowest bit indicates the byte in a word.

And on both implementations when c is a char pointer, (char *)(int *)c
may lose information. (Ever tried to implement the original source of
the Bourne shell on such a machine?)

On the other hand, on both implementations a pointer to an array of
chars can not be a word pointer. (There are no padding bytes
between elements of an array.) So on those implementations the
representation of char * and char *[20] is the same. Consider
char a[5][5],
&(a[1]) must be a pointer to the array starting at the fifth byte, and so
can not be a word pointer. And it is the fifth byte because there is no
padding.

You don't even have to resort to 2-dimensional arrays. Consider

char a[6];
typedef char (*array_ptr)[5];
array_ptr p0 = (array_ptr)a;
array_ptr p1 = (array_ptr)(a+1);

Both p0 and p1 are (I think!) valid pointers to arrays of 5 chars. p0
points to the array starting at element 0 of a; p1 points to the array
starting at element 1 of a (i.e., the last 5 of the 6 elements of a).
But this does *not* say that the pointers can not have different
representations, although I do not know of a system where that is
indeed the case.

Agreed. Even if they happen to have the same representation on all
possible platforms, I wouldn't find it particularly convenient to be
able to make that assumption.

Note that the code snippet above doesn't assume anything about the
representations of the various types of pointers. It uses casts
(explicit conversions), so the compiler will take care of any change
of representation necessary to convert from one pointer type to
another. The original question was about arguments to scanf, for
which no such conversion takes place.
 
J

Jordan Abel

See my other article. It can not use a word pointer for a pointer to
array N of char, because there is no padding between elements of
arrays.

What about padding at the end of an array? Is a pointer to char
guaranteed to be convertible to a pointer to an array of chars?
 
E

eerok

Richard said:
eerok said:
The example you give doesn't fail because of a type issue, but because you
attempt to write to storage that you're not supposed to write to. Had t1
been pointing at writeable storage, you'd have had no segfault. For
example, if you'd done this:
#include <stdio.h>

char *t1 = "This can produce a segfault";
char t2[] = "Best to do it this way ....";

char s[] = "This won't produce a segfault";
t1 = s;

you'd have had no problem, even though the type of t1 hasn't changed.

Thanks for your response, which forced me to do some reading.
If my understanding is correct now, my problem was caused by
trying to write to a string literal, resulting in UB.

I'm trying to scrape the rust off my C skills, which were
learned long ago on a PDP-11 ... between the things I've
forgotten and the things that have changed, I'm pretty much a
newbie again :)
 
R

Richard Heathfield

eerok said:
Thanks for your response, which forced me to do some reading.
If my understanding is correct now, my problem was caused by
trying to write to a string literal, resulting in UB.
Correct.

I'm trying to scrape the rust off my C skills, which were
learned long ago on a PDP-11 ... between the things I've
forgotten and the things that have changed, I'm pretty much a
newbie again :)

You appear to learn reasonably quickly. Stick around clc, read more (much
more) than you write, and ask when you have to. If you do that, then within
a few months you should be sufficiently back up to speed to consider
answering questions here (which, if it can be done regularly without
getting your rear end handed to you on a platter, is almost enough to
qualify you as an "expert").
 
D

Dik T. Winter

>
> What about padding at the end of an array?

No. The size of an array is the product of the number of elements and
the size of an element.
> Is a pointer to char
> guaranteed to be convertible to a pointer to an array of chars?

I do not think it is guaranteed that way. It *is* guaranteed the
other way.
 
E

eerok

Richard said:
eerok said:
[...]
I'm trying to scrape the rust off my C skills, which were
learned long ago on a PDP-11 ... between the things I've
forgotten and the things that have changed, I'm pretty much a
newbie again :)
You appear to learn reasonably quickly. Stick around clc, read more (much
more) than you write, and ask when you have to. If you do that, then within
a few months you should be sufficiently back up to speed to consider
answering questions here (which, if it can be done regularly without
getting your rear end handed to you on a platter, is almost enough to
qualify you as an "expert").

Thanks, Richard. This newsgroup has been an enormous help to
me in the short time that I've been visiting here. Keep up
the good work :)
 
S

Steve Summit

Chris said:
If he is familiar with basketball, try the argument Steve Summit once
repeated here (I am not sure where he got it):

Someone told me that, in basketball, you have to bounce the
ball off the floor; you can't hold the ball and run around the
court. But I tried it and it works just fine. Obviously he
does not understand basketball!

That was Roger Miller said:
Or, for Boston drivers, remember the rule about driving the wrong
way on a one-way street ("it's OK as long as you're in reverse!").

I suppose you think that's some kind of joke! Until recently,
I lived on a quiet one-way residential street in Cambridge,
and I saw people doing that all the time... :)
 

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,733
Messages
2,569,440
Members
44,832
Latest member
GlennSmall

Latest Threads

Top