1

I have a simple question. I'm learning linked lists and my data type is int. I'm wondering how can validate it where it doesn't allow to take in alphabetic input.

When I do it the way I have it, it doesn't print the message. So how can I properly do something like that?

My code:

node * createLinkedList()
{
    node * head = NULL;
    node * temp = NULL;
    node * p = NULL;
    
    while ((scanf("%d", &(temp->data))) !=EOF )
    {
        if ((temp->data>= 'a' && temp->data<= 'z') || (temp->data>= 'A' && temp->data<= 'Z')){
            fprintf(stderr,"ERROR alph is not allowed");
        }

    }
}
3
  • fprintf prints to a file, so you need to tell it which file. Did you perhaps mean printf(no leading f ? Commented Oct 8, 2020 at 10:00
  • @MSalters it wouldnt matter if changed it to printf it would not even go into the if statement Commented Oct 8, 2020 at 10:03
  • Well you access the data member of temp, which is NULL... can you please give a more precise description of what output you actually get (actual behavior) in addition to the desired behavior? Commented Oct 8, 2020 at 10:05

2 Answers 2

3

The %d scanf specifier is to read int, if an alphabetic character is inputed, scanf will fail to read it and temp->data will retain its previous value.

A better condition for your cycle would be:

while (scanf("%d", &(temp->data)) == 0) //while input is not correctly parsed...
{
    fprintf(stderr, "ERROR alph is not allowed\n"); //...print error message...
    int c;
    while((c = getchar()) != '\n' && c != EOF) {} //...and clear stdin
}

This makes it so that if the input is not parseable as an int a new input will be asked until a good value is inputed.

Note that, as @JohnBode pointed out, an input starting with a digit but that contains alphabetic characters will be parsed until the character is found, i.e. 123abc4 will parse 123. If you want to avoid this, using a combination of fgets and strtoll is a more robust method and will allow you to validate inputs like the above.

If it's something that you want to allow to happen, and continue using scanf, don't forget you need to then clear stdin which will have the characters that were not parsed, (in the exemplified case abc4\n), before asking for new inputs, @JohnBode's answer covers these matters perfectly, check that out.


There is another problem in the code you show, your temp pointer is NULL, it is not able to store any data. Either declare it as an object or allocate memory for it. As it is, it leads to undefined behavior.


Sign up to request clarification or add additional context in comments.

5 Comments

@DavidRanieri, too late, OP added stderr.
fprintf(stderr,"ERROR"); what I meant just forgot to add that
if ((temp->data) == 0){ fprintf(stderr,"ERROR"); return 0; } and it worked thank you!
This will not catch bad input like "12w45" - it will successfully convert and assign "12" but leave "w45" in the input stream to foul up the next read.
@JohnBode, disclaimer added.
2

If you need to validate integer input, then you can't rely on %d alone. It won't catch and reject bad entries like "12w45" - it will successfully convert and assign "12" but will leave "w45" in the input stream to foul up the next read.

There are two ways around this. One is to scan and check the character immediately following the input, like so:

int tmp;
char dummy = 0;

int r;

if ( (r = scanf( "%d%c", &tmp, &dummy )) == 2 )
{
  // if following character is whitespace, then this is a valid numeric input
  if ( isspace( dummy ) )
    temp->data = tmp;
  else
  {
    fprintf( stderr, "non-numeric character '%c' (%d) detected in input\n",
      isprint( dummy ) ? dummy : '.', dummy );

    fprintf( stderr, "clearing out input stream\n" );
    while ( getchar() != '\n' )
      ; // empty loop
  }
}
else if ( r == 1 ) // only thing following numeric input was EOF
{
  temp->data = tmp;
}
else if ( r == 0 )
{
  fprintf( stderr, "Non-numeric input detected, clearing input stream\n" );
  while ( getchar() != '\n' )
    ; // empty loop
}
else
{
  fprintf( stderr, "EOF or error detected on input\n" );
}

A better way to do this in my opinion is to avoid using scanf entirely - read your input as a string using fgets, then use strtol or strtod to perform the conversion:

char buffer[13]; // 11 decimal digits plus sign plus string terminator;
                 // should be able to store the decimal string representation
                 // of any 32-bit integer;

if ( fgets( buffer, sizeof buffer, stdin ) )
{
  // chk will point to the first character *not* converted by strtol
  char *chk;
  int tmp = (int) strtol( buffer, &chk, 10 );
  if ( !isspace( *chk ) && *chk != 0 )
  {
    fprintf( stderr, "Detected non-numeric character '%c' (%d) in input\n",
      isprint( *chk ) ? *chk : '.', *chk );
  }
  else
  {
    temp->data = tmp;
  }
}
else
{
  fprintf( stderr, "EOF or error on input\n" );
}

When you're doing this kind of validation, use a temporary to store the converted value until you've finished; do not update your actual target until you know the value is good.

2 Comments

Just to be thorough you could add errno check for out of range conversion.
@anastaciu: true. May do that later.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.