Discussion:
Why is this giving me error?
(too old to reply)
Christopher
2017-07-10 03:55:00 UTC
Permalink
Raw Message
#include <stdio.h>
#include <math.h>


void getnum ()
{
int num;
char again;

printf ("Enter an integer to be squared: ");
scanf ("%d", &num );

printf ("%d Squared is %d\n", num, sqr (num) );

printf ("Square another number? Y or N: ");
scanf ("%1s", &again);

if ( (again == 'Y') || (again == 'y') ) getnum();
else return;
}

int sqr (int num)
{
return (pow (num, 2) );
}


int main()
{

int start;

getnum();

return 0;
}
Stefan Ram
2017-07-10 04:23:41 UTC
Permalink
Raw Message
Post by Christopher
printf ("%d Squared is %d\n", num, sqr (num) );
sqr has not been declared here yet.
Post by Christopher
scanf ("%1s", &again);
scanf will add a terminating NUL (IIRC),
but there was no memory reserved for it.
Post by Christopher
return (pow (num, 2) );
Here the double value is /truncated/ to an int,
which might produce quite a large error.
Post by Christopher
int start;
What's that for?
Keith Thompson
2017-07-10 04:51:43 UTC
Permalink
Raw Message
Post by Christopher
#include <stdio.h>
#include <math.h>
void getnum ()
Better: void getnum(void)
Post by Christopher
{
int num;
char again;
printf ("Enter an integer to be squared: ");
scanf ("%d", &num );
printf ("%d Squared is %d\n", num, sqr (num) );
The declaration of sqr() isn't visible at this point. That's ok in
C89/C90, but not in C99 or later.
Post by Christopher
printf ("Square another number? Y or N: ");
scanf ("%1s", &again);
This will attempt to store two bytes in again.

It would make more sense to use getchar(), but it would read input left
behind by the scanf() call.
Post by Christopher
if ( (again == 'Y') || (again == 'y') ) getnum();
else return;
Calling getnum() recursively is odd. A loop would be better.
Post by Christopher
}
int sqr (int num)
{
return (pow (num, 2) );
}
As I wrote elsethread, num * num is a better way to do this.
Post by Christopher
int main()
Better: int main(void)
Post by Christopher
{
int start;
You don't use this.
Post by Christopher
getnum();
return 0;
}
What error?

I can think of at least two possible things a compiler might complain
about, but you haven't shown us the error message.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Barry Schwarz
2017-07-11 05:43:08 UTC
Permalink
Raw Message
It would help considerably if you told us what kind of error you were
given. Is it a compiler error, a linker error, the wrong value, some
other unexpected behavior, or does your program terminate abnormally.

For future reference, it pays to put your question in the body of your
message.

On Mon, 10 Jul 2017 01:55:00 -0200, Christopher
Post by Christopher
#include <stdio.h>
#include <math.h>
void getnum ()
{
int num;
char again;
printf ("Enter an integer to be squared: ");
scanf ("%d", &num );
printf ("%d Squared is %d\n", num, sqr (num) );
printf ("Square another number? Y or N: ");
scanf ("%1s", &again);
if ( (again == 'Y') || (again == 'y') ) getnum();
else return;
}
int sqr (int num)
{
return (pow (num, 2) );
}
int main()
{
int start;
getnum();
return 0;
}
--
Remove del for email
Christopher
2017-07-12 00:30:00 UTC
Permalink
Raw Message
Post by Barry Schwarz
It would help considerably if you told us what kind of error you were
given. Is it a compiler error, a linker error, the wrong value, some
other unexpected behavior, or does your program terminate abnormally.
For future reference, it pays to put your question in the body of your
message.
The error I was getting was as shown in this picture:

<Loading Image...>

The problem was that I was using:

scanf ("%1s", &again);

When I should have been using:

scanf (" %c", &again);

Notice the white-spaces before %c. Apparently, to read single
character, it is necessary to have some spaces according to this link
and other articles I found online:

<https://stackoverflow.com/questions/13542055/how-to-do-scanf-for-single-char-in-c>

I like to find the real solution before trying some other functions like
fgetc, getchar etc, I wanted to document scanf (and Microsoft's
scanf_s). I struggled for about 3 days but it was worth it. Ram and
Thompson did point me in the right-direction and I am very thankful to them.

