Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding string value to map in c++

I am trying to add a char array value into a map, but on displaying the value of char array is not coming, however the integer value is displayed. That is ii.first is not displayed, however ii.second is displayed correctly.

Here is the complete code which I am running,

#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();
}

The output obtained on running the code:

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

Here the first = farhan:909, should be the correct output, can anyone make me understand where I am making it wrong??

like image 468
frp farhan Avatar asked Apr 17 '26 08:04

frp farhan


2 Answers

The problem there as other mentioned is the char *. Also in you case the char * becomes dangling and you are actually pointing to garbage, the reason behind that is that when name goes out of scope that memory is freed, and you are still pointing to that memory, you actually need to copy the data in the map.

this one works

// 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();
}

Is just a quick fix, probably with a bit more effort can be made better. But just to give you an idea.

If you need to do it with char *, then you probably need to allocate memory yourself in bulk, each time you go and ask for a name you copy that in your data struct and retrieve a pointer to it. To properly handle that the way you make your data struct changes a lot in how clean your result will be, but the core point is, you need to manage your memory, copy in a place which will persist and not get lost, and store a pointer to that memory, not to a region of memory freed when you get out of set_value().

like image 92
Marco Giordano Avatar answered Apr 20 '26 07:04

Marco Giordano


This line

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

adds a char* pointer to the map, not the string itself. If the pointer points to the stack (name[] is on the stack) then it will be the potentially the same address in each iteration.

Either use a std::string

e.g.

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

or allocate dynamic memory manually and keep track of the string

char* nameStorage = new char[strlen(name)+1];
strcpy(nameStorage,name);
p.insert(std::make_pair(nameStorage,empid));
like image 39
AndersK Avatar answered Apr 20 '26 07:04

AndersK