7

字符串可以用作C中的数组索引吗?

例:字符串 对应值 "ONE" 1 "TWO" 2 "FIVE" 5 "TEN" 10

当将上述列表中的字符串传递给函数时,函数必须返回上述对应的值。这可以通过声明一个以字符串为索引的常量数组来实现吗

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

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

上述逻辑并没有按预期工作;是否有解决方法来实现上述逻辑以获得字符串索引数组?

4

8 回答 8

19

它可能会编译,但它不会工作。

目前尚不完全清楚您要达到的目标。我认为你想要一个关联数组,在这种情况下你应该找到一个的库实现。

如果您正在寻找更像枚举类型的东西,并且可以依赖C89,请查看以下内容:

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

如果你不能依赖 C89,那么你应该尝试一些typedef诡计。

于 2009-01-06T11:57:59.040 回答
10

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.

于 2009-01-06T14:39:14.830 回答
5

bsearch()您可以使用提供的功能轻松构建查找表stdlib.h。一个工作示例是这样的:

#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;
}
于 2009-01-06T12:45:24.247 回答
3

您将需要编写一个将字符串映射到整数的函数,或者在整个过程中使用枚举(然后可能是一个将枚举值映射到字符串的函数)。

一般来说,后者更好:传递整数,以便实现不依赖于可能在表示中使用的字符串的细节。例如,如果您需要使这些字符串对说不同语言的人来说是可口的,请考虑如何管理本地化(翻译)。

于 2009-01-06T11:59:04.467 回答
1

您正在寻找的可能相当于一个关联数组,不幸的是,它无法在 C 中提供相同的语法糖,但没有一些愚蠢的结果。

但是,如果您的数据符合键 -> 值对,您可以提供的是哈希图。您将需要一个适当的散列函数。

这里有一个简单的哈希表示例:

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

于 2009-01-06T12:15:44.933 回答
0

如前所述,您需要一个关联数组或哈希映射或等效项。此类代码的一个可能来源是 Hanson 的“ C 接口和实现”(Google Code中的代码- 在使用之前仔细检查许可条款等。)

于 2009-01-06T13:18:46.943 回答
0

这是一个旧线程,但我认为这对于那些正在寻找实现的人来说可能仍然有用。不需要太多代码;我做了大约 100 行,没有像 Hank Gay 建议的任何额外的库。我称它为字典,因为它与(某种)python 数据类型平行。这是代码:

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

typedef struct hollow_list hollow_list;

struct hollow_list{
    unsigned int size;
    void *value;
    bool *written;
    hollow_list *children;
};

//Creates a hollow list and allocates all of the needed memory
hollow_list hollow_list_create(unsigned int size){
    hollow_list output;
    output = (hollow_list) {.size = size, .value = (void *) 0, .written = calloc(size, sizeof(bool)), .children = calloc(size, sizeof(hollow_list))};
    return output;
}

//Frees all memory of associated with a hollow list and its children
void hollow_list_free(hollow_list *l, bool free_values){
    int i;
    for(i = 0; i < l->size; i++){
        hollow_list_free(l->children + i, free_values);
    }
    if(free_values){
        free(l->value);
    }
    free(l);
}

//Reads from the hollow list and returns a pointer to the item's data
void *hollow_list_read(hollow_list *l, unsigned int index){
    if(index == 0){
        return l->value;
    }
    unsigned int bit_checker;
    bit_checker = 1<<(l->size - 1);
    int i;
    for(i = 0; i < l->size; i++){
        if(bit_checker & index){
            if(l->written[i] == true){
                return hollow_list_read(l->children + i, bit_checker ^ index);
            } else {
                return (void *) 0;
            }
        }
        bit_checker >>= 1;
    }
}

//Writes to the hollow list, allocating memory only as it needs
void hollow_list_write(hollow_list *l, unsigned int index, void *value){
    if(index == 0){
        l->value = value;
    } else {
        unsigned int bit_checker;
        bit_checker = 1<<(l->size - 1);
        int i;
        for(i = 0; i < l->size; i++){
            if(bit_checker & index){
                if(!l->written[i]){
                    l->children[i] = hollow_list_create(l->size - i - 1);
                    l->written[i] = true;
                }
                hollow_list_write(l->children + i, bit_checker ^ index, value);
                break;
            }
            bit_checker >>= 1;
        }
    }
}

typedef struct dictionary dictionary;

struct dictionary{
    void *value;
    hollow_list *child;
};

dictionary dictionary_create(){
    dictionary output;
    output.child = malloc(sizeof(hollow_list));
    *output.child = hollow_list_create(8);
    output.value = (void *) 0;
    return output;
}

void dictionary_write(dictionary *dict, char *index, unsigned int strlen, void *value){
    void *hollow_list_value;
    dictionary *new_dict;
    int i;
    for(i = 0; i < strlen; i++){
        hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
        if(hollow_list_value == (void *) 0){
            new_dict = malloc(sizeof(dictionary));
            *new_dict = dictionary_create();
            hollow_list_write(dict->child, (int) index[i], new_dict);
            dict = new_dict;
        } else {
            dict = (dictionary *) hollow_list_value;
        }
    }
    dict->value = value;
}

void *dictionary_read(dictionary *dict, char *index, unsigned int strlen){
    void *hollow_list_value;
    dictionary *new_dict;
    int i;
    for(i = 0; i < strlen; i++){
        hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
        if(hollow_list_value == (void *) 0){
            return hollow_list_value;
        } else {
            dict = (dictionary *) hollow_list_value;
        }
    }
    return dict->value;
}

int main(){
    char index0[] = "hello, this is a test";
    char index1[] = "hello, this is also a test";
    char index2[] = "hello world";
    char index3[] = "hi there!";
    char index4[] = "this is something";
    char index5[] = "hi there";

    int item0 = 0;
    int item1 = 1;
    int item2 = 2;
    int item3 = 3;
    int item4 = 4;

    dictionary d;
    d = dictionary_create();
    dictionary_write(&d, index0, 21, &item0);
    dictionary_write(&d, index1, 26, &item1);
    dictionary_write(&d, index2, 11, &item2);
    dictionary_write(&d, index3, 13, &item3);
    dictionary_write(&d, index4, 17, &item4);

    printf("%d\n", *((int *) dictionary_read(&d, index0, 21)));
    printf("%d\n", *((int *) dictionary_read(&d, index1, 26)));
    printf("%d\n", *((int *) dictionary_read(&d, index2, 11)));
    printf("%d\n", *((int *) dictionary_read(&d, index3, 13)));
    printf("%d\n", *((int *) dictionary_read(&d, index4, 17)));
    printf("%d\n", ((int) dictionary_read(&d, index5, 8)));
}

不幸的是,您无法复制 list[x] 语法,但这是我想出的最佳选择。

于 2017-03-30T01:34:54.643 回答
-2

在“plain C”中,您可以模仿使用字符串作为索引,但不能以您想要的方式模仿。但是,这样做很少有用,而且主要是使您的代码不可读的好方法。您似乎想要的是能够将字符串键用于字典(或“哈希表”,如果您愿意),并且在 C 中没有内置的数据结构。确切的设计取决于您的想要(事实上,如果这是家庭作业的一部分,您甚至可能不需要使用成熟的哈希表实现,但可能会使用性能较差的静态编码)。

在 a[b] 构造的“索引位置”中使用字符串(OK,char 数组)的示例:

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

据我所知,以上是合法的 C,具有明确定义的输出(字符串“Tss ssi”)。它依赖于 a[b] 被定义为与 *(a+b) 相同的事实。

于 2009-01-06T12:44:14.187 回答