Best regards,
Post by Barry Schwarz
On Mon, 10 Jul 2017 01:55:00 -0200, Christopher
Post by Christopher
#include <stdio.h>
#include <math.h>
void getnum ()
{
int num;
char again;
printf ("Enter an integer to be squared: ");
scanf ("%d", &num );
printf ("%d Squared is %d\n", num, sqr (num) );
printf ("Square another number? Y or N: ");
scanf ("%1s", &again);
if ( (again == 'Y') || (again == 'y') ) getnum();
else return;
}
int sqr (int num)
{
return (pow (num, 2) );
}
int main()
{
int start;
getnum();
return 0;
}
Keith Thompson
2017-07-12 01:15:32 UTC
Permalink
Raw Message
Post by Christopher
Post by Barry Schwarz
It would help considerably if you told us what kind of error you were
given. Is it a compiler error, a linker error, the wrong value, some
other unexpected behavior, or does your program terminate abnormally.
For future reference, it pays to put your question in the body of your
message.
<https://s7d6.turboimg.net/sp/10ec9bd5759279f2f371e81312b8ac7c/C-Error-Message.png>
It's almost always better to post copy-and-pasted text rather than a
link to a picture of text. For one thing, the site hosting the image
might not keep it there forever, whereas this article is likely to
persist for years.

It's a run time error, "Stack around the variable 'again' was corrupted".

With the right options, you should have gotten several compile-time
warnings as well.
Post by Christopher
scanf ("%1s", &again);
scanf (" %c", &again);
One space would be sufficient.

A directive composed of white-space character(s) is executed
by reading input up to the first non-white-space character
(which remains unread), or until no more characters can be read.

scanf("% %c", &again) should work.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Ben Bacarisse
2017-07-12 02:03:55 UTC
Permalink
Raw Message
<snip>
Post by Keith Thompson
Post by Christopher
scanf ("%1s", &again);
scanf (" %c", &again);
One space would be sufficient.
A directive composed of white-space character(s) is executed
by reading input up to the first non-white-space character
(which remains unread), or until no more characters can be read.
scanf("% %c", &again) should work.
I think you meant scanf(" %c", &again). % introduces a conversion
specification and "% " has no defined meaning, though the first % looks
like finger trouble rather than a misunderstand about what constitutes a
directive.
--
Ben.
Keith Thompson
2017-07-12 16:15:27 UTC
Permalink
Raw Message
[...]
Post by Ben Bacarisse
Post by Keith Thompson
scanf("% %c", &again) should work.
I think you meant scanf(" %c", &again). % introduces a conversion
specification and "% " has no defined meaning, though the first % looks
like finger trouble rather than a misunderstand about what constitutes a
directive.
Yes, thanks. Stupid fingers!
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
m***@gmail.com
2017-07-12 09:11:42 UTC
Permalink
Raw Message
Post by Christopher
#include <stdio.h>
#include <math.h>
void getnum ()
{
int num;
char again;
printf ("Enter an integer to be squared: ");
scanf ("%d", &num );
printf ("%d Squared is %d\n", num, sqr (num) );
printf ("Square another number? Y or N: ");
scanf ("%1s", &again);
if ( (again == 'Y') || (again == 'y') ) getnum();
else return;
}
Can I ask if anyone believes scanf() is useful for interactive use,
or does the CLC FAQ Q12.20 <http://c-faq.com/stdio/scanfprobs.html>
still apply?
Scott Lurndal
2017-07-12 12:48:34 UTC
Permalink
Raw Message
Post by m***@gmail.com
Post by Christopher
#include <stdio.h>
#include <math.h>
void getnum ()
{
int num;
char again;
printf ("Enter an integer to be squared: ");
scanf ("%d", &num );
printf ("%d Squared is %d\n", num, sqr (num) );
printf ("Square another number? Y or N: ");
scanf ("%1s", &again);
if ( (again == 'Y') || (again == 'y') ) getnum();
else return;
}
Can I ask if anyone believes scanf() is useful for interactive use,
or does the CLC FAQ Q12.20 <http://c-faq.com/stdio/scanfprobs.html>
still apply?
In almost forty years of intensive C and C++ programming, I've
_never_ found a use for scanf in production code.
s***@casperkitty.com
2017-07-12 16:35:09 UTC
Permalink
Raw Message
Post by Scott Lurndal
In almost forty years of intensive C and C++ programming, I've
_never_ found a use for scanf in production code.
Much of the Standard library only exists because of historical inertia,
and the fact that nobody has had enough "clout" to provide better
replacements; worse, there are a lot of things which a good standard
library should provide, but which C still doesn't, such as:

1. A function like puts(), but without the newline.

2. Functions like gets() and fgets(), but which read an entire line, store
as much as will fit, and indicate how many characters were read.

3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.

