Input Validation Patterns
Parse Integer Status
Parsing code should return an explicit status instead of assuming text is valid.
parse status
`strtol` can report where parsing stopped so the program can reject partial input.
range limit
A valid number can still be outside the range accepted by the program.
Parse Integer Status
parse_int_status.c
Replay: real traced execution (multi-file project)
#include <stdio.h>
#include <stdlib.h>
int parseInt(const char *text, int *outValue) {
char *end = 0;
long value = strtol(text, &end, 10);
if (end == text || *end != '\0') {
return 0;
}
if (value < -100 || value > 100) {
return 0;
}
*outValue = (int)value;
return 1;
}
int main(void) {
int inputCase = 0;
const char *text = "42";
if (inputCase == 1) {
text = "17x";
} else if (inputCase == 2) {
text = "150";
}
int value = 0;
int ok = parseInt(text, &value);
printf("inputCase=%d ok=%d value=%d\n", inputCase, ok, value);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int parseInt(const char *text, int *outValue) {
char *end = 0;
long value = strtol(text, &end, 10);
if (end == text || *end != '\0') {
return 0;
}
if (value < -100 || value > 100) {
return 0;
}
*outValue = (int)value;
return 1;
}
int main(void) {
int inputCase = 1;
const char *text = "42";
if (inputCase == 1) {
text = "17x";
} else if (inputCase == 2) {
text = "150";
}
int value = 0;
int ok = parseInt(text, &value);
printf("inputCase=%d ok=%d value=%d\n", inputCase, ok, value);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int parseInt(const char *text, int *outValue) {
char *end = 0;
long value = strtol(text, &end, 10);
if (end == text || *end != '\0') {
return 0;
}
if (value < -100 || value > 100) {
return 0;
}
*outValue = (int)value;
return 1;
}
int main(void) {
int inputCase = 2;
const char *text = "42";
if (inputCase == 1) {
text = "17x";
} else if (inputCase == 2) {
text = "150";
}
int value = 0;
int ok = parseInt(text, &value);
printf("inputCase=%d ok=%d value=%d\n", inputCase, ok, value);
return 0;
}
inputCase ← 0, text ← 42, value ← 0
19int main(void) {20 int inputCase→ 0 = 0; //@inputCase=1, 221 const char *text→ 42 = "42";22 if (inputCase == 1) {23 text = "17x";24 } else if (inputCase == 2) {25 text = "150";26 }2728 int value→ 0 = 0;29 int ok = parseInt(text42, &value0);end ← (empty), value ← 42
4int parseInt(const char *text42, int *outValue⟨addr A⟩) {5 char *end→ (empty) = 0;6 long value→ 42 = strtol(text42, &end(empty), 10);78 if (end == text || *end != '\0') {9 return 0;10 }11 if (value < -100 || value > 100) {12 return 0;13 }1415 *outValue⟨addr A⟩ = (int)value42;16 return 1;17}value ← 42, ok ← 1
28 int value = 0;29 int ok→ 1 = parseInt(text42, &value→ 42);3031 printf("inputCase=%d ok=%d value=%d\n", inputCase0, ok1, value42);32 return 0;33}outputinputCase=0 ok=1 value=42
inputCase ← 1, text ← 42
19int main(void) {20 int inputCase→ 1 = 1;21 const char *text→ 42 = "42";22 if (inputCase == 1) {text ← 17x
21const char *text = "42";22if (inputCase1 == 1) {23 text→ 17x = "17x";24} else if (inputCase == 2) {value ← 0
28int value→ 0 = 0;29int ok = parseInt(text17x, &value0);end ← (empty), value ← 17
4int parseInt(const char *text17x, int *outValue⟨addr A⟩) {5 char *end→ (empty) = 0;6 long value→ 17 = strtol(text17x, &end→ x, 10);if (end == text || *end != '\0')
8if (endx == text17x || *end != '\0') {9 return 0;10}ok ← 0
28 int value = 0;29 int ok→ 0 = parseInt(text17x, &value0);3031 printf("inputCase=%d ok=%d value=%d\n", inputCase1, ok0, value0);32 return 0;33}outputinputCase=1 ok=0 value=0
inputCase ← 2, text ← 42
19int main(void) {20 int inputCase→ 2 = 2;21 const char *text→ 42 = "42";22 if (inputCase == 1) {text ← 150
23 text = "17x";24} else if (inputCase2 == 2) {25 text→ 150 = "150";26}value ← 0
28int value→ 0 = 0;29int ok = parseInt(text150, &value0);end ← (empty), value ← 150
4int parseInt(const char *text150, int *outValue⟨addr A⟩) {5 char *end→ (empty) = 0;6 long value→ 150 = strtol(text150, &end(empty), 10);if (value < -100 || value > 100)
10}11if (value150 < -100 || value > 100) {12 return 0;13}ok ← 0
28 int value = 0;29 int ok→ 0 = parseInt(text150, &value0);3031 printf("inputCase=%d ok=%d value=%d\n", inputCase2, ok0, value0);32 return 0;33}outputinputCase=2 ok=0 value=0
Exercise: parse_int_status.c
Reject empty, partial, and out-of-range integer input with distinct status codes