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
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 I have now compiled this, and tested and corrected it (the correction being to replace the recursive call ...bogus...
is not valid C, you can tell I've not compiled this, butpowa(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;
}
You're only allocating 7 bytes for kol
. You're trying to write beyond the bounds of the array.