I don't think any implementation should have any trouble supplying the above,
and on platforms that have a "read line" system call, #2 could offer better
performance than could be achieved otherwise, but as yet I know of no
standard for any of the above.
Keith Thompson
2017-07-12 16:52:37 UTC
Permalink
Raw Message
Post by s***@casperkitty.com
Post by Scott Lurndal
In almost forty years of intensive C and C++ programming, I've
_never_ found a use for scanf in production code.
Much of the Standard library only exists because of historical inertia,
and the fact that nobody has had enough "clout" to provide better
replacements; worse, there are a lot of things which a good standard
1. A function like puts(), but without the newline.
fputs(s, stdout);

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Kenny McCormack
2017-07-12 16:57:56 UTC
Permalink
Raw Message
Post by Keith Thompson
Post by s***@casperkitty.com
Post by Scott Lurndal
In almost forty years of intensive C and C++ programming, I've
_never_ found a use for scanf in production code.
Much of the Standard library only exists because of historical inertia,
and the fact that nobody has had enough "clout" to provide better
replacements; worse, there are a lot of things which a good standard
1. A function like puts(), but without the newline.
fputs(s, stdout);
All of the things supercat mentions are do-able in user-code.

I don't think anybody doubts or denies that.

The point is that it would be nice to have them in the library,
standardized (in any of mulitple senses of that word).

To elaborate on that last point, let me be explicit. It is better that
they are just in the library and usable, than to have each user implement
them on their own, in slightly different and incompatible ways.
--
Alice was something of a handful to her father, Theodore Roosevelt. He was once
asked by a visiting dignitary about parenting his spitfire of a daughter and he
replied, "I can be President of the United States, or I can control Alice. I
cannot possibly do both."
s***@casperkitty.com
2017-07-12 21:41:58 UTC
Permalink
Raw Message
Post by Kenny McCormack
All of the things supercat mentions are do-able in user-code.
If there were a version of gets() which accepted a maximum-length parameter
and an application calls it with a length of e.g. three, an implementation
could visually indicate to the user how much data would be accepted in
whatever fashion would be typical of programs on that platform. There is
no portable way of doing that in user code.

Unix people might not mind the lack of such a feature in the language, since
the OS doesn't generally indicate expected input length except when using
something like curses, at which point portability with non-Unix systems flies
out the window.
Joe Pfeiffer
2017-07-12 22:14:21 UTC
Permalink
Raw Message
Post by Kenny McCormack
Post by Keith Thompson
Post by s***@casperkitty.com
Post by Scott Lurndal
In almost forty years of intensive C and C++ programming, I've
_never_ found a use for scanf in production code.
Much of the Standard library only exists because of historical inertia,
and the fact that nobody has had enough "clout" to provide better
replacements; worse, there are a lot of things which a good standard
1. A function like puts(), but without the newline.
fputs(s, stdout);
All of the things supercat mentions are do-able in user-code.
I don't think anybody doubts or denies that.
The point is that it would be nice to have them in the library,
standardized (in any of mulitple senses of that word).
To elaborate on that last point, let me be explicit. It is better that
they are just in the library and usable, than to have each user implement
them on their own, in slightly different and incompatible ways.
fputs(s, stdout) is a single function in the library taking one more
parameter than puts(s). That seems to meet the goal just fine.

The other two would, indeed, take some more user code to implement.
s***@casperkitty.com
2017-07-12 21:20:05 UTC
Permalink
Raw Message
Post by Keith Thompson
Post by s***@casperkitty.com
1. A function like puts(), but without the newline.
fputs(s, stdout);
Some systems may support forms of console I/O that behave differently from
file I/O using stdout. Whatever reasons exist to have functions like
printf, rather than using fprintf(stdout, ...) would seem just as applicable
in the even more common case where code simply wants to output a string
(without a newline). I would suggest that the whole reason that printf gets
abused to output strings that aren't expected to contain percent signs is
that it's the most compact way of achieving such behavior.
Keith Thompson
2017-07-12 21:45:14 UTC
Permalink
Raw Message
Post by s***@casperkitty.com
Post by Keith Thompson
Post by s***@casperkitty.com
1. A function like puts(), but without the newline.
fputs(s, stdout);
Some systems may support forms of console I/O that behave differently from
file I/O using stdout.
Are you suggesting that
puts("hello");
and
fputs("hello\n", stdout);
can behave differently? If not, what are you talking about?

I'm not entirely happy with the seemingly arbitrary difference
between puts() and fputs(), but it's there, and we can safely take
advantage of it.

