Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 4036278
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 20, 20262026-05-20T12:12:13+00:00 2026-05-20T12:12:13+00:00

I’m trying to implement an all-purpose function for printing 2D data. What I’ve come

  • 0

I’m trying to implement an all-purpose function for printing 2D data. What I’ve come up with is:

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

The challenge is determining how many bits to read at once from data, based on fmt.

The format fmt is going to be the stdlib’s-specific format for printf() and alike.

Do you have any knowledge of already-existing features from stdlibc (GNU GCC C’s) I could use to ease this up?

I try avoiding having to do it all manually, because I know “I am stupid” (I don’t want to introduce stupid bugs). Thus, reusing code would be the bug-freest way.

Thanks

Addendum

I see there’s a /usr/include/printf.h. Can’t I use any of those functions to do it right and ease my job at the same time?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-20T12:12:13+00:00Added an answer on May 20, 2026 at 12:12 pm

    Design proposed in question:

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

    High-level design points

    1. If you want to print a 4×4 section of an 8×8 matrix, you need to know the row length of the matrix as well as the size to print. Or you may prefer to have that as a separate function.
    2. Presumably, the format will define the separation between matrix entries, or will you force a space between them, or what? (If the user specifies “%d”, will the numbers all be joined together?)
    3. You’re implicitly assuming that the matrix will be printed by itself, left-justified on the page. How would you adapt the interface to print the matrix elsewhere? Leading spaces on the line? Text before each line of the matrix? Text after line of the matrix?

    Low-level design points

    1. The format string should be a const char *.

    2. Clearly, your code can do what printf() does, more or less. It looks at the format conversion specifier, and then determines what type to collect. Your code will be slightly more complex, in some respects. You’ll need to treat an array of unsigned char differently from an array of short, etc. C99 provides for modifier hh for signed char or unsigned char (before the format specifiers d, i, o, u, x, or X), and the modifier h for short or unsigned short. You should probably recognize these too. Similarly, the modifiers L for long double and l for long and ll for long long should be handled. Interestingly, printf() does not have to deal with float (because any single float value is automatically promoted to double), but your code will have to do that. By analogy with h and L, you should probably use H as the modifier to indicate a float array. Note that this case means you will need to pass to the printf() function a different format from the one specified by the user. You can make a copy of the user-provided format, dropping the ‘H’ (or use exactly the user-provided format except when it contains the ‘H’; you will not modify the user’s format string – not least because the revised interface says it is a constant string).

    3. Ultimately, your code will have to determine the size of the elements in the array. It might be that you modify the interface to include that information – by analogy with functions such as bsearch() and qsort(), or fread() and fwrite(). Or you can determine it from the format specifier.

    4. Note that although GCC allows pointer arithmetic on void *, Standard C does not.

    5. Are you sure you want a void ** in the interface? I think it would be easier to understand if you pass the address of the starting element of the array – a single level of pointer.

      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); 
      

      This changes the data parameter to a void *. Maybe I’m too decaffeinated, but I can’t see how to make a double pointer work sanely.

    Outline

    • Determine size of elements and correct format string.
    • For each row
      • For each column
      • Find the data for the element
      • Call an appropriate function to print it
      • Print a separator if you need to
      • Print a newline

    Illustration

    This code assumes a ‘0 is success’ convention. It assumes you are dealing with numbers, not matrices of pointers or strings.

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

    Working code

    Left as an exercise:

    1. Pointers
    2. Strings
    3. size_t
    4. intmax_t
    5. ptrdiff_t

    Note that I would not normally use the += or *= operators on the same line as other assignments; it was convenient for generating test numbers, though.

    #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 */
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm trying to decode HTML entries from here NYTimes.com and I cannot figure out
I am trying to understand how to use SyndicationItem to display feed which is
Basically, what I'm trying to create is a page of div tags, each has
link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have just tried to save a simple *.rtf file with some websites and
I am trying to loop through a bunch of documents I have to put
I'm parsing an RSS feed that has an &#8217; in it. SimpleXML turns this
I have this code: - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock { NSString *someString = [[NSString
I have some data like this: 1 2 3 4 5 9 2 6
i want to parse a xhtml file and display in UITableView. what is the

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.