如何将 int 映射到 C/C++ 中的相应字符串

Posted

技术标签:

【中文标题】如何将 int 映射到 C/C++ 中的相应字符串【英文标题】:how can I map an int to a corresponding string in C/C++ 【发布时间】:2009-12-15 22:05:18 【问题描述】:

我有 20 位数字,我想将它们与字符串相关联。除了使用 switch case 语句来实现这一点之外,还有更快的方法吗?

我需要将 int 转换为相应的字符串,并且数字不一定是打包的。 Qt 中的一些代码也可能有用吗?

示例:以下数字和字符串相互关联,

1:   "Request System Info"

2:   "Change System Info"

10:  "Unkown Error"

【问题讨论】:

数字是否连续?如果是这样,只需使用字符串数组/向量。 我假设“20 个数字”,即整数。您需要 Unicode 才能获得比 '0'-'9' 更多的数字。 注意:没有 C/C++ 之类的东西 ... 答案都是针对 C++ 的。我需要一个 C 实现并且被误导了.. ;) 【参考方案1】:

我推荐 std::map

#include <map>
#include <string>

std::map<int, std::string> mapping;

// Initialize the map
mapping.insert(std::make_pair(1, "Request System Info"));
mapping.insert(std::make_pair(2, "Change System Info"));
mapping.insert(std::make_pair(10, "Unkown Error"));

// Use the map
std::map<int, std::string>::const_iterator iter =
    mapping.find(num);
if (iter != mapping.end())

    // iter->second contains your string
    // iter->first contains the number you just looked up

如果您有一个实现initalizer-list feature of the draft C++0x standard 的编译器,您可以结合地图的定义和初始化:

std::map<int, std::string> mapping = 1, "Request System Info",
                                      2, "Change System Info"
                                      10, "Unkown Error";

std::map 可以很好地扩展到大量条目,因为 std::map::find 在 O(log N) 中运行。拥有hash-map feature of the draft C++0x standard 后,您可以轻松地将其转换为 std::unordered_map,它应该能够在 O(1) 时间内查找内容。

【讨论】:

这是特定于 Windows 的编程吗? @yan - std::map 是标准 C++ 库的一部分,因此任何兼容的编译器都可以使用它。 +1 到 STL 地图,我打算建议它,但你打败了我;) IMO,此示例中的 insert(make_pair) 习语比 @pm100 的 mymap[key]=value 示例更难阅读。严格来说, insert(make_pair) 习惯用法可能会稍微快一些,因为使用括号运算符会导致默认的构造函数调用,但我想知道性能提升是否值得可读性的好处。 Chris,STL 是标准 C++ 库的一部分。 Netjeff,如果被复制的对象是重量级的(例如 std::string),则使用 std::map::insert 而不是 std::map::operator[] 的性能增益可能很大。另外,我不认为任何 C++ 程序员会查看对 map::insert 的调用,并且不知道发生了什么......【参考方案2】:

Qt 还提供了它自己的地图实现 - QMap 和 QHash。

QMap<int, QString> myMap;
myMap[1234] = "Some value";
myMap[5678] = "Another value";

myMap.insert(1234, "Some value");

文档提供了更多示例,但非常易于使用。

【讨论】:

thx,因为我正在制作一个 Qt 应用程序,所以我会使用你的方法,但我的问题一般来说更多的是 C++,所以我将不得不接受另一个答案......希望你不介意(我希望我可以接受 2 个答案 :D)【参考方案3】:

更简单的地图使用方式

std::map<int, std::string> mymap;
mymap[1] = "foo";
mymap[10] = "bar";
// ...
int idx = 10;
std::string lookup = mymap[idx];

【讨论】:

当然实现可以随意实现 map,包括开关、跳转表等(尽管几乎可以肯定会是二叉树) Pm100,标准要求某种二叉树结构。该标准明确禁止跳转表等。此外,在插入时,如果使用 std::map::insert 而不是 std::map::operator[],您将获得更好的性能。 使用 operator[] 进行查找的一个问题是,如果您正在查找的索引不在地图中,它将修改您的地图。【参考方案4】:

如果您正在寻找速度,switch 语句将是最有效的。大多数 C/C++ 编译器会将其实现为二叉树,因此速度非常快。

【讨论】:

20 个密集值可能会出现在跳转表中 - 您的地图和树木都无法应对两次跳转... 似乎也更容易实现 我很确定会实现跳转表,但这是否会使其效率低于 std::map?【参考方案5】:

如果您的字符串在编译时已知,那么您可以在 C 中执行此操作:

#include <stdio.h>

struct message 
    int val;
    const char *msg;
;