One alternative would have been to provide 4 functions (with and
without a FILE* argument, and with and without an added newline),
but that would have cluttered the name space.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
s***@casperkitty.com
2017-07-12 22:28:08 UTC
Permalink
Raw Message
Post by Keith Thompson
Are you suggesting that
puts("hello");
and
fputs("hello\n", stdout);
can behave differently? If not, what are you talking about?
They could potentially do so. MS-DOS systems have low-level and high-level
ways of doing console I/O; the high-level I/O supports indirection but on
older systems was dog slow. Console I/O using the lower-level approaches
could be more than twice as fast as using the high-level approaches. Since
writing a screen of text through high-level DOS calls could take several
seconds, that would be a useful speedup.

The MS-DOS compilers I've used made "printf" go through stdout and added
new functions like "cprintf" to output things more quickly, but I would
not be surprised if some compilers used the faster routines by default
rather than sending everything through stdout.
j***@verizon.net
2017-07-12 23:14:07 UTC
Permalink
Raw Message
Post by s***@casperkitty.com
Post by Keith Thompson
Are you suggesting that
puts("hello");
and
fputs("hello\n", stdout);
can behave differently? If not, what are you talking about?
They could potentially do so.
Sure, they could. However:

"The fputs function writes the string pointed to by *s* to the stream pointed to by *stream*. The terminating null character is not written." (7.21.7.4p2)

"The puts function writes the string pointed to by *s* to the stream pointed to by *stdout*, and appends a new-line character to the output. The terminating null character is not written." (7.21.7.9p2)

In the call fputs(s, stdout), "the stream pointed to by *stream*" IS "the stream pointed to by *stdout*". With that substitution, the two descriptions become identical except the part about the newline character.

Therefore, any implementation of C that produced different observable behavior for puts(s) and fputs(s, stdout) would be non-conforming. Do you know of any implementation that is non-conforming in that fashion?
Post by s***@casperkitty.com
... MS-DOS systems have low-level and high-level
ways of doing console I/O; the high-level I/O supports indirection but on
older systems was dog slow. Console I/O using the lower-level approaches
could be more than twice as fast as using the high-level approaches. Since
writing a screen of text through high-level DOS calls could take several
seconds, that would be a useful speedup.
The MS-DOS compilers I've used made "printf" go through stdout and added
new functions like "cprintf" to output things more quickly, but I would
not be surprised if some compilers used the faster routines by default
rather than sending everything through stdout.
I presume that cprintf() can avoid sending everything through stdout, because it is defined as writing to the console, regardless of what stream stdout refers to. Does it interact properly with printf()? For instance, if stdout points to a stream associated with the console, and if the side effects of a particular call to cprintf() are required by the C standard to be sequenced after the side-effects of a particular printf() call, does that actually happen? Since, for printf(), those side effects involve the flushing of the buffer associated with stdout, I don't see how they could be properly sequenced if cprintf() fails to interact with the data structures associated with that buffer. This would be permissible, since there's no way to link in cprintf() that doesn't render the behavior of the code undefined - but it would be rather annoying.

However, printf(), puts(), and fputs(..., stdout) are all defined as writing to whichever stream stdout points at, so none of those functions has the option of not "sending everything through stdout". If a program uses freopen() to associate stdout with a different stream, then printf(), puts(), and fputs(..., stdout) are all required to to send their output to that same different stream.

In any event, the speed with which something happens is constrained by the C standard. Differences in the speed do not count as differences in observable behavior. If that's the only way that puts(s) and fputs(s, stdout) differ, that would not, in itself, render such an implementation non-conforming.

However, if puts() could somehow always send it's output to whichever stream stdout refers to, even if reopened, while gaining a speed advantage by somehow doing so without "sending everything through stdout", then what prevents fputs(..., stream) from taking that same approach whenever stream==stdout?
James R. Kuyper
2017-07-12 23:21:47 UTC
Permalink
Raw Message
Post by Keith Thompson
Are you suggesting that
puts("hello");
and
fputs("hello\n", stdout);
can behave differently? If not, what are you talking about?
...
Therefore, any implementation of C that produced different observable behavior for puts(s) and fputs(s, stdout) would be non-conforming. ...
That was stated incorrectly - I should have borrowed from Keith's
example: 'any implementation of C that produced different observable
behavior from puts("hello") and fputs("hello\n", stdout) would be
non-conforming'.

