ZetCode

C vscanf function

last modified April 6, 2025

Formatted input is a crucial aspect of C programming, allowing flexible reading of data from various sources. The vscanf function provides a powerful way to handle variable argument lists for input scanning. This tutorial explains vscanf in depth, covering its syntax, usage patterns, and security considerations. You'll learn through practical examples how to leverage this function effectively in your programs.

What Is vscanf?

The vscanf function is a variant of scanf that accepts a variable argument list through a va_list object. It reads formatted input from stdin, matching the format string with provided arguments. This function is declared in stdarg.h and is particularly useful when creating wrapper functions for input processing. Unlike scanf, it requires proper initialization of the variable argument list.

Basic vscanf Example

This example demonstrates the fundamental usage of vscanf to read multiple values from standard input.

basic_vscanf.c
#include <stdio.h>
#include <stdarg.h>

void read_input(const char *format, ...) {
    va_list args;
    va_start(args, format);
    vscanf(format, args);
    va_end(args);
}

int main() {
    int age;
    float height;
    char name[50];

    printf("Enter name, age, and height: ");
    read_input("%s %d %f", name, &age, &height);

    printf("Name: %s\nAge: %d\nHeight: %.2f\n", name, age, height);
    return 0;
}

In this example, we create a wrapper function read_input that uses vscanf. The va_start macro initializes the argument list, and va_end cleans it up. The format string and variables are passed through the variable arguments mechanism. This approach centralizes input processing while maintaining scanf's flexibility.

Safe Input with vscanf

This example shows how to implement bounds checking when using vscanf to prevent buffer overflows.

safe_vscanf.c
#include <stdio.h>
#include <stdarg.h>

void safe_scanf(const char *format, ...) {
    va_list args;
    va_start(args, format);
    
    // Replace %s with width specifiers to prevent overflow
    char modified_format[100];
    snprintf(modified_format, sizeof(modified_format), "%s", format);
    
    // This is a simplified example - in practice you would parse the format
    // string and add width specifiers to all %s conversions
    
    vscanf(modified_format, args);
    va_end(args);
}

int main() {
    char city[30];
    int population;

    printf("Enter city and population: ");
    safe_scanf("%29s %d", city, &population);

    printf("City: %s\nPopulation: %d\n", city, population);
    return 0;
}

While vscanf inherits scanf's security limitations, this example demonstrates a safer approach. We limit string input size with %29s to prevent buffer overflow in the city array. For production code, consider using fgets with parsing for complete safety. Always validate input and handle potential errors explicitly.

Custom Input Function with vscanf

Create a reusable input function that combines prompts with vscanf for better user interaction.

custom_input.c
#include <stdio.h>
#include <stdarg.h>

int input(const char *prompt, const char *format, ...) {
    va_list args;
    int count;
    
    printf("%s", prompt);
    fflush(stdout);
    
    va_start(args, format);
    count = vscanf(format, args);
    va_end(args);
    
    return count;
}

int main() {
    int num1, num2;
    
    if (input("Enter two numbers: ", "%d %d", &num1, &num2) != 2) {
        printf("Invalid input!\n");
        return 1;
    }
    
    printf("Sum: %d\n", num1 + num2);
    return 0;
}

This example creates an input function that displays a prompt before reading input. The function returns the number of successfully matched items, allowing for error checking. The fflush(stdout) ensures the prompt appears before waiting for input. This pattern makes your code more readable and maintainable by encapsulating common input operations.

Reading Different Data Types

Demonstrate vscanf's ability to handle various data types in a single function call.

multi_type.c
#include <stdio.h>
#include <stdarg.h>

void read_data(const char *format, ...) {
    va_list args;
    va_start(args, format);
    vscanf(format, args);
    va_end(args);
}

int main() {
    char letter;
    int number;
    double value;
    char word[20];
    
    printf("Enter a letter, number, value, and word: ");
    read_data(" %c %d %lf %19s", &letter, &number, &value, word);
    
    printf("Letter: %c\nNumber: %d\nValue: %.2f\nWord: %s\n",
           letter, number, value, word);
    return 0;
}

This example shows vscanf reading multiple data types in one call. The format string specifies conversions for a character (%c), integer (%d), double (%lf), and string (%19s). Note the space before %c to skip any whitespace. The function handles all conversions through the variable argument list, demonstrating vscanf's flexibility.

Error Handling with vscanf

Implement robust error handling when using vscanf to manage invalid input scenarios.

error_handling.c
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>

bool try_read(const char *format, ...) {
    va_list args;
    int expected, actual;
    
    va_start(args, format);
    actual = vscanf(format, args);
    va_end(args);
    
    // Count expected conversions
    expected = 0;
    while (*format) {
        if (*format++ == '%' && *format != '%' && *format != '*') {
            expected++;
        }
    }
    
    if (actual != expected) {
        // Clear input buffer on failure
        while (getchar() != '\n');
        return false;
    }
    return true;
}

int main() {
    int age;
    
    printf("Enter your age: ");
    while (!try_read("%d", &age)) {
        printf("Invalid input. Please enter a number: ");
    }
    
    printf("Your age is: %d\n", age);
    return 0;
}

This example creates a try_read function that returns a boolean indicating success. It compares the expected number of conversions (counted from the format string) with the actual conversions performed. On failure, it clears the input buffer to prevent infinite loops. The main function demonstrates using this in a loop until valid input is received. This pattern is essential for creating robust user interfaces.

Best Practices for Using vscanf

Source

C vscanf Documentation

This tutorial has explored the vscanf function, demonstrating its use through practical examples. While powerful, remember to use it cautiously, especially with user input. Proper error handling and input validation are essential for creating robust applications.

Author

My name is Jan Bodnar, and I'm a dedicated programmer with a deep passion for coding. Since 2007, I've been sharing my expertise through over 1,400 articles and 8 e-books. With more than a decade of teaching experience, I strive to make programming accessible and engaging.

List C Standard Library.