Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Using &array with scanf

Reply
Thread Tools

Using &array with scanf

 
 
Mike Wahler
Guest
Posts: n/a
 
      01-05-2006

"James Daughtry" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...
> Richard Heathfield wisely wrote:
>> James Daughtry said:
>>
>> > char array[20];
>> > scanf("%19s", &array);
>> >
>> > I know this is wrong because it's a type mismatch, where scanf expects
>> > a pointer to char and gets a pointer to an array of 20 char.

>>
>> Yup. It's also wrong because it doesn't check the return value of scanf.
>>

>
> Yea, I didn't want to dilute the example with error checking.
> Fortunately, I have no intention of compiling that snippet, and I don't
> imagine it will do any harm when executed as a Usenet post.
>
>> > I know that question 6.12 of the C FAQ says that it's wrong for that
>> > very
>> > reason.

>>
>> Yup.
>>
>> > What I don't know is where the standard tells me conclusively that it's
>> > wrong.

>>
>> The fscanf specification:
>>
>> s Matches a sequence of non-white-space characters. The corresponding
>> argument shall be a pointer to the initial character of an array large
>> enough to accept the sequence and a terminating null character, which
>> will be added automatically.
>>
>> &array is not a pointer to the initial character of an array large enough
>> to
>> accept the sequence; it's a pointer to an entire array. Different type.
>> That's a violation of a "shall" outside a constraint, so the behaviour is
>> undefined.
>>

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


Someone who tries to prove program correctness (as defined by
the language standard) by using the behavior of a particular
implementation as evidence, is imo not really worthy of the
title 'programmer'.

> that array and &array result in the same address,


Yes, the same 'value', but certainly not the same type.
Also note that while the 'value' might be the same,
the representation is not required to be the same.

>and the type doesn't
> matter



According to the standard, it *does* matter, very much.

> because scanf will treat the same address like a pointer to
> char,


Nowhere does the language standard make this assertion.

> and the type mismatch is irrelevant.


It's *very* relevant, because it results in undefined behavior.

>
> #include <stdio.h>
>
> int main(void)
> {
> char array[20];
>
> printf("%p\n%p\n", (void*)&array, (void*)array);


This is valid because the types of the arguments being passed
have been converted to types which *are* valid for specifier
'%p'

>
> return 0;
> }
>
> Like I said, he's a stubborn little bugger.


Taking your description as valid, he seems to be to be
both ignorant and arrogant. Very dangerous combination.
I sincerely hope he's not involved in creating critical
software (e.g. that controlling hospital equipment, etc.).

>
>> > What I also don't know is somewhere that this type
>> > mismatch will break in practice.

>>
>> Irrelevant. A conforming implementation which breaks it could be released
>> tomorrow.
>>

>
> Unfortunately, he's the kind of person who uses the "it works for me"
> argument.


And I predict he'll be very surprised when suddenly it
ceases to work, and he has no idea why.

>I know he's wrong, you know he's wrong, but he refuses to
> admit that he's wrong until I can write a program that proves him
> wrong.


That's a losing battle. No program can prove him right or wrong,
since it's not implementations that define the language, but the
ISO standard document (ISO 9899).

>
>> > A peer asked me recently why it was wrong when I told him that it was
>> > wrong, and I was very uncomfortable because I know it's wrong and I had
>> > no good answer when he asked me to prove it.

>>
>> Ask him to explain how he can possibly confuse a char (*)[20] and a char
>> *,
>> given that they are completely different types with completely different
>> sizes.
>>

>
> I asking him almost the same question. I asked why it should work when
> pointers of different types aren't required to have the same
> representation even if they point to the same address, adding emphasis
> by pointing out the relevant parts of the standard. Holding his ground,
> he ran the program again and said that the addresses are the same,



He can run it until doomsday, yet that will still prove nothing,
except perhaps a few things about a particular implementation.

> then
> ran an incorrect scanf example to prove that it worked the way he
> expected,


That only proves that a particular implementation worked the
way he expected. It proves nothing at all about the correctness
of the code.


> and repeated that scanf will do an implicit conversion
> internally.


Ask him to cite from where a guarantee of such a conversion
comes. Certainly not from ISO 9899.

