【问题标题】:Map C-style string to int using C++ STL?使用 C++ STL 将 C 风格的字符串映射到 int?
【发布时间】:2016-07-18 22:20:29
【问题描述】:

stringint 的映射工作正常。

std::map<std::string, int> // working

但我想将C-style 字符串映射到int

例如:

char A[10] = "apple";
map<char*,int> mapp;
mapp[A] = 10;

但是当我尝试访问映射到“apple”的值时,我得到一个垃圾值而不是 10。为什么它的行为与 std::string 不同?

【问题讨论】:

  • 那是因为你不比较operator[]中的字符串,而是字符串常量的地址。 std::string 是不同的东西。这就是为什么在C 中使用strcmp 函数来比较字符串,std::map 中的operator[] 使用简单的== 进行比较。
  • @Black Moses 谢谢我明白了。这意味着我将不得不在这样的场景中使用 usr std::string。
  • 不,它没有。这意味着你必须提供一个比较功能。
  • 同意 Marshall Clow 的观点,但 string 已为您完成,因此更容易。 @BlackMoses 也同意 Mephy。把它写下来,稍微说明一下如何使用比较器,你就会得到一个值得赞成的答案。

标签: c++ string dictionary stl


【解决方案1】:
map<char*,int> mapp;

这里的键类型不是“c string”。至少不是,如果我们将 c 字符串定义为“一个字符数组,带有空终止符”。键类型char* 是指向字符对象的指针。区别很重要。您没有在地图中存储字符串。您正在存储指针,而字符串位于其他位置。

除非您使用自定义比较函数对象,否则std::map 默认使用operator&lt;(const key_type&amp;,key_type&amp;)。当且仅当它们指向同一个对象时,两个指针才相等。

以下是三个对象的示例:

char A[] = "apple";
char B[] = "apple";
const char (&C)[6] = "apple"

前两个是数组,第三个是左值引用,它绑定到也是一个数组的字符串字面量对象。作为单独的对象,它们的地址当然也不同。所以,如果你要写:

mapp[A] = 10;
std::cout << mapp[B];
std::cout << mapp[C];

每个的输出都是 0,因为您没有初始化 mapp[B]mapp[C],所以它们的值将由 operator[] 初始化。即使每个数组包含相同的字符,键值也不同。

解决方案:不要使用operator&lt; 来比较指向c 字符串的指针。请改用std::strcmp。对于std::map,这意味着使用自定义比较对象。但是,您还没有完成警告。您仍然必须确保字符串必须保留在内存中,只要它们被映射中的键指向。例如,这将是一个错误:

char A[] = "apple";
mapp[A] = 10;
return mapp; // oops, we returned mapp outside of the scope
             // but it contains a pointer to the string that
             // is no longer valid outside of this scope

解决方案:注意范围,或者只使用std::string

【讨论】:

  • 一个很好的答案,除了mapp[A] = 10; std::cout &lt;&lt; mapp[B]; std::cout &lt;&lt; mapp[C]; 不输出“垃圾”,它输出00 因为std::map::operator[] 插入value_type(key, T()) 如果key 尚不存在。
【解决方案2】:

可以,但是你需要更智能的字符串:

struct CString {
    CString(const char *str) {
        strcpy(string, str);
    }
    CString(const CString &copy); // Copy constructor will be needed.
    char string[50]; // Or char * if you want to go that way, but you will need
                     // to be careful about memory so you can already see hardships ahead.
    bool operator<(const CString &rhs) {
        return strcmp(string, rhs.string) < 0;
    }
}

map<CString,int> mapp;
mapp["someString"] = 5;

但正如您可能看到的,这是一个巨大的麻烦。可能有些事情我也错过或忽略了。

你也可以使用比较函数:

struct cmpStr{
    bool operator()(const char *a, const char *b) const {
        return strcmp(a, b) < 0;
    }
};

map<char *,int> mapp;
char A[5] = "A";
mapp[A] = 5;

但是有很多外部内存管理,如果As 内存消失但映射仍然存在,UB 会发生什么。这仍然是一场噩梦。

只需使用std::string

【讨论】:

  • 在你的最后一个例子中,你的意思是map&lt;char*, int, cmpStr&gt; mapp;
猜你喜欢
  • 2013-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多