Matrix Printing

I am trying to implement a universal function for printing 2D data. I came up with the following:

int mprintf(FILE* f, char* fmt, void** data, size_t cols, size_t rows)

The task is to determine how many bits to read immediately from data, based on fmt.

The format fmtwill be the stdlib format for printf()and similar.

Do you have any knowledge of pre-existing functions from stdlibc (GNU GCC C) that I could use to facilitate this?

I try to avoid having to do all this manually, because I know "I'm stupid" (I don't want to introduce stupid mistakes). Thus, reusing code would be the freest way.

thank

Adding

I see there /usr/include/printf.h. Can I use any of these functions to do it right and make my work easier at the same time?

+3
5

, :

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);  // Possible error ignored
        }
    }

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...
}

:

  • size_t
  • intmax_t
  • ptrdiff_t

, += *= , ; .

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

/* mprintf() - print a matrix of size cols x rows */
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;
}

/* analyze format string - all arguments can be modified */
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;

            /* Length modifiers */
        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;

            /* Integer format specifiers */
        case 'd':
        case 'i':
        case 'o':
        case 'u':
        case 'x':
        case 'X':
            if (scanning_type)
            {
                /* No floating point modifiers */
                if (Hcount > 0 || Lcount > 0)
                    return -1;
                /* Can't be both longer and shorter than int at the same time */
                if (hcount > 0 && lcount > 0)
                    return -1;
                /* Valid modifiers are h, hh, l, ll */
                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;

            /* Floating point format specifiers */
        case 'e':
        case 'E':
        case 'f':
        case 'F':
        case 'g':
        case 'G':
        case 'a':
        case 'A':
            if (scanning_type)
            {
                /* No integer modifiers */
                if (lcount > 0 || hcount > 0)
                    return -1;
                /* Can't be both float and long double at once */
                if (Lcount > 0 && Hcount > 0)
                    return -1;
                /* Cannot repeat L or H modifiers */
                if (Lcount > 1 || Hcount > 1)
                    return -1;
                if (Lcount > 0)
                {
                    *size = sizeof(long double);
                    *print = printLongDouble;
                }
                else if (Hcount > 0)
                {
                    /* modify format string, dropping the H */
                    assert(Hptr != 0 && strlen(Hptr+1) > 0);
                    memmove(Hptr, Hptr+1, strlen(Hptr));    // Copy '\0' too!
                    *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);     // strdup() is not standard C99
    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);    // Or fputs("<<error>>\n");
                    goto exit_loop;
                }
            }
            fputc('\n', fp);  // Possible error ignored
        }
    }

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 /* TEST */
+6

, , . , , , , :

int mprintf(FILE* file, char* fmt, int** data, size_t cols, size_t rows) {
for(int r=0; r<rows; r++) {
    for(int c=0; c<cols; c++) {
        fprintf(file, fmt, data[r][c]); // fmt can be e.g. "%9i"
    }
    printf("\n");
}
}
+1

printf. OP , printf, scanf. , printf "scanf" . "% f", printf float double. , printf , scanf "% f" "% lf", . OP scanf- , printf. .

, , , , . (, fprintf , - fprintf). , , , , , :

#include <stdio.h>

typedef const void *(*Printfunc)(FILE *f, const void *datum);

/* print an integer and advance the pointer */
static const void* print_int(FILE *f, const void *datum)
{
    const int* p = datum;
    fprintf(f, "%d", *p);
    return p + 1;
}

/* print a char and advance the pointer */
static const void* print_char(FILE *f, const void *datum)
{
    const char* p = datum;
    fprintf(f, "%c", *p);
    return p + 1;
}

static void mprint(FILE *f, Printfunc p, const void *data, size_t cols, size_t rows)
{
    const void *next = data;
    int i;
    for (i = 0; i < rows; ++i) {
        int j;
        for (j = 0; j < cols; ++j) {
            next = p(f, next);
            putc(' ', f);
        }
        putc('\n', f);
    }
}

int main()
{
    int imatrix[3][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } };
    char cmatrix[2][2] = { { 'a', 'b' }, { 'c', 'd' } }; 

    mprint(stdout, print_int, imatrix, 2, 3);
    mprint(stdout, print_char, cmatrix, 2, 2);

    return 0;
}
+1

, , fmt , ( , (f) printf , , - , , ), , , , , , void ** ( ).

, , .

, , for, , .

+1

I think that when using the void ** method, data based on * fmt will do the trick. I am not sure if I understand your question correctly. Since you can put a switch-case statement based on * fmt for typcasting and then use ** data as a 2-D array to print it. Use rows / columns as the index of a 2-dimensional array.

0
source

Source: https://habr.com/ru/post/1796488/


All Articles