How subtle is that? (* NEW *)
People reading this Q&A represent the full spectrum of experience, from novices to battle-hardened professionals. Perhaps not-unnoticed, but, oddly, so far unreported is:
// if ( scanf("%" PRIu64, &n) != 1 ) {
if ( scanf("%" SCNu64, &n) != 1 ) {
The almost invisible, likely inconsequential this time, use of the wrong macro is typical of one class of coding bugs:
How can something that looks so right be so wrong?
Guidelines and support tools (like the descendants of lint
) do their best to help. Heed them, but always recognised C will allow you to write foolish code.
"With great power comes great responsibility"
Review
OP is off to a pretty good start on their C adventure.
Very minor layout (whitespace) inconsistencies, not worthy of mention.
As noted in comments below the question, n = -1;
is ill-advised.
The negative constant with the unsigned
variable creates unnecessary tension.
My first response (in a comment) suggests omitting this statement completely.
The considered, expert response regarding this, from @Chux, shows that using n = 0;
would ensure that execution would always be predictable.
Incantations
A while()
loop and a large (peevish) comment have been used to read and discard 'rubbish' characters that a user may have typed on the same line.
Suggested:
if( scanf( "%" PRIu64 "%*[^\n]", &n ) != 1 ) {
would similarly dispose of possible trailing rubbish, LEAVING only the 'whitespace' character LF
(linefeed) in the input buffer. In MANY (but not ALL) cases, this residual whitespace will not cause problems for subsequent scanf()
invocations. As the OP's experiences with scanf()
broaden and diversify, they are advised to return to the documentation often in order to solidify and consolidate their concepts of its behaviour.
Consider using this format specification (incantation called a "scanset") with scanf()
instead of an explicit while()
and getchar()
...
Mixed use of scanf()
with C's other input functions (eg: getchar()
, and especially fgets()
) can be ill-advised.
One other thing:
while ( getchar() != '\n' ) {} /* "clear" stdin */
takes no account of the possibility that EOF
is returned (until forever) by getchar()
. There are a number of situations where stdin
will not be providing a LF
. (Things are never as simple as they first appear!)
Personality: I enjoy discovering uplifting 'Easter Eggs' of authors' personalities in embedded comments (and frequently try my best to be 'unbusinesslike', too.) Consider your reader(s). If straying from 'business', make sure your comment seeks to lighten the reader's day, not darken it...
Code to the problem statement
... the algorithm multiplies it by three and adds one.
n = ( 3 * n ) + 1; // parentheses superfluous
The compiler will likely emit the same machine code for this version.
Seemingly trivial here, 'direct mapping' between a mathematical formula and its expression in a programming language becomes more important when those formula are more complex.
// comments
/* This (block) style of commenting works, but is considered 'old-fashioned'. */
//
// You are free to use whichever style you prefer in your own programs.
// When working with code in a group, stick to one style agreed to by the majority.
//
Tip:
A recent project was peppered with several tracing (aka "print debugging") printf()
statements similar to:
...
/**/ printf( "yadda yadda %d\n", varX );
...
The /**/
at the margin marked these lines as distinct from the surrounding code.
While there are various (proper) ways to facilitate dis-/en-abling these helpful statements, it was quick-and-dirty to simply add/remove one '/'
from the front of these lines:
//**/ printf( "yadda yadda %d\n", varX ); // entire line now 'disabled'
'Print debugging' (to trace the flow or intermediary results of working code) is another 'tool for the toolbox' that may be useful to you someday.
Been there; done that
Coding a tool to play with the Collatz Conjecture is a valid exercise. Its precepts are simple, and its behaviour 'curious' to observe. (It has been empirically tested using 'seeds' up to some very large number of digits without encountering any dragons or unicorns. An amateur is unlikely to have the compute power available to push the proven boundary much higher.)
Noteworthy is the 4 -> 2 -> 1 'loop' at its end. Spot the
22 -> 21 -> 20 happening?
Rather than using base-10 (decimal) to report the sequence of calculated values, octal output provides a possibility to recognise patterns, especially in the lower digits of the results.
The OP might allow the user enter the 'seed' as either decimal ("255"
) or octal ("0377"
).
Make this a learning experience.
n *= 3;
may overflow? \$\endgroup\$n = -1;
Unsigned integers don't like being set-to or tested-for being negative... Might be best to just leave it to its initial value0
... (Kudos for initialising when declaring!) Keep at it... \$\endgroup\$scanf("%" PRIu64, &n)
failed due to a rare input error ofstdin
(e.g. "12 <keyboard communication failure>), IMO, the spec is squishy enough to leaven
is an indeterminate state. Only a pedantic concern. \$\endgroup\$