-Mike


 
Reply With Quote
 
 
 
 
Mike Wahler
Guest
Posts: n/a
 
      01-05-2006

"Roland Csaszar" <(E-Mail Removed)> wrote in message
news:87lkxukdrr.wl%(E-Mail Removed)...
> Hi,
>
> At 5 Jan 2006 05:12:32 -0800,
> James Daughtry wrote:
>>
>> char array[20];
>> scanf("%19s", &array);
>>
>> A peer asked me recently why it was wrong when I told him that it was
>> wrong, and I was very uncomfortable because I know it's wrong and I had
>> no good answer when he asked me to prove it.

>
> &array is a pointer to the pointer


It is not. It is simply a pointer.

> to the first element of array,


No. It's a pointer to the entire array.

> it is
> of type char**, not char*.


No. It's type is char(*)[[20] (pointer to array of 20 char).

> You can use
> scanf ("%19s", array);
> or
> scanf ("%19s", &array[0]);


Correct, since both expressions 'array' and '&array[0]'
yield the same type object.

-Mike


 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      01-05-2006
"James Daughtry" <(E-Mail Removed)> writes:
> Richard Heathfield wisely wrote:

[snip]
>> Ask him to explain how he can possibly confuse a char (*)[20] and a char *,
>> given that they are completely different types with completely different
>> sizes.

>
> I asking him almost the same question. I asked why it should work when
> pointers of different types aren't required to have the same
> representation even if they point to the same address, adding emphasis
> by pointing out the relevant parts of the standard. Holding his ground,
> he ran the program again and said that the addresses are the same, then
> ran an incorrect scanf example to prove that it worked the way he
> expected, and repeated that scanf will do an implicit conversion
> internally.


scanf doesn't do a conversion, implicit or otherwise. It takes
whatever bits you give it and *assumes* that they constitute a valid
representation of an object of the correct type. There are
open-source/freeware implementations of scanf; ask him to show you the
code that does this "implicit conversion".

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

He ran the program again *on the same platform* and claimed that he
had proven that it works correctly. Pick a platform that he doesn't
have access to and ask him to "prove" that his code works correctly on
that platform.

Show him the following program:

#include <stdio.h>
int main(void)
{
int before[10];
int array[10];
int after[10];
array[-1] = array[10] = 42;
printf("array[-1] = %d\n", array[-1]);
printf("array[10] = %d\n", array[10]);
return 0;
}

You and I know that it invokes undefined behavior. On most systems,
I'd be surprised if the manifestation of that undefined behavior were
something other than producing the following output:

array[-1] = 42
array[10] = 42

Compile and run the program several times, showing him the consistent
output each time. Ask him if this "proves" that accessing elements
outside an array is valid.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <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.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      01-05-2006
Roland Csaszar <(E-Mail Removed)> writes:
> At 5 Jan 2006 05:12:32 -0800,
> James Daughtry wrote:
>>
>> char array[20];
>> scanf("%19s", &array);
>>
>> A peer asked me recently why it was wrong when I told him that it was
>> wrong, and I was very uncomfortable because I know it's wrong and I had
>> no good answer when he asked me to prove it.

>
> &array is a pointer to the pointer to the first element of array, it is
> of type char**, not char*.


Nope. Time to re-read section 6 of the comp.lang.c FAQ.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <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.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      01-05-2006
Keith Thompson <(E-Mail Removed)> writes:
[snip]
> He ran the program again *on the same platform* and claimed that he
> had proven that it works correctly. Pick a platform that he doesn't
> have access to and ask him to "prove" that his code works correctly on
> that platform.


I suggest the IBM AS/400, especially if he's not familiar with it.
I'm not very familiar with it myself, but it seems to be a canonical
example of a system with a conforming C implementation that breaks a
lot of assumptions if you don't carefully stick to what the standard
actually guarantees; it's second only to the DS9K.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <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.
 
Reply With Quote
 
Chris Torek
Guest
Posts: n/a
 
      01-05-2006
In article <(E-Mail Removed) .com>
James Daughtry <(E-Mail Removed)> wrote:
>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.


