How to scanf only integer and repeat reading if the user enters non-numeric characters?

Use scanf("%d",&rows) instead of scanf("%s",input)

This allow you to get direcly the integer value from stdin without need to convert to int.

If the user enter a string containing a non numeric characters then you have to clean your stdin before the next scanf("%d",&rows).

your code could look like this:

#include <stdio.h>  
#include <stdlib.h> 

int clean_stdin()
{
    while (getchar()!='\n');
    return 1;
}

int main(void)  
{ 
    int rows =0;  
    char c;
    do
    {  
        printf("\nEnter an integer from 1 to 23: ");

    } while (((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) || rows<1 || rows>23);

    return 0;  
}

Explanation

1)

scanf("%d%c", &rows, &c)

This means expecting from the user input an integer and close to it a non numeric character.

Example1: If the user enter aaddk and then ENTER, the scanf will return 0. Nothing capted

Example2: If the user enter 45 and then ENTER, the scanf will return 2 (2 elements are capted). Here %d is capting 45 and %c is capting \n

Example3: If the user enter 45aaadd and then ENTER, the scanf will return 2 (2 elements are capted). Here %d is capting 45 and %c is capting a

2)

(scanf("%d%c", &rows, &c)!=2 || c!='\n')

In the example1: this condition is TRUE because scanf return 0 (!=2)

In the example2: this condition is FALSE because scanf return 2 and c == '\n'

In the example3: this condition is TRUE because scanf return 2 and c == 'a' (!='\n')

3)

((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin())

clean_stdin() is always TRUE because the function return always 1

In the example1: The (scanf("%d%c", &rows, &c)!=2 || c!='\n') is TRUE so the condition after the && should be checked so the clean_stdin() will be executed and the whole condition is TRUE

In the example2: The (scanf("%d%c", &rows, &c)!=2 || c!='\n') is FALSE so the condition after the && will not checked (because what ever its result is the whole condition will be FALSE ) so the clean_stdin() will not be executed and the whole condition is FALSE

In the example3: The (scanf("%d%c", &rows, &c)!=2 || c!='\n') is TRUE so the condition after the && should be checked so the clean_stdin() will be executed and the whole condition is TRUE

So you can remark that clean_stdin() will be executed only if the user enter a string containing non numeric character.

And this condition ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) will return FALSE only if the user enter an integer and nothing else

And if the condition ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) is FALSE and the integer is between and 1 and 23 then the while loop will break else the while loop will continue


#include <stdio.h>
main()
{
    char str[100];
    int num;
    while(1) {
        printf("Enter a number: ");
        scanf("%[^0-9]%d",str,&num);
        printf("You entered the number %d\n",num);
    }
    return 0;
}

%[^0-9] in scanf() gobbles up all that is not between 0 and 9. Basically it cleans the input stream of non-digits and puts it in str. Well, the length of non-digit sequence is limited to 100. The following %d selects only integers in the input stream and places it in num.