int i, f;
f = scanf("%d", &i);
When I enter input as 3333333333333333333333 (greater than the capacity of int). Shouldn't the value of f be 0?
int i, f;
f = scanf("%d", &i);
When I enter input as 3333333333333333333333 (greater than the capacity of int). Shouldn't the value of f be 0?
No, it can't be detected that way.
The below is not a portable solution, but it works in gcc12.1, clang14.0 and msvc19.32. It may stop working in later releases.
You need to set errno = 0; first and then check it for range errors:
#include <errno.h>
// ...
    errno = 0;
    f = scanf("%d",&i);
    if(f == 1 && errno != ERANGE) {
        // success
    }
For portability, read this from an early draft of the C2x standard:
Unless assignment suppression was indicated by a
*, the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a conversion result. If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
A better (as in portable) option to detect this would be to read into a char[] buffer first and then use strtol() to convert it to a number. From the same standard draft:
The
strtol,strtoll,strtoul, andstrtoullfunctions return the converted value, if any. If no conversion could be performed, zero is returned. If the correct value is outside the range of representable values,LONG_MIN,LONG_MAX,LLONG_MIN,LLONG_MAX,ULONG_MAX, orULLONG_MAXis returned (according to the return type and sign of the value, if any), and the value of the macroERANGEis stored inerrno.
Here's a demonstrative program using strtol() (which converts to long):
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
// A wrapper around `strtol` to convert to `int`
int strtoi(const char *str, char **str_end, int base) {
    int errno_save = errno;
    errno = 0; // clear it from any previous error (must be done)
    long result = strtol(str, str_end, base);
    if(errno == ERANGE) return result == LONG_MAX ? INT_MAX : INT_MIN;
    if(result > INT_MAX || result < INT_MIN) {
        errno = ERANGE;
        return result > INT_MAX ? INT_MAX : INT_MIN;
    }
    // success or no conversion could be performed
    errno = errno_save;  // restore errno
    return (int)result;
}
#define Size(x) (sizeof (x) / sizeof *(x))
int main(void) {
    const char* strings[] = {
        "3333333333333333333333 foo",
        "2147483647 will probably succeed",
        "2147483648 will probably fail",
        "32767 guaranteed success",
        "32767xyz",
        "xyz",
        "123",
        ""
    };
    char *end; // this will point at where the conversion ended in the string
    for(unsigned si = 0; si < Size(strings); ++si) {
        printf("testing \"%s\"\n", strings[si]);
        errno = 0; // clear it from any previous error (must be done)
        int result = strtoi(strings[si], &end, 10);
        if(errno == ERANGE) {
            perror(" to big for an int");
        } else if(strings[si] == end) {
            fprintf(stderr, " no conversion could be done\n");
        } else if(*end != '\0' && !isspace((unsigned char)*end)) {
            fprintf(stderr, " conversion ok,"
                            " but followed by a rouge character\n");
        } else {
            printf(" success: %d rest=[%s]\n", result, end);
        }
    }
}
Possible output:
testing "3333333333333333333333 foo"
 to big for an int: Numerical result out of range
testing "2147483647 will probably succeed"
 success: 2147483647 rest=[ will probably succeed]
testing "2147483648 will probably fail"
 to big for an int: Numerical result out of range
testing "32767 guaranteed success"
 success: 32767 rest=[ guaranteed success]
testing "32767xyz"
 conversion ok, but followed by a rouge character
testing "xyz"
 no conversion could be done
testing "123"
 success: 123 rest=[]
testing ""
 no conversion could be done
 
    
    Shouldnt the value of f be 0?
With standard C, no.  With scanf("%d",&i), on int overflow, the result is undefined.
With scanf() in Unix (of which there are variations), I find no prevention of undefined behavior with overflow.
Best to ditch (not use) scanf() and use fgets() for all user input.
Code could try a textual width limit and a wider type:
intmax_t bigd;
//          vv --- width limit
if (scanf("%18jd",&bigd) == 1 && bigd >= INT_MIN && bigd <= INT_MAX) {
  d = (int) bigd;
} else {
  puts("Oops");
}
Yet that has trouble on novel implementations where int is as wide as intmax_t.
scanf() returns 0 when no int textual input found.
A key design element missing from OP's questions is what should happen to user input that exceeds the int range?  Stop reading after the first `"333333333"?
What is best, depends on how OP wants to handle, in detail, error conditions - something not yet stated.
 
    
    scanf("%d", &i) does not detect overflow, worse even, scanf() has undefined behavior if the number exceeds the range of the destination type: depending on the implementation, the value of i could be -434809515, -1, 0, INT_MAX or any value including a trap value with or without some undesirable side effects.
The proper way to check the input is to read it as a line in an array of char and to parse it with strtol():
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
    char input[120];
    char ch;
    char *p;    
    long x;
    int i;
    printf("Enter an integer: ");
    if (!fgets(input, sizeof input, stdin)) {
        fprintf(stderr, "missing input\n");
        return 1;
    }
    errno = 0;
    x = strtol(input, &p, 0);
    if (p == input) {
        fprintf(stderr, "invalid input: %s", input);
        return 1;
    }
    if (x < INT_MIN || x > INT_MAX) {
        errno = ERANGE;
    }
    if (errno == ERANGE) {
        fprintf(stderr, "number too large: %s", input);
        return 1;
    }
    if (sscanf(p, " %c", &ch) == 1) {
        fprintf(stderr, "trailing characters present: %s", input);
        return 1;
    }
    i = (int)x;  // we know `x` is in the proper range for this conversion
    printf("The number is %d\n", i); 
    return 0;
}
You can encapsulate these tests in a getint() function:
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
/* read an int from a standard stream:
   always update *res with the value read
   return 0 on success
   return -1 on out of range, value is clamped to INT_MIN or INT_MAX
   return -2 on non a number, value is 0
   only read characters as needed, like scanf
*/
int getint(FILE *fp, int *res) {
    int n = 0;
    int ret = 0;
    int c;
    while (isspace(c = getc(fp)))
        continue;
    if (c == '-') {
        c = getc(fp);
        if (!isdigit(c)) {
            ret = -2;
        } else {
            while (isdigit(c)) {
                int digit = '0' - c;
                if (n > INT_MIN / 10 || (n == INT_MIN / 10 && digit >= INT_MIN % 10)) {
                    n = n * 10 + digit;
                } else {
                    n = INT_MIN;
                    ret = -1;
                }
                c = getc(fp);
            }
        }
    } else {
        if (c == '+')
            c = getc(fp);
        if (!isdigit(c)) {
            ret = -2;
        } else {
            while (isdigit(c)) {
                int digit = c - '0';
                if (n < INT_MAX / 10 || (n == INT_MAX / 10 && digit <= INT_MAX % 10)) {
                    n = n * 10 + digit;
                } else {
                    n = INT_MAX;
                    ret = -1;
                }
                c = getc(fp);
            }
        }
    }
    if (c != EOF)
        ungetc(c, fp);
    *res = n;
    return ret;
}
int main() {
    int i, res;
    printf("Enter an integer: ");
    res = getint(stdin, &i);
    switch (res) {
    case 0:
        printf("The number is %d.", i);
        break;
    case -1:
        printf("Number out of range: %d, res=%d.\n", i, res);
        break;
    default:
        printf("Invalid or missing input, res=%d.\n", res);
        break;
    }
    return 0;
}
