There is tradeoff between correctness and comprehensiveness. Therefore I created two versions of program:
- first with extensive error handling
- second is simple - assumes only positive scenario (input doesn't contain errors) to stay comprehensive.
Sequence of integers contained in C-string may be parsed invoking in loop standard C function strtol from <stdlib.h>:
long int strtol (const char* str, char** endptr, int base);
that parses the C-string str interpreting its content as an integral number of the specified base. strtol skips white spaces, interprets integer and set pointer *endptr to the first character following the integer.
Since author has variable sum in his code let's demonstrate parsing of sequence of integers as summation of this sequence. I took function sum_ints_from_string() from GNU Manual 20.11.1 Parsing of Integers
Code in manual assumes positive scenario. Therefore I changed it for first version.
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
sum_ints_from_string (char *string)
{
int sum = 0;
while (1) {
char *tail;
int next;
/* Skip whitespace by hand, to detect the end. */
while (string && isspace (*string)) string++;
if (!string || *string == 0)
break;
/* There is more nonwhitespace, */
/* so it ought to be another number. */
errno = 0;
/* Parse it. */
next = strtol (string, &tail, 0);
/* Add it in, if possible. */
if (string == tail)
{
while (tail && !isspace (*tail)) tail++;
printf("error: %s\n", strerror(errno));
printf ("does not have the expected form: %s\n", string);
}
else if(errno == 0)
{
printf("%d\n", next);
sum += next;
}
else
{
printf("error: %s\n", strerror(errno));
printf ("error: %s\n", string);
}
/* Advance past it. */
string = tail;
}
return sum;
}
int main ()
{
int sum = 0;
size_t len = 0;
char * line;
FILE *f = fopen("file.txt", "w+");
assert(f != NULL && "Error opening file");
const char *text = "010 0x10 -10 1111111111111111111111111111 0 30 A 10 +5 + 10 30\n"
"20 20B 6 ABC - 20 10 0";
assert(fputs(text, f) > 0 && "error writing to file");
rewind(f);
errno = 0;
while (getline(&line, &len, f) != -1)
{
sum += sum_ints_from_string(line);
printf("%d\n", sum);
free(line);
line = NULL;
len = 0;
}
assert(sum == 175);
return 0;
}
Second version - positive scenario:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
sum_ints_from_string (char *string)
{
int sum = 0;
while (1) {
char *tail;
int next;
/* Skip whitespace by hand, to detect the end. */
while (isspace (*string)) string++;
if (*string == 0)
break;
/* There is more nonwhitespace, */
/* so it ought to be another number. */
errno = 0;
/* Parse it. */
next = strtol (string, &tail, 0);
/* Add it in, if not overflow. */
if (errno) // returned value is not tested in GNU original
printf ("Overflow\n");
else
sum += next;
/* Advance past it. */
string = tail;
}
return sum;
}
int main ()
{
int sum = 0;
size_t len = 0;
char * line;
while (getline(&line, &len, stdin) != -1)
{
sum += sum_ints_from_string(line);
/*
` If line is set to NULL and len is set 0 before the call, then
getline() will allocate a buffer for storing the line. This buffer
should be freed by the user program even if getline() failed.
*/
free(line);
line = NULL;
len = 0;
}
return 0;
}
Error checking in version from GNU manual is almost skipped.
According to CppReference.com strtol:
Return value
- If successful, an integer value corresponding to the contents of str is returned.
- If the converted value falls out of range of corresponding return type, a range error occurs (setting errno to ERANGE) and LONG_MAX, LONG_MIN, LLONG_MAX or LLONG_MIN is returned.
- If no conversion can be performed, 0 is returned.
So for our purpose of summation we are interested only: whether we can add next val or not - we don't need granular and complex error checking here.
We have nothing for summation and print error in case: of out of range OR strtol returns 0 (zero return value means: integer equals 0 or conversion cannot be performed).
Otherwise we add next.