【问题标题】:Translation array翻译数组
【发布时间】:2017-01-18 02:40:16
【问题描述】:

我需要做一个简单的翻译器。例如:

  • 输入:“foo” 输出:“bar”
  • 输入:“the” 输出:“teh”
  • 输入:“what” 输出:“wut”

我知道我可以这样写:

if (!strcmp(input, "foo"))
    puts("bar");
else if (!strcmp(input, "the"))
    puts("teh");
else if (!strcmp(input, "what"))
    puts("wut");

但这又大又乱。有没有捷径可以做到这一点?我知道在 PHP 中(对不起,不可避免的语法错误,我不精通)有这样的东西:

value = array(
    "foo" => "bar",
    "the" => "teh",
    "what" => "wut"
);

如何使用 PHP 数组之类的东西缩短原始代码?

【问题讨论】:

    标签: c arrays string


    【解决方案1】:

    您可以定义一个struct,其中包含单词和翻译:

    typedef struct {
        const char *word;
        const char *translation;
    } translate_t;
    

    然后你可以像这样创建一个结构数组:

    const translate_t translate[] = {{"foo", "bar"},
                                     {"the", "teh"},
                                     {"what", "wut"}};
    

    如果你想打印出单词和翻译,那么你可以这样做:

    size_t size = sizeof translate/sizeof *translate;
    
    for (size_t i = 0; i < size; i++) {
        printf("Word: %s Translation: %s\n", translate[i].word, translate[i].translation);
    }
    

    将输出:

    Word: foo Translation: bar
    Word: the Translation: teh
    Word: what Translation: wut
    

    这是将单词与翻译相关联的好方法。

    更新:@Olaf 建议为size 使用宏,这对于声明数组的大小要好得多。因此,上述代码可以表示为:

    #define ARRAY_SIZE(x) ((sizeof x)/sizeof *x) /* near top, or before main() is a good place for this */
    
    for (size_t i = 0; ARRAY_SIZE(translate); i++) {
        printf("Word: %s Translation: %s\n", translate[i].word, translate[i].translation);
    }
    

    【讨论】:

    • 一个补充:如果您指向字符串文字,请使用const char *。作为其他读者的旁注:数组长度(size = ...)的计算是宏的一个很好的候选者(我想知道为什么 C11 死不添加这个,就像他们添加了offsetof)。
    • @Olaf 添加了constsize_t size 的宏。感谢您的建议。
    • 好吧,旁注并不是我希望您为该示例添加的任何内容,但很高兴看到您认真对待我的评论:-)。这更像是对读者的一般性建议。挑剔:lengthof/length_of(就像在 Linux 内核中一样)可能是一个更好的名字;毕竟size 太接近sizeof/size_t`。 (你已经拿到了我的 UV,无需编辑 ;-)
    【解决方案2】:

    发现了:

    const char *Translate[] = {
        "foo",  "bar",
        "the",  "teh",
        "what", "wut"
    };
    
    int t_idx(char *s)
    {
        int i;
        for (i = 0; Translate[i]; i += 2)
            if (!strcmp(Translate[i], s))
                return i+1;
    
        return -1;
    }
    
    const char *translate(char *s)
    {
        int idx = t_idx(s);
    
        return (idx == -1) ? s : Translate[idx];
    }
    

    translate的返回值:

    translate("what") = "wut"
    translate("some") = "some"
    translate("foo")  = "bar"
    

    【讨论】:

    • “诀窍”在哪里?为什么不也创建数组const
    • 请注意,您的代码会愉快地践踏数组的末尾。在循环条件中定义enum { NUM_TRANSLATE = sizeof(Translate) / sizoef(Translate[0]) }; 并测试i &lt; NUM_TRANSLATE,或者在数组末尾添加一个(或两个)NULL 指针。不过,结构可能更好。
    • 这不是技巧,而是糟糕的编码风格。正如@JonathanLeffler 所写,struct 将是更好的方法。 C 确实支持不同类型的复合数据类型 - 使用它们。
    • 您为什么忽略解决您问题的帖子?它们可能具有指导意义。
    • 请随意思考。但是,如果您以专业程序员的身份编写此类代码,请准备好与您的老板进行一次非常认真的谈话。如果你问一个自我回答的问题,你至少应该公平地接受另一个比你的答案更好的答案并接受那个。
    【解决方案3】:

    标准 C 中没有 map 或关联数组类型;你必须自己实现它。一个简单的想法是使用struct:

    #include <string.h>
    #include <stdio.h>
    
    struct map {
      struct map_elem {
        char *key;
        char *value;
      } * elem;
      size_t size;
    };
    
    int main(void) {
      struct map_elem map_elem[] = {
          {"foo", "bar"}, {"the", "teh"}, {"what", "wut"}};
    
      struct map const map = {map_elem, sizeof map_elem / sizeof *map_elem};
    
      char input[] = "foo";
    
      for (size_t i = 0; i < map.size; i++) {
        struct map_elem *elem = map.elem + i;
        if (strcmp(input, elem->key) == 0) {
          puts(elem->value);
          break;
        }
      }
    }
    

    当然,这只是一个小例子。

    【讨论】:

    • @JonathanLeffler The stdlib.h and stddef.h header files define a datatype called size_t,在这里并不重要,因为 string.hstdio.h 包含它。感谢纠正我的错别字。
    • &lt;stdio.h&gt;&lt;string.h&gt; 也是如此……所以在这种情况下你不需要&lt;stddef.h&gt;。如果你使用offsetof(),你需要它;如果您没有任何“强大的三重奏”(&lt;stdio.h&gt;&lt;stdlib.h&gt;&lt;string.h&gt;),您可能需要它用于size_tNULL;如果您使用ptrdiff_twchar_tmax_align_t,您可能需要它。不过,通常情况下,您不必担心。
    • 一个间接的太多了。为什么不写 const 正确的代码呢?
    • @Olaf 什么是间接过多,为什么? “为什么不写 const 正确的代码?”,你想成为 const 什么?顺便说一句,我们没有进行代码审查。
    • @Stargateur:从什么时候开始提供 good 代码用于代码审查? “你想成为什么const” - 你有非const 指向字符串文字的指针。这是一个允许的遗产,几十年来不应该使用,而且绝对不适合初学者。额外的间接是内部struct。无需嵌套structs;在定义中使用数组并从数组中计算length_of。表示:代码不正确。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-14
    • 1970-01-01
    • 2017-01-01
    • 2016-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多