The \n makes a big difference in the accuracy of the statement.
...
... If that's the only way that puts(s) and fputs(s, stdout) differ, that would not, in itself, render such an implementation non-conforming.
A similar modification is required for that sentence.
s***@casperkitty.com
2017-07-13 00:19:09 UTC
Permalink
Raw Message
Post by j***@verizon.net
Therefore, any implementation of C that produced different observable behavior for puts(s) and fputs(s, stdout) would be non-conforming. Do you know of any implementation that is non-conforming in that fashion?
I know of platforms where being non-conforming in such fashion would have
made them more useful for many purposes. I also know of freestanding
implementations that support printf and friends but not fopen, fprintf,
etc.

In any case, I see no reason why a system should provide special "console
I/O" functions for many tasks but not for outputting a string without a
trailing new-line, or inputting a line with bounded length.
Post by j***@verizon.net
I presume that cprintf() can avoid sending everything through stdout, because it is defined as writing to the console, regardless of what stream stdout refers to. Does it interact properly with printf()? For instance, if stdout points to a stream associated with the console, and if the side effects of a particular call to cprintf() are required by the C standard to be sequenced after the side-effects of a particular printf() call, does that actually happen?
If stdout isn't redirected, things will be displayed in sequence on the
same console. If it is redirected, cprintf will continue to go to the
console regardless of what stdout does. If a program needs to prompt the
user to do something, that's a good feature.
Post by j***@verizon.net
However, if puts() could somehow always send it's output to whichever stream stdout refers to, even if reopened, while gaining a speed advantage by somehow doing so without "sending everything through stdout", then what prevents fputs(..., stream) from taking that same approach whenever stream==stdout?
The ability to redirect stdout may be useful for some purposes, but for
other purposes having forms of I/O that *can't* be redirected can also
be useful. The Standard opted to mandate the former and ignore the latter,
but I wouldn't be surprised if in pre-standard days the former was pretty
common.
Scott Lurndal
2017-07-12 16:56:49 UTC
Permalink
Raw Message
Post by s***@casperkitty.com
Post by Scott Lurndal
In almost forty years of intensive C and C++ programming, I've
_never_ found a use for scanf in production code.
Much of the Standard library only exists because of historical inertia,
and the fact that nobody has had enough "clout" to provide better
replacements; worse, there are a lot of things which a good standard
1. A function like puts(), but without the newline.
fputs(string, stdout);
Post by s***@casperkitty.com
2. Functions like gets() and fgets(), but which read an entire line, store
as much as will fit, and indicate how many characters were read.
Or one can simply call strlen() after fgets() returns in the
rather unusual case where the length of the string is needed.

One should _never_ use gets().
Post by s***@casperkitty.com
3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.
Of limited usefulness. I've used snprintf() instead of strcpy for the last
15 or so years, and snprintf does return the index to the nul byte, unless
the output buffer overflows.
Kenny McCormack
2017-07-12 17:03:46 UTC
Permalink
Raw Message
Post by Scott Lurndal
Post by s***@casperkitty.com
Post by Scott Lurndal
In almost forty years of intensive C and C++ programming, I've
_never_ found a use for scanf in production code.
Much of the Standard library only exists because of historical inertia,
and the fact that nobody has had enough "clout" to provide better
replacements; worse, there are a lot of things which a good standard
1. A function like puts(), but without the newline.
fputs(string, stdout);
All of the things supercat mentions are do-able in user-code.

I don't think anybody doubts or denies that.

The point is that it would be nice to have them in the library,
standardized (in any of mulitple senses of that word).

To elaborate on that last point, let me be explicit. It is better that
they are just in the library and usable, than to have each user implement
them on their own, in slightly different and incompatible ways.
--
http://www.rollingstone.com/politics/news/the-10-dumbest-things-ever-said-about-global-warming-20130619
Ike Naar
2017-07-12 18:05:01 UTC
Permalink
Raw Message
Post by Scott Lurndal
Post by s***@casperkitty.com
3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.
Of limited usefulness.
But probably more useful than the current behaviour, which returns
a pointer to the beginning of the destination string, which gives
you nothing new because you already have other means to get that
information.

Of course the behaviour of strcpy can't be changed now because that
would break existing code, but that does not mean that the current
behaviour is the best choice that could have been made.
Keith Thompson
2017-07-12 19:29:28 UTC
Permalink
Raw Message
Post by Ike Naar
Post by Scott Lurndal
Post by s***@casperkitty.com
3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.
Of limited usefulness.
But probably more useful than the current behaviour, which returns
a pointer to the beginning of the destination string, which gives
you nothing new because you already have other means to get that
information.
Of course the behaviour of strcpy can't be changed now because that
would break existing code, but that does not mean that the current
behaviour is the best choice that could have been made.
I suspect the intent was to allow operations to be chained:

strcat(strcpy(s, foo), bar);

