Alternative Solution to repeated digit worked example in chapter 8, KNK C Programming (Arrays & Boolean Values)

Viewed 64

I am dealing with my attempted solution to a worked through problem of Chapter 8 in KNK's C Programming, A Modern Approach. I understand the answer they have proposed but would like to know why my one is wrong. I am stumped...

I am trying to write a program using arrays and the getchar() function to read a positive number and check whether it has repeated digits.

My program uses Boolean values to keep track of which digits appear in a number. The array named digit_seen is indexed from 0 to 9 to correspond to the 10 possible digits. Initially every element of the array is false.

I would like to write a program which, when given a number n, examines n's digits one at a time, from left to right. Storing each examined digit into the digit variable and then using it as an index into digit_seen. If digit_seen[digit] is true then digit appears at least twice in n. However if digit_seen[digit] is false then digit has not been seen before and the program will then update digit_seen[digit] to true and keep on going.

Here is my imperfect code:

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

int main()
{
  bool digit_seen[10] = {false};
  int digit;
  printf("Enter a positive number: ");

  while((digit = getchar()) != EOF) {
    if(digit_seen[digit])
      break;

     digit_seen[digit] = true;
  }

  if(digit == EOF)
    printf("No repeated digit\n");
  else
    printf("Repeated digit\n");
}

Let me briefly explain why I (clearly incorrectly) think it should work. Suppose I type in the number 12 (i.e. n=12). Then getchar() takes 1, puts it in digit. Note that 1 != EOF, so the while loop is executed. We also see that digit_seen[digit] is false so the if statement is never executed and now we assign digit_seen[digit] to true (i.e. the number 1 has been 'seen' now).

The exact process is repeated for the next digit 2. Then all the possible digits have been scanned and we get to EOF. So we assign digit = EOF. At this point the while loop is not executed. We go to the if statement following the while loop, see that it is indeed true and print the words "No repeated digit".

Now suppose instead I type in the number 22 instead of 12 (i.e. n=22). By the time we read the 2 digit for the second time digit_seen[digit] is already true, so we break out of the while loop. We then encounter if(digit == EOF) and note that in the case where we are breaking out of the while loop (instead of the argument in the while's parenthesis being false) digit must have an integer value between 0 and 9 respectively. Yet EOF is stored as -1 on the computer. So the if(digit == EOF) is not executed, instead the else clause is executed and we have the program correctly telling us that a "Repeated digit" has been typed.

Can someone please tell me what I am missing here? My output is always just "Repeated digit"? Further I would like to add that this is a worked example that KNK provides a solution for BUT the solution does not involve getchar(). It involves scanf() then uses modulo (%) and divide(/) operations to analyse the number's digits from right to left. I understand their solution but I am not content with understanding their alternative approach and not seeing where I failed. I find it curious they didn't use getchar() as this was my first instinct before looking at their solution. Is there a way to solve the problem using my proposed method, by analysing n's digits as they're typed? Or does it require a different approach like the one in the book?

As a self-taught programmer with no one else to ask these sorts of questions any elucidation would be very generous.

ANSWER:

After having taken your considerations on board I am posting my "alternative answer". One small tweak was all that was needed. I am now extra aware of what getchar() does and the ASCII Table. Not that I had a good reason not to be before. I would urge anyone reading to compare with KNK should be they curious.

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

int main()
{
  bool digit_seen[10] = {false};
  int  digit;
  printf("Enter a positive number: "); 

  while((digit = getchar()) != '\n') {
    digit -= '0';
    if(digit_seen[digit])
      break; 
  
     digit_seen[digit] = true;
  }
    
  if(digit == '\n')
    printf("No repeated digit\n");
  else
    printf("Repeated digit\n");
}
1 Answers

getchar() does not return a digit. It returns a code for a character.

In the code most commonly used for characters in C implementations, ASCII, the codes for the digit characters “0” through “9” are 48 through 57. Then digit_seen[digit] attempts to access the array using an index that is out of bounds of the array. This may result in accessing some part of memory that contains some unrelated value. If that value is non-zero, then digit_seen[digit] evaluates as true, and the break; is executed to leave the loop.

Then digit == EOF is not true, and “Repeated digit” is printed.

First, after getting a character with getchar, test whether it is a digit character using the isdigit function declared in <ctype.h>. If it is a digit character, convert it to a digit (0-9) using digit -= '0';. Then you can use it as an index into the array.

If it is not a digit character, you might ignore it or print a warning to the user. For example, “white space” characters (detected using the isspace function) may be ignored. This includes the new-line character that is generated when the user presses enter or return.

Related