int main(void)

    struct message messages[] = 
        1, "Request System Info",
        2, "Change System Info",
        10, "Unkown Error"
    ;
    size_t nmessages = sizeof messages / sizeof messages[0];
    size_t i;

    for (i=0; i < nmessages; ++i) 
        printf("%d : '%s'\n", messages[i].val, messages[i].msg);
    
    return 0;

【讨论】:

其实这不是我需要的 这并不难过,如果错误代码的数量很少并且在编译时已知。当然,对于任何更复杂的事情,这个简单的方案都不是最优的。 @yan:你能解释一下吗?我相信您正在构建一个错误代码和错误消息表,对吧? 我需要能够将您正在使用的索引 i 直接映射到消息,即我从函数调用接收状态变量,我想在消息中插入相关定义而不查看每次都起来。 我需要能够将您正在使用的索引 i 直接映射到消息,即我从函数调用接收状态变量,我想在消息中插入相关定义而不查看每次或使用 switch 语句时,STL 映射都可以正常工作(不要介意他是个小气)。【参考方案6】:

如果您的数字和字符串是常量,则映射将不起作用;它必须被加载。

对于常量和字符串,我推荐一个数组:

struct Entry

   unsigned int  key;
   const char *  text;
;

而对于大数量,使用二分查找算法;否则线性搜索的速度差不多(只要对数组进行排序)。

【讨论】:

【参考方案7】:

类似:?

#include <sstream>
using namespace std;
string f(int i)

    ostringstream oss;
    oss << i;
    return oss.str();

【讨论】:

【参考方案8】:

我一直很喜欢将开关作为控制结构。易于理解和维护。请注意,早期的return 缩短了对break 的需求。

这个例子经过测试并且可以工作:

char* getError(int err)
  switch(err)
    case 1: return "Request System Info";
    case 2: return "Change System Info";
    case 10: return "Unkown Error";
    default: return "Whaaaat!";
     

【讨论】:

【参考方案9】:

在编译时是否知道字符串?如果是这样,请创建地图

std::map 消息;

messages[key] = "一些值"; messages[key2] = "其他值";

如果要从文件中读取它们,那么就像这样

std::ifstream ifile("the file")

while (ifile && !ifile.eof())

  ifile >> key >> value;
  messages[key] = value;

【讨论】:

【参考方案10】:

如果您的数字是连续的(或几乎是连续的),一个简单的字符串数组或向量会很好地工作。

如果数字之间的差距很大,最快的方法可能是std::pair&lt;int, std::string&gt;(或std::pair&lt;int, char *&gt;)的数组。虽然大多数人会自动想到使用二分搜索来进行快速查找,但在这种情况下,要考虑的少量可能性很可能会让线性搜索非常有效地竞争——事实上,它很可能是可用的最快选择。原因很简单:虽然它会进行更多比较,但它避免了除法之类的事情,而且对 20 个整数的比较无论如何都会很快。

编辑:请注意,std::map 可能不是一个非常好的选择。 std::map 通常使用平衡二叉树,这意味着 20 个项目将使用 20 个节点,每个节点通常是单独分配的。除了您需要存储的 int 之外,每个节点通常还包含至少两个指针,因此您存储的数据量大致增加了三倍——所有这些都导致缓存局部性相对较差。鉴于所涉及的项目数量较少,一次缓存未命中将花费超过 20 次比较。

【讨论】:

【参考方案11】:

std::map


再次阅读您的问题,我认为您是说您只有 20 个要映射的数字(您说 20 个数字,这让我想到了非常大的数字)。如果这些都在一个相当小的范围内,那么你最好只使用一个数组。您需要一个与largestIndex - smallestIndex + 1 一样大的字符串指针数组。然后要获取与某个数字关联的字符串,您可以执行以下操作:

std::string GetStatus(int statusID)
    return statusArray[statusID - smallestIndex];

statusArray 变量被初始化为:

void SetStatus(int statusID, std::string description)
    statusArray[statusID - smallestIndex] = description;


void InitStatuses()
    statusArray = new std::string[largestIndex - smallestIndex + 1];
    SetStatus(1, "Request System Info");
    SetStatus(2, "Change System Info");
    SetStatus(10, "Unknown Error");

这将比map 更快,并且非常易于使用。如果您的 ID 差异很大,那就不合适了。

【讨论】:

以上是关于如何将 int 映射到 C/C++ 中的相应字符串的主要内容,如果未能解决你的问题,请参考以下文章

超高性能 C/C++ 哈希映射(表、字典)[关闭]

如何将活动记录类特定属性映射到rails中相应的通用关注方法

Entity Framework 4.1 Code First - 如何将包含实体 ID(外键)的 csv 的字符串映射到相应的实体

如何以编程方式将整数映射到const字符串?

C++中如何将一个字符串(string类型的)映射(转换)到枚举值(enum)

手动将字符串转换为 int 并检查 C/C++ 中是不是发生溢出?