You can read digits (c >= '0' && c <= '9') in a loop, and append them to your integer, i = 10*i + (c - '0'):
Code:
int i, c;
c = getchar();
i = 0;
while (c >= '0' && c <= '9') {
i = 10 * i + (c - '0');
c = getchar();
}
/* c already contains the next character, which is a non-digit.
* i contains the parsed unsigned integer. Overflow is not checked for. */
The digits 0 to 9 are consecutive in all character sets I know of, even those not compatible with ASCII. As long as your compiler reads the code using the same character set as you write it, the above loop approach should always work.
If you want to be extra careful, you can use a helper function, perhaps
Code:
/* Return positive decimal number corresponding to the digit,
* or -1 if c is not a decimal digit. */
int decimal_digit(const int c)
{
switch (c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
default: return -1;
}
}
...
int i, c, d;
c = getchar();
i = 0;
while ((d = decimal_digit(c)) >= 0) {
i = 10 * i + d;
c = getchar();
}
/* c already contains the next character, which is a non-digit.
* i contains the parsed unsigned integer. Overflow is not checked for. */
While I agree that complete code should not be shown, because it is will not usually help the original poster, I'll make an exception here.
Code:
#include <stdio.h>
#include <limits.h>
int main(void)
{
int c, integer;
c = getchar();
while (c != EOF) {
unsigned int negative = 0U;
unsigned int value;
unsigned int limit;
/* Skip ASCII whitespace and control characters */
while (c >= 0 && c <= 32)
c = getchar();
/* End of input? */
if (c == EOF)
break;
/* Sign(s)? */
while (c == '+' || c == '-') {
negative ^= (c == '-'); /* Flip bit 0 of negative if c == '-'. */
c = getchar();
}
/* Not a digit? */
if (!(c >= '0' && c <= '9')) {
fprintf(stderr, "Garbage characters in input.\n");
return 1;
}
/* Upper limit for the absolute value.
* It is either abs(INT_MIN) or abs(INT_MAX). */
if (negative)
limit = (unsigned int)(-(double)INT_MIN);
else
limit = INT_MAX;
/* First digit. */
value = c - '0';
c = getchar();
/* Other digits. */
while (c >= '0' && c <= '9') {
const unsigned int digit = c - '0';
/* Would this overflow? */
if ((limit - digit + 1U) / 10U < value) {
fprintf(stderr, "Integer overflow in input.\n");
return 1;
}
value = 10U * value + digit;
c = getchar();
}
/* Integer too large (limit + 1)? */
if (value > limit) {
fprintf(stderr, "Integer overflow in input.\n");
return 1;
}
/* Compute correct integer value. */
if (negative)
integer = (int)(-(double)value);
else
integer = (int)value;
/*
* New integer:
*/
printf("%d\n", integer);
}
return 0;
}
The code above has certain features I'd like you to notice:
- It skips all ASCII control characters (except DEL, 127) between numbers.
- It supports only ASCII digits.
Character sets used in current operating systems are all ASCII-compatible. It does not parse integers specified using non-ASCII digits, or when input is in e.g. EBCDIC.
If you want support for non-ASCII inputs, make your program locale-aware (by calling setlocale(LC_CTYPE, ""); setlocale(LC_NUMERIC, ""); early in your program), and using *scanf() or strtol() or similar functions. - It allows more than one successive sign. For example, --5 is the same as +5 or 5.
- It uses an unsigned integer to compose the absolute value of the integer.
- It detects integers that cannot be represented by the int type.
For this, it uses an unsigned integer to hold the absolute value (per the sign). If the unsigned int type can hold both -INT_MIN+1 and INT_MAX+1, and it can on all current architectures, the detection should work. - It uses the double type to avoid the typical pitfall on most architectures, where -INT_MIN == INT_MIN unless promoted to a type with better precision.
This assumes double can represent all possible int and unsigned int values exactly.
If your C compiler supports it, I recommend using long long instead.
If you know your architecture uses two's complement numbers, then you can use (unsigned int)(-INT_MIN) and (int)(-value) instead, as the binary representation of the values is such that the values will be correct even if the compiler thinks there may be an overflow.
The reason I showed this is that it turns out that in all C libraries, standard I/O is pretty slow in parsing numbers. Using low-level I/O instead of getchar() but otherwise the above parsing scheme you can read massive amounts of decimal integers, usually only limited by I/O speed. (The GNU C library, for example, cannot reach that even on very fast x86-64 machines.)
It is possible to extend this for reading floating-point values -- which are extremely slow to parse, in relative terms -- but correct rounding becomes a difficult issue. (Most C libraries use arbitrary-precision numbers to parse floating-point data, so they can get the least significant bits correct. The IEEE-754 rules are quite strict.) I have been looking for a fast method to do that, but thus far I have only managed to read at 32-bit precision (IEEE-754 Binary32 type, or float on most architectures) using double-precision termporaries. It's enough for visualisation, but not for scientific work. It is more than an order of magnitude faster than the GNU C library, though, and can reach filesystem read speeds even on typical x86-64 workstations; it's a significant improvement, when you try to visualize millions of atoms specified in a text file.
For your use case, you should omit the irrelevant parts of the code. To determine which parts are not relevant to you, you'll need to understand the code first -- which to me personally warrants showing the code; you cannot just use it as-is.
Questions?