Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In plain C, how to do you make the equivalent of a "map"?

So I'm trying to make a program completely from scratch (no libraries included) and I have a function which is very ugly:

int parseUnsignedInt ( char * ch, unsigned int * ui )
{
/* Starting at character ch, reads the unsigned int into the
       variable ui, returns the number of characters read.
*/
    ui = 0; // unsigned integer into which the string representation is read 
    int m = 1; // multiplier
    int ncp = 0; // # of characters parsed
    while (*ch)
    {
        bool chid = false; // ch is a decimal
        for (int k = 0; k < decmapLength; ++k)
        {
            if (decmap[k].cval == *ch)
            {
                ui += decmap[k].ival * m;
                m *= 10;
                chid = true;
                break;
            }
        }
        if (!chid) break;
        ++ncp;
        ++ch;
    }
    return ncp;
}

Part of its ugliness stems from the fact that I needed a way to associate characters to integers ('0'->0, '1'->1, ..., '9'->9) and made an array or structs

typedef struct icpair
{
    char cval;
    int ival;
} icpair;

icpair decmap [10] = {{'0',0}, {'1',1}, {'2',2}, {'3',3}, {'4',4}, {'5',5}, {'6',6}, {'7',7}, {'8',8}, {'9',9}};
int decmapLength = sizeof(decmap)/sizeof(icpair);

for that purpose. But, looking up a value, if it even exists, accounts for the unsightly number of lines that could be condensed if there was a better way to do this in pure C. I also want this to be reliable, so no ASCII value subtraction like '9'-'ch'. Is this possible in pure C, and if so, how is it implemented?

like image 221
Crappy Programmer Avatar asked Apr 27 '15 01:04

Crappy Programmer


1 Answers

A simple map API in C might look like:

Map * map_create(void);
void map_insert(Map * map, char key, int value);
int map_find(Map * map, char key);
void map_destroy(Map * map);

Then you'd be able to do map_find(map, '0') to get the integer value, perhaps with the semantics of returning -1 if it isn't found.

The implementation of this could be done with a number of different data structures, depending on your needs. If you don't care about maintaining an order, a hash table would probably be most appropriate. If you do need to maintain the order based on key, for example, a binary tree might be a better idea (perhaps a red-black tree).

You could modify the API to take void * for the key and for the value to generalize it a bit (in the absence of generics, which C lacks). There would be added complexity like providing a hashing function for a hash table or a comparison function for a binary tree.

That said, doing *ch - '0' is safe to do and will work just fine.

like image 160
Sydius Avatar answered Oct 04 '22 11:10

Sydius