, :
int mprintf(FILE *f, char *fmt, void **data, size_t cols, size_t rows);
- 4x4 8x8, , . .
- , , ? ( "% d", ?)
- , , . ? ? ? ?
- const char *.
 
- , , - printf(), . , , . .- unsigned char-- short.. C99- hh- signed char- unsigned char(- d,- i,- o,- u,- x- x)- h- short- unsigned short. , , . ,- L- long double- L- long- ll- long long. ,- printf()- float(- float- double), .- h- L, , ,- h- float. , ,- printf(), . , "H" ( , , "H", - , , ).
 
- . , - , - bsearch()- qsort(),- fread()- fwrite(). .
 
- , GCC - void *, Standard C .
 
- , - void **? , , - .
 - short s[3][4];
float f[2][5];
char  c[20][30];
mprintf(fp, "%3hd",   &s[0][0],  4,  3);
mprintf(fp, "%8.4Hf", &f[0][0],  5,  2);
mprintf(fp, "%hhu",   &c[0][0], 30, 20); 
 - data- void *. , , , .
 
"0 ". , , .
typedef int (*PrintItem)(FILE *fp, const char *format, void *element);
static int printChar(FILE *fp, const char *format, void *element)
{
    char c = *(char *)element;
    return (fprintf(fp, format, c) <= 0) ? -1 : 0;
}
...and a whole lot more like this...
static int printLongDouble(FILE *fp, const char *format, void *element)
{
    long double ld = *(long double *)element;
    return (fprintf(fp, format, ld) <= 0) ? -1 : 0;
}
int mprintf(FILE *fp, const char *fmt, void *data, size_t cols, size_t rows)
{
    char *format = strdup(fmt);
    int rc = 0;
    size_t size;
    PrintItem print;
    if ((rc = print_info(format, &size, &print)) == 0)
    {
        for (size_t i = 0; i < rows; i++)
        {
            for (size_t j = 0; j < cols; j++)
            {
                 void *element = (char *)data + (i * cols + j) * size;
                 if ((rc = print(fp, format, element)) < 0)
                      goto exit_loop;
            }
            fputc('\n', fp);  
        }
    }
exit_loop:
    free(fmt);
    return rc;
}
static int print_info(char *fmt, size_t *size, PrintItem *print)
{
    ...analyze format string...
    ...set *size to the correct size...
    ...set *print to the correct printing function...
    ...modify format string if need so be...
    ...return 0 on success, -1 on failure...
}
:
, += *= , ; .
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
extern int mprintf(FILE *fp, const char *fmt, void *data, size_t cols, size_t rows);
typedef int (*PrintItem)(FILE *fp, const char *format, void *element);
static int printChar(FILE *fp, const char *format, void *element)
{
    char value = *(char *)element;
    return (fprintf(fp, format, value) <= 0) ? -1 : 0;
}
static int printShort(FILE *fp, const char *format, void *element)
{
    short value = *(short *)element;
    return (fprintf(fp, format, value) <= 0) ? -1 : 0;
}
static int printInt(FILE *fp, const char *format, void *element)
{
    int value = *(int *)element;
    return (fprintf(fp, format, value) <= 0) ? -1 : 0;
}
static int printLong(FILE *fp, const char *format, void *element)
{
    long value = *(long *)element;
    return (fprintf(fp, format, value) <= 0) ? -1 : 0;
}
static int printLongLong(FILE *fp, const char *format, void *element)
{
    long long value = *(long long *)element;
    return (fprintf(fp, format, value) <= 0) ? -1 : 0;
}
static int printFloat(FILE *fp, const char *format, void *element)
{
    float value = *(float *)element;
    return (fprintf(fp, format, value) <= 0) ? -1 : 0;
}
static int printDouble(FILE *fp, const char *format, void *element)
{
    double value = *(double *)element;
    return (fprintf(fp, format, value) <= 0) ? -1 : 0;
}
static int printLongDouble(FILE *fp, const char *format, void *element)
{
    long double valued = *(long double *)element;
    return (fprintf(fp, format, valued) <= 0) ? -1 : 0;
}
static int print_info(char *format, size_t *size, PrintItem *print)
{
    char *fmt = format;
    char c;
    bool scanning_type = false;
    int hcount = 0;
    int lcount = 0;
    int Hcount = 0;
    int Lcount = 0;
    char *Hptr = 0;
    while ((c = *fmt++) != '\0')
    {
        switch (c)
        {
        case '%':
            if (*fmt == '%')
                fmt++;
            else
                scanning_type = true;
            break;
            
        case 'h':
            if (scanning_type)
                hcount++;
            break;
        case 'l':
            if (scanning_type)
                lcount++;
            break;
        case 'L':
            if (scanning_type)
                Lcount++;
            break;
        case 'H':
            if (scanning_type)
            {
                Hptr = fmt - 1;
                Hcount++;
            }
            break;
            
        case 'd':
        case 'i':
        case 'o':
        case 'u':
        case 'x':
        case 'X':
            if (scanning_type)
            {
                
                if (Hcount > 0 || Lcount > 0)
                    return -1;
                
                if (hcount > 0 && lcount > 0)
                    return -1;
                
                if (hcount > 2 || lcount > 2)
                    return -1;
                if (hcount == 2)
                {
                    *size = sizeof(char);
                    *print = printChar;
                }
                else if (hcount == 1)
                {
                    *size = sizeof(short);
                    *print = printShort;
                }
                else if (lcount == 2)
                {
                    *size = sizeof(long long);
                    *print = printLongLong;
                }
                else if (lcount == 1)
                {
                    *size = sizeof(long);
                    *print = printLong;
                }
                else
                {
                    *size = sizeof(int);
                    *print = printInt;
                }
                return 0;
            }
            break;
            
        case 'e':
        case 'E':
        case 'f':
        case 'F':
        case 'g':
        case 'G':
        case 'a':
        case 'A':
            if (scanning_type)
            {
                
                if (lcount > 0 || hcount > 0)
                    return -1;
                
                if (Lcount > 0 && Hcount > 0)
                    return -1;
                
                if (Lcount > 1 || Hcount > 1)
                    return -1;
                if (Lcount > 0)
                {
                    *size = sizeof(long double);
                    *print = printLongDouble;
                }
                else if (Hcount > 0)
                {
                    
                    assert(Hptr != 0 && strlen(Hptr+1) > 0);
                    memmove(Hptr, Hptr+1, strlen(Hptr));    
                    *size = sizeof(float);
                    *print = printFloat;
                }
                else
                {
                    *size = sizeof(double);
                    *print = printDouble;
                }
                return 0;
            }
            break;
        default:
            break;
        }
    }
    return -1;
}
int mprintf(FILE *fp, const char *fmt, void *data, size_t cols, size_t rows)
{
    char *format = strdup(fmt);     
    int rc = 0;
    size_t size;
    PrintItem print;
    if ((rc = print_info(format, &size, &print)) == 0)
    {
        for (size_t i = 0; i < rows; i++)
        {
            for (size_t j = 0; j < cols; j++)
            {
                void *element = (char *)data + (i * cols + j) * size;
                if ((rc = print(fp, format, element)) < 0)
                {
                    fputc('\n', fp);    
                    goto exit_loop;
                }
            }
            fputc('\n', fp);  
        }
    }
exit_loop:
    free(format);
    return rc;
}
#ifdef TEST
int main(void)
{
    short s[3][4];
    float f[2][5];
    char  c[8][9];
    FILE *fp = stdout;
    int v = 0;
    for (size_t i = 0; i < 3; i++)
    {
        for (size_t j = 0; j < 4; j++)
        {
            s[i][j] = (v += 13) & 0x7FFF;
            printf("s[%zu,%zu] = %hd\n", i, j, s[i][j]);
        }
    }
    v = 0;
    for (size_t i = 0; i < 8; i++)
    {
        for (size_t j = 0; j < 9; j++)
        {
            c[i][j] = (v += 13) & 0x7F;
            printf("c[%zu,%zu] = %hhu\n", i, j, c[i][j]);
        }
    }
    float x = 1.234;
    for (size_t i = 0; i < 2; i++)
    {
        for (size_t j = 0; j < 5; j++)
        {
            f[i][j] = x *= 13.12;
            printf("f[%zu,%zu] = %g\n", i, j, f[i][j]);
        }
    }
    mprintf(fp, " %5hd",      &s[0][0], 4, 3);
    mprintf(fp, "%%(%3hhu) ", &c[0][0], 8, 9);
    mprintf(fp, " %11.4He",   &f[0][0], 5, 2);
    mprintf(fp, " %11.4He",    f,       5, 2);
    return 0;
}
#endif