首页 > 解决方案 > 当长度、元素大小和格式已知时,如何使用 printf 打印 void * 数组?

问题描述

我已经尝试过这种方式。然后在输出中得到垃圾并发现我做错了。

#include "stdlib.h"
#include "stdio.h"

/*
 * Prints array from the anonymous array pointer.
 *
 * Returns 0 on success.
 * Return -1 on failure.
 */
int print_array(const void *arr, size_t arr_len,
                size_t elem_size, const char *format) {
    for (size_t i = 0; i < arr_len; ++i)
        if (printf(format, (char *) arr + i * elem_size) < 0)
            return -1;
    printf("\n");

    return 0;
}

// Usage example
int main() {
    const int n = 3;
    int arr[n];
    for (int i = 0; i < n; ++i)
        arr[i] = i;
    print_array(arr, n, sizeof(int), "%d ");
}

我的代码应该适用于不同的可能类型。类型实际上是在执行开始的某个地方推导出来的,然后使用这个最小描述。这种技巧很好地适用,scanf因为它需要指向元素而不是元素本身的指针。

需要这种复杂性来符合开闭原则,从而最大限度地减少代码中的开关和条件句的数量。我试图只将实际类型推导集中在一个地方。

我想与 with 相同的事情scanf应该是可能的,因为printf它实际上是一个可变参数函数,它可以在运行时获取任何值并解析它们。滥用“stdarg.h”可能会有所帮助。

当然,我希望有不是特定于编译器的解决方案。

标签: arraysc

解决方案


与其传递格式化字符串,不如传递一个函数来打印它,允许用户做他想做/需要的任何事情来打印实际数据。

int print_array(const void *arr, size_t arr_len, size_t elem_size,
       int (*print_elem)(const void *el, void *cookie), // I would add FILE* argument
       void *cookie // allow users to pass additional context if they wanna
) {
    for (size_t i = 0; i < arr_len; ++i) {
        if (print_elem((char*)arr + i * elem_size, cookie) < 0) {
            return -1;
        }
    }
    printf("\n");
    return 0;
}

int print_int(const void *el, void *cookie) {
    return printf("%d", *(int*)el);
}

// print and allow users to pass options
int print_int_with_width(const void *el, void *cookie) {
    int width = *(int*)cookie;
    return printf("%*d", width, *(int*)el);
}

int arr[5];
int main() {
    print_array(arr, 5, sizeof(int), print_int, NULL);
    int width = 5;
    print_array(arr, 5, sizeof(int), print_int_with_width, &width);
}

推荐阅读