tags:

views:

2209

answers:

7

Hi,

Can a string be used as array index in C?

Ex: String Corresponding value "ONE" 1 "TWO" 2 "FIVE" 5 "TEN" 10

When a string in the above list is passed to the function, the function must return the corresponding value indicated above. Can this be achieved by declaring a constant array with string as index

int *x;
x["ONE"]  = 1;
x["TWO"]  = 2;
x["FIVE"] = 5;
x["TEN"]  = 5;

return x["string received by the function"];

The above logic does not work as expected; is there a workaround to implement the above logic in order to have a string-indexed array?

+13  A: 

It might compile, but it won't work.

It's not entirely clear what you're trying to achieve. I think you want an associative array, in which case you should find a library implementation of one.

If you're looking for something more like an enumerated type, and you can rely on C89, look at something like:

enum cardsuit {
   CLUBS,
   DIAMONDS,
   HEARTS,
   SPADES
};

If you can't rely on C89, then you should try some typedef trickery.

Hank Gay
+2  A: 

You will need to write a function that maps strings to integers, or alternatively use enumerations throughout (and then perhaps a function that maps enumerated values to strings).

In general, it's nicer to do the latter: to pass integers, so that the implementation isn't dependent on the details of strings that might be used in the representation. For example, think about how you would manage localization (translation) if ever you need to make those strings palatable to somebody speaking a different language.

Martin Carpenter
+1  A: 

What you are looking for is probably the equivalent of an associative array which can't be provided with the same syntactic sugar in C unfortunately without some silly results.

However, what you can provide is a hashmap if your data conforms to key -> value pairs. What you will need is an appropiate hash function.

There's a decent simple example of a hashtable here:

http://www.cl.cam.ac.uk/~cwc22/hashtable/

Phil
A: 

In "plain C" you can mimic using a string as an index, but not QUITE in the way you seem to be wanting. However, doing so is seldom useful and mostly an excellent way of making your code unreadable. What you seem to be wanting is to be able to use string keys into a dictionary (or "hash table", if you prefer) and there are no built-in data structure for that in C. The exact design would depend on what you want (and, indeed, if this is part of homework, you may not even need to use a full-fledged hash-table implementation but could probably get away with less performant static coding).

An example using a string (OK, a char array) in the "index position) of an a[b] construct:

int main (void)
{
  char *str = "This is a test string";
  int x;

  for (x=0; x < 12; x += 3)
    putchar(x[str]);

  printf("\n");

  return 0;
}

The above is, as far as I can tell, legal C, with a well-defined output (the string "Tss ssi"). It relies on the fact that a[b] is defined to be the same as *(a+b).

Vatine
How exactly does this help with Kanakagiri's problem? That `x[str]` is the same as `str[x]` if one is a pointer and the other an integer might be interesting, but has nothing to do with the question...
Christoph
Actually, it has very much to do with the question (specifically, yes, you CAN use a string as an index, but not in the obvious way that the original querier wants).
Vatine
+2  A: 

You can easily build lookup tables with the function bsearch() provided by stdlib.h. A working example is this:

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

#define count(ARRAY) (sizeof(ARRAY)/sizeof(*ARRAY))

struct item
{
    const char * name;
    int value;
};

static _Bool sorted;

static struct item items[] =
{
    { "one", 1 },
    { "two", 2 },
    { "three", 3 },
    { "ten", 10 }
};

static int compare(const void * p1, const void * p2)
{
    return strcmp(*((const char **)p1), *((const char **)p2));
}

int get(const char * name)
{
    if(!sorted)
    {
        qsort(items, count(items), sizeof(*items), compare);
        sorted = 1;
    }

    struct item * item = bsearch(&name, items, count(items), sizeof(*items),
        compare);

    return item ? item->value : 0;
}

int main(int argc, char ** argv)
{
    int i;
    for(i = 1; i < argc; ++i)
        printf("%i\n", get(argv[i]));

    return 0;
}
Christoph
Core dump if you enter a value not in the list :(
Jonathan Leffler
Works fine with mingw-gcc 3.4.5 and current tinyCC on winXP - which system/compiler are you using?
Christoph
Has anyone elese tried this and got a core dump? Can't fix it if I don't know whether it's broken or not...
Christoph
A: 

As already indicated, you need an associative array or hash map or equivalent. One possible source for such code is Hanson's "C Interfaces and Implementations" (code at Google Code - double check licencing terms etc before using it.)

Jonathan Leffler
+2  A: 

There are other excellent answers to what you should do, so I thought I'd explain what you are doing and why it's compiling and not working.

In C, array reference is done by having an array or pointer and an integer of some sort. (in x[1], x is the array and 1 is the integer). As long as you're using some integral type, it'll work as you expect.

Suppose you have something that's not an integer. In that case, the C implementation will see if it can convert it to the appropriate type, so you wind up with array and integer. It's cases like this where you get into trouble (and slightly more sophisticated versions of this in C++ have confused more experienced people than you).

In C, a literal string like "one" is of type const char *, meaning pointer to characters you can't change. The actual value is the memory address of where the string actually resides in memory. Normally, you'd pay no attention to this pointer value, and look at the string value, but there's a gotcha here.

In C, any data pointer can be converted to some sort of integer, and will be automatically. Therefore, you've got a string like "one", and its value is whatever number that represents the memory address. Use it where C expects some sort of integer, and it'll get converted to some integral value or other.

Therefore, this is what's happening with x["ONE"]. The C system has to put the string "ONE" somewhere in memory, and it doesn't matter where. It's likely to be somewhere with a fairly large memory address, quite possibly in the billions. When it sees x["ONE"], it tries to convert that value to an integer, and uses it as a subscript. Therefore, you're trying to access the array x far, far beyond its bounds, and that's causing the problem. Either you're trying to use memory you're not allowed to, and the system just stops you, or you're mucking with a chunk of memory you should be leaving alone, and it's likely to fail in some mysterious way later.

David Thornley
+1 for describing how the compiler understands the code. If Kanakagiri really tried compiling the code, turning on compiler warnings would have given at least an indication that the compiler had a different understanding of the code than the programmer...
hillu