0

I have a triangle program in c

#include <stdio.h>

// A function which decides the type of the triangle and prints it
void checkTriangle(int s1, int s2,int s3)
{
    // Check the values whether it is triangle or not.
    if ((s1 + s2 > s3 && s1 +  s3 > s2 && s2 + s3 > s1) && (s1 > 0 && s2 > 0 && s3 > 0))
    {
        // Deciding type of triangle according to given input.
        if (s1 == s2 && s2 == s3)
            printf("EQUILATERAL TRIANGLE");
        else if (s1 == s2 || s2 == s3 || s1 == s3)
            printf("ISOSCELES TRIANGLE\n");
        else
            printf("SCALENE TRIANGLE \n");
    }
    else
        printf("\nTriangle could not be formed.");
}

int main(void)
{
    // Initializing variables
    int a,b,c;

    // Getting input from user
    printf("Please enter the sides of triangle");

    printf("\nPlease enter side 1:");
    scanf("%d",&a);

    printf("Please enter side 2:");
    scanf("%d",&b);

    printf("Please enter side 3:");
    scanf("%d",&c);

    // Calling function in order to print type of the triangle.
    checkTriangle(a,b,c);
}

When the input is:

7b

it gives an error, which is what I want, but when I entered the data like this:

7
7
7b 

it ignores 'b' and take 7 as an integer — but why? How can I prevent this?

What I want to do is give an error also for

7
7
7b
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
abc
  • 516
  • 1
  • 5
  • 9

5 Answers5

4

If you want to be able to detect an error with the user's input, such as a line not being a valid decimal integer, then you could do the following:

  • Read the input into a buffer using fgets(buffer, size, stdin)
  • Use strtoul(buffer, &endptr, 10) to parse the buffer as a decimal integer (base 10), where endptr is a char*
  • endptr will point to the first invalid character in buffer, ie. the character after the last one which was successfully parsed
  • Now if *endptr == '\0', ie. endptr points to the end of buffer, the whole string was parsed as a valid decimal integer
AusCBloke
  • 18,014
  • 6
  • 40
  • 44
  • +1: The general outline is certainly correct. Note that `fgets()` keeps the newline, so unless you strip it, `endptr` is likely to point to the newline (or perhaps an innocent space after the number). The return values from `strtoul()` or `strtol()` should be analyzed to ensure that it is a valid `int` (for systems where `sizeof(int) < sizeof(long)`, in particular. If you use `strtoul()`, you have to worry about values with the high order bit set; if you use `strtol()`, you have to worry about negative values (which also have the high order bit set, of course). See my answer. Note `errno` too. – Jonathan Leffler Oct 15 '12 at 05:39
  • @JonathanLeffler: Yeah I should've mentioned that `fgets` stores the newline. And yeah the OP should interchange `strtoul` with `strtol` depending on whether he wants negative values to be included. – AusCBloke Oct 15 '12 at 06:01
1

If you really want each number on a separate line of input, and for the whole of the line to be valid number or space, then you probably need to forget scanf() and family and use fgets() and strtol() instead.

#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>

static int read_side(void)
{
    char buffer[4096];
    if (fgets(buffer, sizeof(buffer), stdin) == 0)  // EOF
        return -1;
    char *end;
    errno = 0;
    long result = strtol(buffer, &end, 10);
    if (result < 0 || errno != 0) // Neither errors nor negative numbers are allowed
        return -1;
    if (end == buffer)     // Nothing was convertible
        return -1;
    while (isspace(*end))
        end++;
    if (*end != '\0')      // Non-spaces after the last digit
        return -1;
    if (result > INT_MAX)  // Result too big for `int`
        return -1;
    return result;
}

(If you needed to accept any valid int value but distinguish errors, then you'd pass in a pointer to the function and return -1 on error or 0 on success, and assign the safe result to the pointer.)

Yes, it really is that fiddly to do the job properly. And yes, analyzing the result of strtol() is as tricky as that; you do have to be very careful. (And there's an outside chance I've forgotten to check for a detectable error condition.) And no, I don't think you can do the equivalent job with scanf() et al; in particular, the behaviour on overflow with scanf() is undefined.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

%d accepts only integer. try with %x in scanf() for hex-decimal input.

Better you can get input as string then check using isnumeric() else use scanf("%[^\n]s", word) like @mou suggested.

Jeyaram
  • 9,158
  • 7
  • 41
  • 63
0

you shouldn't use scanf or do scanf("%[^\n]s", word); Or use someting like get() also put d or x at the end of my example not s for string :P

Arnaud Aliès
  • 1,079
  • 13
  • 26
  • is this a bug or a know issue .d – abc Oct 15 '12 at 05:20
  • This is not really a bug I think they wanted that I don't really know but you must know that to go foward in C – Arnaud Aliès Oct 15 '12 at 05:32
  • Note that a scan-set conversion specification ends with the close square bracket. The `s` in your example is not wanted, though it is undetectable with a single `scanf()` call whether the `s` was matched or not (with the given format string). `get()` is not a standard function; if you're thinking of `gets()`, don't (it is deadly); if you're thinking of `fgets()`, you're more nearly on track. Putting `d` or `x` at the end of your string would be as bad as the `s`. – Jonathan Leffler Oct 15 '12 at 05:59
0

Read the input into a string buffer. Parse the string to extract numeric values be of any kind one by one.

जलजनक
  • 3,072
  • 2
  • 24
  • 30