【问题标题】:Adding string value to map in c++在c ++中将字符串值添加到映射
【发布时间】:2016-01-21 10:55:31
【问题描述】:

我正在尝试将 char 数组值添加到地图中,但在显示 char 数组的值时不会出现,但会显示整数值。 即 ii.first 没有显示,但是 ii.second 显示正确。

这是我正在运行的完整代码,

#include <iostream>
#include <cstring>
#include <map>
#include <utility>

using namespace std;

class map_demo {
public:
    class cmp_str {
    public:
        bool operator() (char const *a, char const *b) {
                        return std::strcmp(a, b) <0;
        }
    };

private:
    typedef map <char*, int, cmp_str> ptype;
    ptype p;

public:
    void set_value() {
        char name[20];
        int empid;

        cout<<"Enter the employee name\n";
        cin.getline(name,20);

        // cout<<"name entered=:"<<name;

        cout<<"Enter the employee id\n";
        cin>>empid;

        this->p.insert(map<char *,int>::value_type(name,empid));
    }

    void get_value() {
        cout << "Map size: " << p.size() << endl;

        for(ptype::iterator ii=p.begin(); ii!=p.end(); ++ii) {
            cout <<"the first="<< (*ii).first << ": " << (*ii).second << endl;
        }
    }
};

//=====================================================================
int main() {

    map_demo  mp1;
    mp1.set_value();
    mp1.get_value();
}

运行代码得到的输出:

Enter the employee name
farhan
Enter the employee id
909
Map size: 1
the first=: 909

这里的first = farhan:909,应该是正确的输出,谁能让我明白我在哪里做错了??

【问题讨论】:

  • 使用std::string,而不是const char*作为密钥。
  • @RichardHodges,先生您好....我也尝试过使用字符串,请问使用 char* 有什么错误。另外,要提到使用的密钥是 char* 而不是 const char*...请验证一次...谢谢...
  • @FarhanPatel char * 用于旧版 C 代码。 std::string 相对于它的优点很多(类型安全、自动内存管理、没有缓冲区溢出、它的重载运算符等)
  • Char * 不会为您管理内存。所以输入的第二个名称将覆盖第一个(您的地图将字符串的地址存储为键,而不是键本身)
  • 看看std::make_pair,用起来更方便。例如p.insert(std::make_pair(name,empid));

标签: c++ dictionary containers


【解决方案1】:

其他提到的问题是char *。同样在您的情况下 char * 变得悬空并且您实际上指向垃圾,其背后的原因是当名称超出范围时内存被释放,并且您仍然指向该内存,您实际上需要复制数据在地图中。

这个有效

// ConsoleApplication1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


#include <iostream>
#include <string>
#include <map>
#include <utility>

using namespace std;
class map_demo
{


public:
    class cmp_str
    {
    public:
        bool operator() (char const *a, char const *b)
        {
            return std::strcmp(a, b) <0;
        }
    };

private:
    typedef map <string, int> ptype;
    ptype p;

public:
    void set_value()
    {
        char name[20];
        std::string inval;
        int empid;

        cout << "Enter the employee name\n";
        cin.getline(name, 20);
        inval = name;
        //cout<<"name entered=:"<<name;

        cout << "Enter the employee id\n";
        cin >> empid;

        //this->p.insert(map<char *, int>::value_type(name, empid));
        this->p.insert(std::pair<string , int>(inval,empid));
    }

    void get_value()
    {

        cout << "Map size: " << p.size() << endl;

        for (auto ii = p.begin(); ii != p.end(); ++ii)
        {
            std::string mysf(ii->first);
            //std::cout << mysf << std::endl;
            cout << "the first=" << mysf << ": " << (*ii).second << endl;
        }

    }

};
int main()
{
    map_demo  mp1;
    mp1.set_value();
    mp1.get_value();
}

只是一个快速修复,可能需要更多的努力才能做得更好。但只是给你一个想法。

如果您需要使用 char * 来执行此操作,那么您可能需要自己批量分配内存,每次您去询问名称时,您都会将其复制到数据结构中并检索指向它的指针。为了正确处理你的数据结构的方式,你的结果会变得多么干净,但核心点是,你需要管理你的内存,复制到一个持久且不会丢失的地方,并存储一个指向该内存的指针,而不是当您退出 set_value() 时释放的内存区域。

【讨论】:

  • @Marco...Thnx 的概念.....但是,如果我错了,请纠正我,字符串 inval 不是你创建的函数 set_value() 的本地,那么如何可以将本地变量添加到地图中..?
  • std::string 提供了复制构造函数,在我的映射中我不是传递指针或引用而是对象本身,这意味着编译器将调用复制构造函数。如果我使用指针或引用,您将遇到同样的问题。在c ++中,数组注意到的不仅仅是带有一点语法糖的指针,用于使用订阅运算符访问值,也就是当您将数组传递给函数时,您传递的是指针,而不是值。 std::string,为你管理内存,分配,移动,复制等
  • 还有@Marco,我们的empid 是函数中的一个局部变量,即使这样也能正常工作……怎么样,因为empid 是一个整数?请澄清这一点......或者插入本地empid是错误的......
【解决方案2】:

这一行

this->p.insert(map<char *,int>::value_type(name,empid));  

向映射添加char* 指针,而不是字符串本身。如果指针 指向堆栈(name[] 在堆栈上),那么它可能是 每次迭代都使用相同的地址。

要么使用 std::string

例如

typedef std::map<std::string, int> ptype;
...
p.insert(std::make_pair(name,empid))

或手动分配动态内存并跟踪字符串

char* nameStorage = new char[strlen(name)+1];
strcpy(nameStorage,name);
p.insert(std::make_pair(nameStorage,empid));

【讨论】:

  • 先生,我同意这个概念,因为你提到 char* 正在变得悬空,因为它是函数本地的,但 empid 也是本地的,但是它被正确分配....为什么会这样?请澄清一下?
  • 指针(数组开始的地址)和整数都是按值复制的,如果是整数,那就是您要复制和存储的内容
【解决方案3】:

您定义了地图的键,例如char *

typedef map <char*, int, cmp_str> ptype;
             ^^^^^

所以在成员函数set_value

void set_value() {
    char name[20];
    int empid;

    //...

    this->p.insert(map<char *,int>::value_type(name,empid));
}

键被分配了本地变量name的地址(更准确地说是数组name的第一个字符的地址),退出函数后将被销毁。

之后该键将失效,因为它将指向一个不存在的字符数组。

此外,键应该是可复制分配的,但数组没有复制分配运算符。

您可以使用标准类std::array&lt;char, 20&gt; 作为键类型。例如

typedef map <std::array<char, 20>, int, cmp_str> ptype;

在这种情况下,您还必须更改 cmp_str 使其接受这种类型的对象。

另一种方法是使用标准类std::string 而不是数组。示例

typedef map <std::string, int> ptype;

【讨论】:

  • 我们的 empid 是函数中的一个局部变量,即使这样也能正常工作……那又如何,因为 empid 是一个整数?请澄清这一点......或者插入本地empid是错误的......
  • @FarhanPatel 存储在地图中的是 empid 对象的副本,而不是其地址。字符数组的情况不同。它是作为键存储的数组名称的第一个字符的地址。退出函数后,数组不存在。所以程序有未定义的行为。
猜你喜欢
  • 2020-07-30
  • 2012-08-21
  • 2018-01-22
  • 1970-01-01
  • 2018-07-09
  • 2023-04-07
  • 2021-11-09
  • 2019-06-09
  • 2012-01-23
相关资源
最近更新 更多