Reputation: 11
Just starting out and working through cs50. I want to:
#include <cs50.h>
#include <stdio.h>
int main(void)
{
long n = 0;
n = get_long("Number: ");
int i = 0;
long cn = n;
while (cn > 0)
{
cn = cn / 10;
i++;
}
if (i != 13 && i != 15 && i != 16)
{
printf("INVALID\n");
}
}
This gets me through steps 1-3, but I cannot figure out how to get step 4 to work. Any help is greatly appreciated.
Upvotes: 1
Views: 250
Reputation: 8354
OP: "I cannot figure out how to get step 4 [repeat] to work"
A: Simply wrap the code to be repeated inside a for()
, a while()
or a do/while()
loop. Perhaps you missed a segment of the course material because loops are parts of the language used in almost every C program.
One has to be careful about making assumptions. The leading digit(s) may be 0, and the number value may not reflect what was entered.
#include <stdio.h>
#include <ctype.h> // for C library function 'isdigit()'
#include "cs50.h"
int main( void ) {
for( ;; ) { // infinite loop to avoid tedium
char *ps = get_string( "Enter a number: " );
int cnt = 0;
while( isdigit( (unsigned char)*ps ) ) {
ps++;
cnt++;
}
// positive logic may be easier for some readers
// MUST also test that user's string entry has been exhausted
if( *ps == '\0' && ( cnt == 13 || cnt == 15 || cnt == 16 ) )
; // all good
else
printf( "INVALID\n" );
}
return 0;
}
Output:
Enter a number: 1234567890123
Enter a number: 123456789012345
Enter a number: 1234567890123456
Enter a number: 12345678901234567
INVALID
Enter a number: 0000000000000
Enter a number: 0001112223334
Enter a number:
Use a "helper function"
An alternative version indicating how to continue processing with valid string of digits.
#include <stdio.h>
#include <ctype.h> // for library function 'isdigit()'
#include "cs50.h"
int isValidLen( char *ps ) { // return 0 for bad, 1 for good
// THIS 'ps' is a local copy.
// Same value, but not the same variable as in main().
int cnt = 0;
while( isdigit( (unsigned char)*ps ) ) {
ps++;
cnt++;
}
return *ps == '\0' && ( cnt == 13 || cnt == 15 || cnt == 16 );
}
int main( void ) {
for( ;; ) {// infinite loop to avoid tedium
char *ps = get_string( "Enter a number: " );
if( !isValidLen( ps ) ) {
printf( "INVALID\n" );
continue; // or something else???
}
// main()'s copy of 'ps' still points to start of the string
/*
* perhaps more processing with validated string
*/
}
return 0;
}
Explore C's (reliable) Standard Library function
Or, one can make use of standard C library functions, instead...
#include <stdio.h>
#include <string.h> // for library function 'strspn()'
#include "cs50.h"
int main( void ) {
for( ;; ) { // infinite loop to avoid tedium
char *ps = get_string( "Enter a number: " );
int cnt = strspn( ps, "0123456789" );
if( ps[ cnt ] == '\0' && ( cnt == 13 || cnt == 15 || cnt == 16 ) )
; // all good
else
printf( "INVALID\n" );
}
return 0;
}
Knowing (now) that this CS50 assignment deals ONLY with 3 brands of credit cards, and that none of those brands' numbers begin with '0'
, using the provided library's get_long()
is reasonable, but ONLY if the data is stored in a long long
variable:
long long ccn = get_long( "Enter a number: " );
// Use a copy to "erase" digits from right-to-left until nothing remains
int cnt = 0;
for( long long cpy = ccn; cpy; cpy /= 10 )
cnt++;
if( cnt == 13 || cnt == 15 || cnt == 16 )
; // all good
else
printf( "INVALID\n" );
Left as an exercise for the beginner:
get_long()
return negative numbers? If so, should the program detect and reject those?octal
or hexadecimal
notation. Does the CS50 get_long()
only accept decimal
digits?decimal
value that can be stored in C's different "integer" datatypes (eg: char
, short
, int
,... both as signed
and unsigned
values.) Hint: Some compilers treat long
as only 32 bits. The maximum value of their unsigned long
is just over 4 billion (i.e. not big enough to store 13, 15 or 16 decimal digit numbers.)Upvotes: 6
Reputation: 39
Put the specific part in a while(1) loop. So here is the solution:
#include <cs50.h>
#include <stdio.h>
int main(void)
{
long n = 0;
int i = 0;
long cn;
while(1)
{
i=0;
n = get_long("Number: ");
cn = n;
while (cn > 0)
{
cn = cn / 10;
i++;
}
if (i != 13 && i != 15 && i != 16)
{
printf("INVALID\n");
}
else{
break;
}
}
}
Upvotes: 0
Reputation: 84579
Even simpler, loop continaully and use the snprintf (NULL, 0, ...)
trick to determine the number of digits. Break only if the number of digits is correct.
From man 3 snprintf
The functions
snprintf()
andvsnprintf()
do not write more than size bytes (including the terminating null byte ('\0'
)). If the output was truncated due to this limit, then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available.
#include <cs50.h>
#include <stdio.h>
int main(void) {
long n = 0;
for (;;) { /* loop continually */
int ndigits = 0;
n = get_long("Number: ");
ndigits = snprintf (NULL, 0, "%ld", n);
if (n < 0) { /* subtract 1 for '-' sign */
ndigits -= 1;
}
if (ndigits == 13 || ndigits == 15 || ndigits == 16) {
break; /* break loop only if ndigits correct */
}
puts ("INVALID");
}
}
(note: technically '-'
isn't a digit, so you need to account for negative values)
Example Use/Output
./bin/ndigitstest
Number: 1
INVALID
Number: 123456789012
INVALID
Number: 1234567890123
Or, with negative values,
$ ./bin/ndigitstest
Number: -123456789012
INVALID
Number: -1234567890123
and so on...
Upvotes: 3
Reputation: 2134
Simplest way is that you give a flag to check input is invalid or not. For example,
int invalid = 1;
long n = 0;
while (invalid) {
n = get_long("Number: ");
int i = 0;
long cn = n;
while (cn > 0)
{
cn = cn / 10;
i++;
}
if (i != 13 && i != 15 && i != 16)
{
printf("INVALID\n");
} else {
invalid = 0;
}
}
Upvotes: 2