Of course that kind of chaining prevents checking for errors on each
operation, which was probably considered less important when the library
was designed than it is now.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
s***@casperkitty.com
2017-07-12 21:14:38 UTC
Permalink
Raw Message
Post by Keith Thompson
Post by Ike Naar
Post by Scott Lurndal
Post by s***@casperkitty.com
3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.
Of limited usefulness.
But probably more useful than the current behaviour, which returns
a pointer to the beginning of the destination string, which gives
you nothing new because you already have other means to get that
information.
Of course the behaviour of strcpy can't be changed now because that
would break existing code, but that does not mean that the current
behaviour is the best choice that could have been made.
strcat(strcpy(s, foo), bar);
Of course that kind of chaining prevents checking for errors on each
operation, which was probably considered less important when the library
was designed than it is now.
I shortened the list and omitted variations which would accept the source
max length and/or a pointers just past the end of the destination buffers,
which would allow safe and easy chaining as:

safecpy(safecpy(safecpy(dest, src1, destend),
src2, destend),
src3, destend);

Note that using a just-past pointer for the destination buffer rather than
the destination space available avoids the need to recompute how much space
is available after each operation.
Ben Bacarisse
2017-07-12 22:03:28 UTC
Permalink
Raw Message
Post by Keith Thompson
Post by Ike Naar
Post by Scott Lurndal
Post by s***@casperkitty.com
3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.
Of limited usefulness.
But probably more useful than the current behaviour, which returns
a pointer to the beginning of the destination string, which gives
you nothing new because you already have other means to get that
information.
Of course the behaviour of strcpy can't be changed now because that
would break existing code, but that does not mean that the current
behaviour is the best choice that could have been made.
strcat(strcpy(s, foo), bar);
I agree about the probable intent, but this example would work still
with the proposed "better" function that returns a pointer to the
trailing null.

<snip>
--
Ben.
James R. Kuyper
2017-07-12 22:18:09 UTC
Permalink
Raw Message
Post by Ben Bacarisse
Post by Keith Thompson
Post by Ike Naar
Post by Scott Lurndal
Post by s***@casperkitty.com
3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.
Of limited usefulness.
But probably more useful than the current behaviour, which returns
a pointer to the beginning of the destination string, which gives
you nothing new because you already have other means to get that
information.
Of course the behaviour of strcpy can't be changed now because that
would break existing code, but that does not mean that the current
behaviour is the best choice that could have been made.
strcat(strcpy(s, foo), bar);
I agree about the probable intent, but this example would work still
with the proposed "better" function that returns a pointer to the
trailing null.
Not only would it work, it would work better. However, with that change,
it would be equivalent to strcpy(strcpy(s,foo), bar), which would be a
more appropriate way of chaining them.
Tim Rentsch
2017-07-14 21:01:23 UTC
Permalink
Raw Message
Post by Keith Thompson
Post by Ike Naar
Post by Scott Lurndal
3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.
Of limited usefulness.
But probably more useful than the current behaviour, which returns
a pointer to the beginning of the destination string, which gives
you nothing new because you already have other means to get that
information.
Of course the behaviour of strcpy can't be changed now because that
would break existing code, but that does not mean that the current
behaviour is the best choice that could have been made.
strcat(strcpy(s, foo), bar);
Of course that kind of chaining prevents checking for errors on each
operation, which was probably considered less important when the library
was designed than it is now.
The str*cpy/cat() functions have no error conditions to check.
s***@casperkitty.com
2017-07-14 21:51:22 UTC
Permalink
Raw Message
Post by Tim Rentsch
Post by Keith Thompson
strcat(strcpy(s, foo), bar);
Of course that kind of chaining prevents checking for errors on each
operation, which was probably considered less important when the library
was designed than it is now.
The str*cpy/cat() functions have no error conditions to check.
The "blindly overwrite whatever is at destination" versions don't, but
versions that could use a limited-length destination might fill that up
without exhausting the source, and it might be useful to report that.
On the other hand, returning a pointer just past the end of the destination
would be a good way of indicating that the source content didn't all fit.

In any case, a better chaining example would be something like:

puts(strcat(buffer1, "%d\n"));

