Calc cell convertor in C

前端 未结 2 1237
长情又很酷
长情又很酷 2021-01-28 23:13

I\'m learning C and I have written a simple program (just a tanning). On input you pass two arguments (row and column) and output you get a Calc (or Excel) code for this cell. F

相关标签:
2条回答
  • 2021-01-28 23:39

    Are you experimenting with recursion? I don't think I'd be using a recursive solution. You should probably not be using as many global variables as you are, either.

    Assuming recursion is crucial, then in outline, I think I'd expect to use a solution such as:

    char *powa(unsigned int code, char *buffer)
    {
        unsigned int div = code / 26;
        unsigned int rem = code % 26;
        if (div > 0)
            buffer = powa(div - 1, buffer);
        *buffer++ = rem + 'A';
        *buffer = '\0';
        return buffer;
    }
    
    int main(void)
    {
        char buffer[32];
        unsigned int col, row;
    
        printf("Enter column and row numbers: ");
        if (scanf("%u %u", &col, &row) == 2)
        {
            if (col == 0 || row == 0)
                fprintf(stderr, "Both row and column must be larger than zero"
                                " (row = %u, col = %u)\n", row, col);
            else
            {
                char *end = powa(col-1, buffer);
                snprintf(end, sizeof(buffer) - (end - buffer), "%u", row);
                printf("Col %u, Row %u, Cell %s\n", col, row, buffer);
            }
        }
        return 0;
    }
    

    Note that the revised powa() returns a pointer to the null at the end of the data it has formatted. Theoretically, I should check the return from snprintf() to ensure no buffer overflow. Since ...bogus... is not valid C, you can tell I've not compiled this, but I have now compiled this, and tested and corrected it (the correction being to replace the recursive call powa(div, buffer) with powa(div - 1, buffer), a change necessary because the calculation needs to deal with 0 versus 1 as the starting point for counting. The recursion scheme seems simpler to me (a single recursive call instead of three of them in your code).

    Enter column and row numbers: 13 27
    Col 13, Row 27, Cell M27
    
    Enter column and row numbers: 27 13
    Col 27, Row 13, Cell AA13
    
    Enter column and row numbers: 30000000 128
    Col 30000000, Row 128, Cell BMPVRD128
    
    Enter column and row numbers: 300000000 128
    Col 300000000, Row 128, Cell YFLRYN128
    

    Here is code to handle both scanning and formatting derived from the code above:

    /*
    ** Convert column and row number into Excel (Spreadsheet) alphanumeric reference
    ** 1,1     => A1
    ** 27,1    => AA1
    ** 37,21   => AK21
    ** 491,321 => RW321
    ** 3941,87 => EUO87
    ** From StackOverflow question 7651397 on 2011-10-04:
    ** http://stackoverflow.com/questions/7651397/calc-cell-convertor-in-c
    */
    
    #include <ctype.h>
    #include <stdio.h>
    #include <string.h>
    
    extern unsigned xl_row_decode(const char *code);
    extern char *xl_row_encode(unsigned row, char *buffer);
    
    static char *xl_encode(unsigned row, char *buffer)
    {
        unsigned div = row / 26;
        unsigned rem = row % 26;
        if (div > 0)
            buffer = xl_encode(div-1, buffer);
        *buffer++ = rem + 'A';
        *buffer = '\0';
        return buffer;
    }
    
    char *xl_row_encode(unsigned row, char *buffer)
    {
        return(xl_encode(row-1, buffer));
    }
    
    unsigned xl_row_decode(const char *code)
    {
        unsigned char c;
        unsigned r = 0;
        while ((c = *code++) != '\0')
        {
            if (!isalpha(c))
                break;
            c = toupper(c);
            r = r * 26 + c - 'A' + 1;
        }
        return r;
    }
    
    static const struct
    {
        unsigned col;
        unsigned row;
        char     cell[10];
    } tests[] =
    {
        {     1,     1, "A1"       },
        {    26,     2, "Z2"       },
        {    27,     3, "AA3"      },
        {    52,     4, "AZ4"      },
        {    53,     5, "BA5"      },
        {   676,     6, "YZ6"      },
        {   702,     7, "ZZ7"      },
        {   703,     8, "AAA8"     },
        {   728,     9, "AAZ9"     },
    };
    enum { NUM_TESTS = sizeof(tests) / sizeof(tests[0]) };
    
    int main(void)
    {
        char buffer[32];
        int pass = 0;
    
        for (int i = 0; i < NUM_TESTS; i++)
        {
            char *end = xl_row_encode(tests[i].col, buffer);
            snprintf(end, sizeof(buffer) - (end - buffer), "%u", tests[i].row);
            unsigned n = xl_row_decode(buffer);
            const char *pf = "FAIL";
    
            if (tests[i].col == n && strcmp(tests[i].cell, buffer) == 0)
            {
                pf = "PASS";
                pass++;
            }
            printf("%s: Col %3u, Row %3u, Cell (wanted: %-8s vs actual: %-8s) Col = %3u\n",
                   pf, tests[i].col, tests[i].row, tests[i].cell, buffer, n);
        }
        if (pass == NUM_TESTS)
            printf("== PASS == %d tests OK\n", pass);
        else
            printf("!! FAIL !! %d out of %d failed\n", (NUM_TESTS - pass), NUM_TESTS);
    
        return (pass == NUM_TESTS) ? 0 : 1;
    }
    
    0 讨论(0)
  • 2021-01-28 23:42

    You're only allocating 7 bytes for kol. You're trying to write beyond the bounds of the array.

    0 讨论(0)
提交回复
热议问题