-2

I want to get a string of numbers up to 50(i.e. the limit on characters is 50) and validate them. For example - 123456789 is valid but 123sadfd456789 is not.

I could only figure out a way to get integer numbers through char.

Here's the code:

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

int conToInteger(int n){
    char ch[50];
    printf("Enter a string: ");
    gets(ch);
    n=atoi(ch);
    printf("Answer is: %d",n);
}

int main(){
  int n;
  conToInteger(n);
  return 0; 
}

Can anybody help me out?? Thanks.

  • Is `1234567890123456789012345678901234567890` valid? (It is less than 50 characters, but the value won't fit in typical `int`, whose maximum value is `2,147,483,647 = 3**31 - 1`) – MikeCAT Jul 08 '21 at 13:55
  • https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used – Retired Ninja Jul 08 '21 at 13:56
  • 3
    To begin with, do not use `gets()`, which has unavoidable risk of buffer overrun, deprecated in C99 and removed from C11. Then, allocate enough elements. `char ch[50];` is too short to read 50-character string because there are no room to store the terminating null-character. – MikeCAT Jul 08 '21 at 13:56
  • @MikeCAT No. It isn't I think long int will solve it won't it? – Advait Dandekar Jul 08 '21 at 13:56
  • What do you mean by "solve"? – MikeCAT Jul 08 '21 at 13:57
  • 1
    @AdvaitDandekar Changing the size of the underlying data type cannot possibly solve the issue. No matter what primitive data type you choose, there will be a string that represents a value that cannot be represented by that data type. – William Pursell Jul 08 '21 at 13:58
  • The typical solution to your problem is to use `strtol` or `strtoul` – William Pursell Jul 08 '21 at 13:59
  • 2
    @AdvaitDandekar by the way, why are you passing `n` to the function`conToInteger`? Moreover, `conToInteger` doesn't return anything, so it should be `void`. – JASLP doesn't support the IES Jul 08 '21 at 13:59
  • @MikeCAT By solve I meant would it accept the `1234567890123456789012345678901234567890`. After your comment on `gets()`, I have made the following changes: `#include` `#include` `#include` `int conToInteger(int n){` `char ch[51];` `printf("Enter a string: ");` `scanf("%s",ch);` `n=atoi(ch);` `printf("Answer is: %d",n);` }` `int main(){` `int n;` `conToInteger(n);` `return 0;` }` – Advait Dandekar Jul 08 '21 at 14:01
  • 1
    @AdvaitDandekar use `scanf("%50s",ch);` instead of `scanf("%s",ch);`. – JASLP doesn't support the IES Jul 08 '21 at 14:01
  • 3
    Do you actually want to convert the string to a number? Your question title makes it sound like you just want to verify if all characters input form a valid number, in which case you can keep your input as a string and use [`isdigit`](https://linux.die.net/man/3/isdigit). If you need support for actual huge numbers that don't fit into the primitive types you'll need to use 3rd party library support or roll your own. – yano Jul 08 '21 at 14:02
  • 3
    `scanf("%s",ch);` is as danger as `gets(ch)`. You should specify the maximum length like `scanf("%50s",ch);` Using `char ch[52];` and `scanf("%51s", ch);` may be better for checking if the input exceeds the limit. – MikeCAT Jul 08 '21 at 14:02
  • Thank you to all of you for helping me out. Since I am a beginner and don't know much about C, I did not understand all the comments. But based on a few comments that I understood, I'll be trying to solve this problem. Thanks again! I'll keep you guys updated. Can I comment even if I close this Question for answers? Please let me know. – Advait Dandekar Jul 08 '21 at 14:13
  • 1
    The techniques to do this are covered in an introductory C course. There are several concepts involved, including using pointers, loops, control statements, expressions, character encodings, and library routines for I/O and character classification. They ought to be learned by reading and working through a C primer or course and not by asking Stack Overflow questions. – Eric Postpischil Jul 08 '21 at 14:26

3 Answers3

3

If all you care about is validating that an arbitrarily long sequence of characters contains only decimal digits, then chux's answer is the right one.

However, based on your code, it looks like you don't just want to validate the string, you want to convert it to the corresponding integer value and save it. If that's the case, 50 digits is way beyond what you can store in any of the standard integer types1; you'd have to use a multi-precision library like GMP. The best you can do with native types is unsigned long long, which on my platform can support values with up to 20 decimal digits (ULLONG_MAX == 18446744073709551615).

Instead of using atoi, you can use something from the strto* family of functions. The neat thing about these functions is you can pass a pointer argument that will point to the first character in the string that wasn't converted - if that character isn't whitespace or the 0 terminator, then you know the input string isn't valid.

In this case we'll use strtoll, which converts strings to long long:

#define LLONG_DIGITS 19 // set this for whatever your platform supports;
                        // mine supports up to 19 for long long

char buf[LLONG_DIGITS+3] = {0}; // digits plus sign, newline, and terminator
long long val = 0;

if ( fgets( buf, sizeof buf, stdin ) )
{
  /**
   * Step 1.  Check for a newline character.  If one isn't present,
   *          then the input was too long for the buffer.  Reject
   *          the input and clear out the input stream.
   */
  char *newline = strchr( buf, '\n' );
  if ( !newline )
  {
    fputs( "Input too long, rejecting\n", stderr );
    while ( getchar() != '\n' )
      ; // empty loop
  }
  else
  {
    /**
     * Step 2. Replace newline with terminator
     */
    *newline = 0;
    char *check;

    /**
     * Step 3.  Use strtoll to convert the string to a long long.
     * check will point to the first character in the string
     * that was *not* converted - if this character isn't
     * whitespace or the string terminator, then the input
     * was not a valid integer string
     */
    long long tmp = strtoll( buf, &check, 10 );
    if ( check > buf && !isspace( *check ) && *check != 0 )
      fputs( "Input value is empty or contains non-numeric characters!\n", stderr );
    else
      val = tmp;
  }
}
else
{
  fputs( "Error on input\n", stderr );
}

Now, when I say a type can support decimal values up to N digits, that doesn't mean it can support all N-digit values. An 8 bit byte can represent 256 distinct values, so it can represent some 3-digit decimals, but it can't represent things like 999. LLONG_MAX is 9223372036854775807, so if you input a value higher than that you will have signed integer overflow, which invokes undefined behavior.


  1. 50 decimal digits corresponds to at least 160 bits; I'm not aware of any system with a native integer type that large. An int is only guaranteed to store values in the range [-32767..32767], which is at most 5 digits. Most platforms use 32-bit int which can store values in the range [-2147483648..2147483647] which is 10 digits. A 64-bit `unsigned long long` can store a value up to 18446744073709551615 which is 21 digits. No native type, not even long double, is going to be able to handle 50 digits.
John Bode
  • 119,563
  • 19
  • 122
  • 198
2

Read the line of user input as a string with fgets(). Use an ample sized buffer. Suggest 2x expected input size.

#define LENGTH_GOOD_MAX 50
#define BUF_N (LENGTH_GOOD_MAX * 2 + 2)  // + 2 for the \n \0
char buf[BUF_N];
if (fgets(buf, sizeof buf, stdin)) {

Then test the characters with isdigit() from <ctype.h>.

  unsigned char *s = buf;  // Change to unsigned type for correct `isdigit()` usage.
  while (isdigit(*s)) {
    s++;
  }

  if (s == buf || s-buf > LENGTH_GOOD_MAX) puts("Too short or too long");
  else if (*s != '\0' && *s != '\n') puts("Not numeric");
  else puts("Just right!");
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
2

You could use getchar() in a loop, but check @chux answer for best practices.

#include <stdio.h>
#include <ctype.h>

int main() {

    char s[50] = { 0 };

    for(int i = 0, c; i < 49 && isdigit(c = getchar()); s[i++] = c);

    printf("%s", s);

    return 0;
}
anotherOne
  • 1,513
  • 11
  • 20