#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
enum oflow { OFL_GOOD, OFL_OVER, OFL_UNDER };
int getnums(const char *str, int nums[], enum oflow oflow[], int n)
{
int i;
for (i = 0; *str; ) {
char *junk;
long val;
str += strcspn(str, "0123456789+-");
if (!*str)
break;
errno = 0;
val = strtol(str, &junk, 10);
if (junk > str) {
if (i < n) {
if (((val == LONG_MIN) && errno == ERANGE) || (val < INT_MIN)) {
nums[i] = 0;
oflow[i++] = OFL_UNDER;
} else if (((val == LONG_MAX) && errno == ERANGE) || (val > INT_MAX)) {
nums[i] = 0;
oflow[i++] = OFL_OVER;
} else {
oflow[i] = OFL_GOOD;
nums[i++] = val;
}
} else {
i++;
}
str = junk;
} else {
str++; /* no number was pulled out: skip one char and try again */
}
}
return i;
}
int main(int argc, char **argv)
{
int nums[256];
enum oflow oflow[256];
if (argc > 1) {
int n = getnums(argv[1], nums, oflow, 256);
int i;
if (n > 256) {
printf("array is too small: we need %d elements\n", n);
n = 256;
}
for (i = 0; i < n; i++) {
if (oflow[i])
printf("nums[%d] = %sflow\n", i, oflow[i] == OFL_OVER ? "over" : "under");
else
printf("nums[%d] = %d\n", i, nums[i]);
}
}
return 0;
}
tests:
$ ./nums ""
$ ./nums "0"
nums[0] = 0
$ ./nums "-"
$ ./nums "+"
$ ./nums "+1"
nums[0] = 1
$ ./nums "-1"
nums[0] = -1
$ ./nums "abc"
$ ./nums "asd+asdf+1 -0+1-3234abc-10zzz-"
nums[0] = 1
nums[1] = 0
nums[2] = 1
nums[3] = -3234
nums[4] = -10
$ ./nums "+++-1+++"
nums[0] = -1
$ ./nums "++"
$ ./nums "1+11111111111111111111111-111111111111111111111"
nums[0] = 1
nums[1] = overflow
nums[2] = underflow
$ ./nums "$(seq 1 300)" | head -5
array is too small: we need 300 elements
nums[0] = 1
nums[1] = 2
nums[2] = 3
nums[3] = 4
$ ./nums "$(seq 1 300)" | tail -5
nums[251] = 252
nums[252] = 253
nums[253] = 254
nums[254] = 255
nums[255] = 256
Homework exercise: in what situations is junk == str
after the strtol
, so that the str++
case executes? Why do we need this logic?