where the "puts" would need a call to the start of the buffer rather
than the end (unlike strcat, which would be better off receiving a
pointer to the zero byte written by strcpy, than to the start of the
resulting string). Even in scenarios where it could be slightly useful,
though, I doubt there are very many programs where the performance
benefits from not having to reload the address of buffer1 in the few
cases where that would be helpful would exceed the cost of every
strcpy/strcat call having to keep a copy of the destination's start
address. Unless a machine has more than two registers which a called
function can trash *without having to save them first*, an strcpy/strcat
that returns a pointer to the start of the destination will likely not
only be less useful, but also *slower*, than one that returns a pointer
to the end.
Tim Rentsch
2017-07-14 22:17:08 UTC
Permalink
Raw Message
Post by Ike Naar
Post by Scott Lurndal
3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.
Of limited usefulness.
But probably more useful than the current behaviour, which returns
a pointer to the beginning of the destination string, which gives
you nothing new because you already have other means to get that
information.
The same is true of the suggested alternative.
s***@casperkitty.com
2017-07-14 22:48:06 UTC
Permalink
Raw Message
Post by Tim Rentsch
Post by Ike Naar
Post by Scott Lurndal
3. A function like strcpy which returns a pointer to where it wrote the
trailing zero byte.
Of limited usefulness.
But probably more useful than the current behaviour, which returns
a pointer to the beginning of the destination string, which gives
you nothing new because you already have other means to get that
information.
The same is true of the suggested alternative.
If one doesn't know the exact length of the source string, there's no
efficient way of getting the final address written by strcpy or strcat.
While one could use strlen to recompute that information after doing
strcpy/strcat, the only advantage that strcpy/strcat have over memcpy is
that they eliminate the need to call strlen. If code is going to need
the value from strlen for other purposes, calling strlen and then memcpy
is almost certainly better than using strlen in combination with strcpy
or strcat.

Ben Bacarisse
2017-07-12 14:14:16 UTC
Permalink
Raw Message
Post by m***@gmail.com
Post by Christopher
#include <stdio.h>
#include <math.h>
void getnum ()
{
int num;
char again;
printf ("Enter an integer to be squared: ");
scanf ("%d", &num );
printf ("%d Squared is %d\n", num, sqr (num) );
printf ("Square another number? Y or N: ");
scanf ("%1s", &again);
if ( (again == 'Y') || (again == 'y') ) getnum();
else return;
}
Can I ask if anyone believes scanf() is useful for interactive use,
or does the CLC FAQ Q12.20 <http://c-faq.com/stdio/scanfprobs.html>
still apply?
I think it's a bit more useful than most, but it's still problematic.
It can be useful for "sloppy" interactive input in the

while (scanf("%lf %lf", &x, &y) == 2) ...

mould. This can get beginners up an running quite quickly.

You can, just about, using it in situations like the above, but you need
to know more than most people ever care to about it. For example, to
get the "discard surplus input on the line" behaviour that is usually
expected you can write:

#include <stdio.h>
#include <stdbool.h>

bool prompt_for_double(double *d)
{
printf("Enter a number: ");
fflush(stdout);
return scanf("%lf%*[^\n]%*1[\n]", d) == 1;
}

bool prompt_for_y(void)
{
printf("Go again? ");
fflush(stdout);
return scanf(" %1[yY]%*[^\n]%*1[\n]", (char [2]){0}) == 1;
}

int main(void)
{
double d;
if (prompt_for_double(&d) == 1)
do printf("%f * %f = %f\n", d, d, d*d);
while (prompt_for_y() && prompt_for_double(&d));
}

(I've got my fingers in my ears so I can't hear the howls of protest!)
--
Ben.
Alain Ketterlin
2017-07-12 14:58:21 UTC
Permalink
Raw Message
Post by Ben Bacarisse
Post by m***@gmail.com
Can I ask if anyone believes scanf() is useful for interactive use,
or does the CLC FAQ Q12.20 <http://c-faq.com/stdio/scanfprobs.html>
still apply?
I think it's a bit more useful than most, but it's still problematic.
[...]
Post by Ben Bacarisse
bool prompt_for_double(double *d)
{
printf("Enter a number: ");
fflush(stdout);
return scanf("%lf%*[^\n]%*1[\n]", d) == 1;
}
[...]

+1. Plus scanf's ability to pattern-match the input, as in:

scanf("( %d , %d )",&x,&y)

when it makes lexical analyzers (or trivial parsers) easier to write.

I actually haven't used scanf for decades, and certainly won't use it
for interactive use, but sscanf can be handy.

-- Alain.
John Bode
2017-07-12 14:39:47 UTC
Permalink
Raw Message
Post by m***@gmail.com
Post by Christopher
#include <stdio.h>
#include <math.h>
void getnum ()
{
int num;
char again;
printf ("Enter an integer to be squared: ");
scanf ("%d", &num );
printf ("%d Squared is %d\n", num, sqr (num) );
printf ("Square another number? Y or N: ");
scanf ("%1s", &again);
if ( (again == 'Y') || (again == 'y') ) getnum();
else return;
}
Can I ask if anyone believes scanf() is useful for interactive use,
or does the CLC FAQ Q12.20 <http://c-faq.com/stdio/scanfprobs.html>
still apply?
scanf()'s great if you can guarantee your input is always well-behaved.
Which means it's a lousy choice for interactive input.

