如何用C语言sscanf校验<Name>,<Age>,<City>格式的用户输入?
sscanf handle strict input validation for Great question! The short answer is yes, you can use sscanf to fix this issue—your current code just isn't using a strict enough format string to catch those invalid cases. Let's walk through why your existing code misses errors, and how to adjust it properly.
Why your current code fails
Your format string "%[a-zA-Z -],%[0-9],%[a-zA-Z-]" has two critical flaws:
- It only matches valid prefixes: For input like
Name1$#,20,NY,sscanfwill happily readName1(the valid part of the name) intoinput[0], then match the comma, age, comma, and city. It ignores the trailing$#entirely, sonumstill equals 3, and your error check doesn't trigger. - No checks for extra characters or field validity: You're not verifying if there's leftover garbage after the city, nor are you validating the age range or ensuring fields aren't empty.
Fixed implementation with sscanf
Here's an improved version that addresses all your validation requirements:
#include <stdio.h> #include <ctype.h> int main() { char input_str[150]; char name[50] = {0}; int age; char city[50] = {0}; int match_count; char trailing_char; // Read input line if (fgets(input_str, sizeof(input_str), stdin) == NULL) { printf("ERROR: Failed to read input\n"); return 1; } // Strict format string: // %49[a-zA-Z -] → Max 49 valid chars for name (avoids buffer overflow) // , → Exact comma separator // %d → Read age as integer (easier to validate range) // , → Exact comma separator // %49[a-zA-Z-] → Max 49 valid chars for city // %c → Catch any trailing character (to check for extra garbage) match_count = sscanf(input_str, "%49[a-zA-Z -],%d,%49[a-zA-Z-]%c", name, &age, city, &trailing_char); // Validate the match result and input rules if (match_count == 3) { // Case 1: Input ends exactly after city (no newline, e.g., EOF) if (name[0] == '\0' || city[0] == '\0') { printf("ERROR: Name or City cannot be empty\n"); } else if (age < 18 || age > 120) { printf("ERROR: Age must be between 18 and 120\n"); } else { printf("Valid input:\nName: %s\nAge: %d\nCity: %s\n", name, age, city); } } else if (match_count == 4) { // Case 2: Input has a trailing character (should be a newline from fgets) if (isspace((unsigned char)trailing_char)) { if (name[0] == '\0' || city[0] == '\0') { printf("ERROR: Name or City cannot be empty\n"); } else if (age < 18 || age > 120) { printf("ERROR: Age must be between 18 and 120\n"); } else { printf("Valid input:\nName: %s\nAge: %d\nCity: %s\n", name, age, city); } } else { printf("ERROR: Extra invalid characters found after the City field\n"); } } else { // Case 3: Match failed (invalid separators, illegal starting chars, etc.) printf("ERROR: Invalid format. Use <Name>,<Age>,<City> where:\n"); printf("- Name: Letters, spaces, hyphens (max 49 chars)\n"); printf("- Age: Integer between 18-120\n"); printf("- City: Letters, hyphens (max 49 chars)\n"); } return 0; }
Key improvements explained
- Field length limits:
%49[...]ensures we never write past the end of our 50-byte arrays (leaving space for the null terminator). - Age as integer: Reading
agedirectly as anintlets us easily validate its range (18-120) without converting a string. - Trailing character check: The final
%ccatches any characters after the city. We only accept it if it's a whitespace character (like the newline fromfgets)—any other character means there's invalid garbage in the input. - Empty field checks: We make sure
nameandcityaren't empty (e.g., input like,20,NYis rejected).
When to consider alternatives
While sscanf works perfectly here, if you ever need more flexible validation (like supporting optional whitespace around commas), you might want to split the input with strtok and validate each field manually. But for your exact requirements, this sscanf approach is clean and efficient.
内容的提问来源于stack exchange,提问作者N4D4V

