Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
143 views
in Technique[技术] by (71.8m points)

dictionary - C++ program with map - Explain the below program how it's working

In the below program, tmp_data is printing first as : "Ravindra Kumar". But after copying into the map it's changed to "RRRRRRRRRRR". When we print next time, it's still printing "Ravindra Kumar" - how. It suppose to print RRRRRRRR right ?

#include <iostream>
#include <cstring>
#include <string>
#include <map>
using namespace std;

void fun_call( );
main(){
        cout << "printing all data " << endl ;

        fun_call();
        fun_call();

}

void fun_call()
{
      //  static void *tmp_data;
        void *tmp_data;
        char *str="Ravindra Kumar";
        char *str1="RRRRRRRRRRRRRRRRRRRRR";
        char name[]="Ravi";
        char value[100];

        static std::map<std::string,void *> name_data_map;
        std::map<std::string,void *>::iterator iter   ;

        iter=name_data_map.find(name) ;

        if ( iter == name_data_map.end())
        {
        tmp_data = (void *) malloc ( strlen(str)+1 );
        memcpy(tmp_data,str,strlen(str)+1);
        name_data_map[name]=tmp_data;
        cout << "Inside the if" << endl ;
        }
        cout << "Outside the if" << endl ;
        iter=name_data_map.find(name) ;

        memcpy(value,iter->second,strlen(str)+1);
        cout << "value is " << value <<  endl ;
        tmp_data=(void *)malloc(100000);
        memcpy(tmp_data,str1,strlen(str1)+1);

}

output :

$ ./a.out
printing all data
Inside the if
Outside the if
value is Ravindra Kumar
Outside the if
value is Ravindra Kumar
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You copy "RRRRRRRRRRRRRRRRRRRRR" into tmp_data, then exit the function, discarding tmp_data altogether (btw without freeing it, so you have a memory leak there). The next call to fun_call will create a new tmp_data local variable, whose value has no relation to what you set it before to. However, name_data_map is declared static, so it is allocated only once (on the first call to fun_call), and reused afterwards, keeping the value you put into it in the previous call (and that value is in fact a different memory block from the one you copy the R's into later).

Update - a more detailed explanation

Here

    tmp_data = (void *) malloc ( strlen(str)+1 );
    memcpy(tmp_data,str,strlen(str)+1);
    name_data_map[name]=tmp_data;

you allocate a memory block, copy "Ravindra Kumar" into it and store a pointer to it in the map. At this point, name_data_map[name] and tmp_data point to the same memory block. Graphically it might roughly look something like this (assuming, for the sake of simplicity, that the two text literals are stored in memory consecutively, which may or may not be the case in real life):

name_data_map[name] ----
                        ˇ
tmp_data ---------------
                        ˇ
raw memory    ..........Ravindra KumarRRRRRRRRRRRRRRRRRRRRR............

If you modified the contents of that memory block (by e.g. copying a different text into tmp_data) the change would be visible through name_data_map[name] too, since both of these point to the same memory location.

However, this would not work vice versa: after changing the map value, e.g.

    name_data_map[name]=str1;

the program state would look like this:

name_data_map[name] --------------------
                                        ˇ
tmp_data ---------------
                        ˇ
raw memory    ..........Ravindra KumarRRRRRRRRRRRRRRRRRRRRR............

making the two pointers point to different locations, thus a change in one would not affect the other. So note that there is a fundamental difference between changing the value of a pointer, vs changing the value of the memory it points to.

You do exactly the former a few lines later, just with tmp_data:

    tmp_data=(void *)malloc(100000);
    memcpy(tmp_data,str1,strlen(str1)+1);

The first line changes the value of tmp_data, so now it no more points to the same place as name_data_map[name]! After that, whatever you do with the newly allocated memory block, it won't affect name_data_map[name] anymore. This is why you failed to change it.

If we declare the map as non static, than we can change it right ?

Wrong. Declaring your map static has no effect on this - it only affects the scope of your map. A nonstatic map would cease to exist when you exit from fun_call, losing all the values stored in it. While it is alive, you can change its values, regardless of it being static or not. You just need to use the right pointer for it.

If your aim was to change the value stored in the map via tmp_data, just drop the second malloc and modify the first one to allocate a longer block (as str1 is longer than str, so trying to copy str1 into a buffer having the length of str results in buffer overrun, i.e. undefined behaviour). After that, you should have a working - although nasty - code, as it is generally not a good idea to try and modify values in a map "behind its back". Moreover, mixing C constructs (malloc and raw pointers, especially void*) in C++ code is a Bad Idea. If you are only experimenting, it is acceptable - bot please don't ever do this in production code. And your intention was something different, please clarify.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...