The problem with this argument lies in the phrase "the type mismatch
is irrelevant". That may be the case on *his* machine, but it is
definitely not the case on *every* machine.

There are machines (Burroughs A-series) in which integers are stored
in the same format as floating-point. (The compiler just makes sure
that the fractional part is always zero.) On such a machine, if you
do this:

double x;

ret = scanf("%d", (int *)&x);
if (ret == 1)
printf("I got %f\n", x);

the code actually works! But it fails on most machines, because the
type is *not* irrelevant on most machines.

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

>Unfortunately, he's the kind of person who uses the "it works for me"
>argument. I know he's wrong, you know he's wrong, but he refuses to
>admit that he's wrong until I can write a program that proves him
>wrong.


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!

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!").
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.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.
 
Reply With Quote
 
eerok
Guest
Posts: n/a
 
      01-05-2006
Richard Heathfield wrote:
> kaikai said:


>> Since
>> array and &array do have the same value,


> But they don't. The values have different types, so how can they be the
> same?
>
> Are $3.14 and 3.14kg the same? Of course not.
> Are 3.14% and 3.14km the same? Of course not.
>
> The type /matters/.


>> It is okay to write such code,


> No, it isn't.


Just to illustrate that it's *not* okay to get sloppy with
types, here's an example that I discovered the other day.


#include <stdio.h>

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

int
main (void)
{
int ia = 3, ib = 2;

/* no apparent problem (on my compiler) when I
* index into either string */
printf ("\nt1: '%s', 4th char: '%c'", t1, t1[ia]);
printf ("\nt2: '%s', 4th char: '%c'\n", t2, t2[ia]);

/* this is of course fine since we've declared
* the string is an array of char */
t2[ib] = t2[ia];
printf ("\nNo segfault here.\n");

/* this will produce a segfault with my compiler */
t1[ib] = t1[ia];
printf ("\nMaybe you'll get this far, but I don't.\n");

return 0;
}


One might think that "a string is a string is a string" --
that a pointer to a string is the same as the address of the
first char of an array of chars. It usually seems to work
this way, but the example above shows this isn't true.

--
"The secret of being boring is to say everything." - Voltaire


 
Reply With Quote
 
Mark McIntyre
Guest
Posts: n/a
 
      01-05-2006
On 5 Jan 2006 05:40:08 -0800, in comp.lang.c , "James Daughtry"
<(E-Mail Removed)> wrote:

>Unfortunately, he's the kind of person who uses the "it works for me"
>argument.


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.
Mark McIntyre
--

----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
 
Reply With Quote
 
Mark McIntyre
Guest
Posts: n/a
 
      01-05-2006
On 5 Jan 2006 09:36:23 -0800, in comp.lang.c , "James Daughtry"
<(E-Mail Removed)> wrote:

>I'm sure that one day he'll get burned by UB and start to understand.
>But until then, I have to work with the guy and suffer his "it works
>for me" attitude.


You could complain to your manager that his code is badly written and
potentially dangerous, pointing to the sections of the Standard which
are relevant. Even complete idiot managers tend to rely on
documentation and will accept that over "it works for me".....

Mark McIntyre
--

----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
 
Reply With Quote
 
Richard Heathfield
Guest
Posts: n/a
 
      01-05-2006
eerok said:

> Just to illustrate that it's *not* okay to get sloppy with
> types, here's an example that I discovered the other day.


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.



--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
difference between scanf("%i") and scanf("%d") ??? perhaps bug inVS2005? =?ISO-8859-1?Q?Martin_J=F8rgensen?= C Programming 18 05-02-2006 10:53 AM
scanf (yes/no) - doesn't work + deprecation errors scanf, fopen etc. =?ISO-8859-1?Q?Martin_J=F8rgensen?= C Programming 185 04-03-2006 02:49 PM
Re: Can I detect "enter" key using scanf? bd C Programming 0 08-07-2003 02:03 AM
Re: Can I detect "enter" key using scanf? Dan Pop C Programming 0 08-06-2003 11:32 AM
Re: Can I detect "enter" key using scanf? Ben Pfaff C Programming 0 08-05-2003 09:49 PM



Advertisments