Specific example - suppose you're reading an integer input for processing
using

if ( scanf( "%d", &x ) == 1 )
// do something with x

and you type in something like "1e3". scanf() will read, convert, and
assign 1 to x, and return 1 indicating a successful read, leaving "e3"
in the input stream to foul up the next read. Ideally you'd like to
reject the whole input as bad, but you don't *realize* it's bad until
after you've already partially consumed it. You can mitigate against it
a bit with something like

scanf( "%d%c", &x, &follow );

and make sure follow is whitespace, but then things still get complicated.
It's just easier to read everything as text with fgets() and then parse
the input yourself.
James R. Kuyper
2017-07-12 14:56:02 UTC
Permalink
Raw Message
Post by m***@gmail.com
Post by Christopher
#include <stdio.h>
#include <math.h>
void getnum ()
{
int num;
char again;
printf ("Enter an integer to be squared: ");
scanf ("%d", &num );
printf ("%d Squared is %d\n", num, sqr (num) );
printf ("Square another number? Y or N: ");
scanf ("%1s", &again);
if ( (again == 'Y') || (again == 'y') ) getnum();
else return;
}
Can I ask if anyone believes scanf() is useful for interactive use,
or does the CLC FAQ Q12.20 <http://c-faq.com/stdio/scanfprobs.html>
still apply?
The *scanf() family's biggest problem, in my opinion, is not even
mentioned on that page: the behavior is undefined when reading an
arithmetic value if given a string representing a number that cannot be
represented using the specified type. C99 introduced the strto*() family
of functions which are harder to use than *scanf(), but only because
they provide better error reporting abilities - which includes
responding to this particular kind of error by reporting it rather than
by having undefined behavior. I try to use the strto*() family whenever
relevant, but it's hard to break a decades-long habit of using the
*scanf() family, despite that problem.

That page says that it's criticisms don't apply to fscanf() or sscanf().
I normally use fgets()/sscanf() rather than scanf(), which nicely avoids
all three of the problems mentioned in the first sentence.

It mentions that, with the %s specifier, "it's hard to guarantee that
the receiving buffer won't overflow". It's not that hard, just use the
field width specifier.
Malcolm McLean
2017-07-12 14:59:53 UTC
Permalink
Raw Message
Post by James R. Kuyper
It mentions that, with the %s specifier, "it's hard to guarantee that
the receiving buffer won't overflow". It's not that hard, just use the
field width specifier.
The problem is you must still detect and take appropriate action if the field
overflows. Otherwise you merely replace undefined behaviour with controlled
flight into terrain.
Keith Thompson
2017-07-12 16:23:41 UTC
Permalink
Raw Message
"James R. Kuyper" <***@verizon.net> writes:
[...]
Post by James R. Kuyper
The *scanf() family's biggest problem, in my opinion, is not even
mentioned on that page: the behavior is undefined when reading an
arithmetic value if given a string representing a number that cannot be
represented using the specified type.
Agreed.
Post by James R. Kuyper
C99 introduced the strto*() family
of functions which are harder to use than *scanf(), but only because
they provide better error reporting abilities - which includes
responding to this particular kind of error by reporting it rather than
by having undefined behavior.
strtod(), strtol(), and strtoul() were introduced in C89/C90.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
James R. Kuyper
2017-07-12 16:41:52 UTC
Permalink
Raw Message
Post by Keith Thompson
[...]
Post by James R. Kuyper
The *scanf() family's biggest problem, in my opinion, is not even
mentioned on that page: the behavior is undefined when reading an
arithmetic value if given a string representing a number that cannot be
represented using the specified type.
Agreed.
Post by James R. Kuyper
C99 introduced the strto*() family
of functions which are harder to use than *scanf(), but only because
they provide better error reporting abilities - which includes
responding to this particular kind of error by reporting it rather than
by having undefined behavior.
strtod(), strtol(), and strtoul() were introduced in C89/C90.
You're right, it was only strtof(), strtold(), strtoll(), strtoull(),
strtoimax() and strtoumax() that were introduced in C99. I'm not sure I
was ever aware of the existence of the other functions until I learned
about C99, which would explain my confusion about when they were introduced.
Loading...