-1

在下面的程序中,tmp_data 首先打印为:“Ravindra Kumar”。但是在复制到地图后,它变成了“RRRRRRRRRRR”。当我们下次打印时,它仍然在打印“Ravindra Kumar” - 如何。它假设打印 RRRRRRRR 对吗?

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

}

输出 :

$ ./a.out
printing all data
Inside the if
Outside the if
value is Ravindra Kumar
Outside the if
value is Ravindra Kumar
4

2 回答 2

2

您复制"RRRRRRRRRRRRRRRRRRRRR"tmp_data,然后退出该函数,完全丢弃tmp_data(顺便说一句,没有释放它,所以那里有内存泄漏)。下一次调用fun_call将创建一个新的tmp_data局部变量,其值与您之前设置的值无关。但是,name_data_map是声明static的,所以它只分配一次(在第一次调用时fun_call),然后重复使用,保留你在上一次调用中放入的值(并且该值实际上是与你复制的不同的内存块R's into later)。

更新——更详细的解释

这里

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

您分配一个内存块,将“Ravindra Kumar”复制到其中并将指向它的指针存储在映射中。此时,name_data_map[name]tmp_data指向同一个内存块。从图形上看,它可能大致看起来像这样(为了简单起见,假设两个文本文字连续存储在内存中,这在现实生活中可能是这样,也可能不是这样):

name_data_map[name] ----
                        ˇ
tmp_data ---------------
                        ˇ
raw memory    ..........Ravindra Kumar\0RRRRRRRRRRRRRRRRRRRRR\0............

如果您修改了该内存块的内容(例如,通过将不同的文本复制到tmp_data中),则更改也将是可见的name_data_map[name],因为它们都指向相同的内存位置。

但是,反之亦然:在更改地图值之后,例如

    name_data_map[name]=str1;

程序状态如下所示:

name_data_map[name] --------------------
                                        ˇ
tmp_data ---------------
                        ˇ
raw memory    ..........Ravindra Kumar\0RRRRRRRRRRRRRRRRRRRRR\0............

使两个指针指向不同的位置,因此其中一个的更改不会影响另一个。因此请注意,更改指针的值与更改其指向的内存值之间存在根本区别。

几行之后,您只需使用以下命令即可完成前者tmp_data

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

第一行改变了 的值tmp_data,所以现在它不再指向同一个地方name_data_map[name]!之后,无论你对新分配的内存块做什么,它都不会再有影响name_data_map[name]了。这就是你没有改变它的原因。

如果我们将地图声明为非静态的,那么我们可以更改它吗?

错误的。声明你的地图static对此没有影响——它只会影响你的地图范围。当您退出时,非静态映射将不复存在fun_call,丢失存储在其中的所有值。当它还活着时,你可以改变它的值,不管它是否static存在。您只需要使用正确的指针即可。

如果您的目标是通过 更改存储在地图中的值tmp_data,只需删除第二个malloc并修改第一个以分配更长的块(因为str1比 长str,因此尝试复制str1到长度为 的缓冲区str导致缓冲区溢出,即未定义的行为)。在那之后,你应该有一个工作 - 虽然讨厌 - 代码,因为尝试“在其背后”修改地图中的值通常不是一个好主意。此外,在 C++ 代码中混合 C 构造(malloc尤其是原始指针)是一个坏主意。void*如果您只是在试验,这是可以接受的——机器人请不要在生产代码中这样做。你的意图是不同的,请澄清。

于 2012-04-26T12:40:29.473 回答
0

以下代码更简单,似乎可以满足您的要求。是否有任何理由更喜欢 char* 而不是 std::string 作为地图中的值?

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

void fun_call()
{
        const char* str="Ravindra Kumar";
        const char* str1="RRRRRRRRRRRRRRRRRRRRR";
        const char* name="Ravi";

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

        iter=name_data_map.find(name) ;

        if ( iter == name_data_map.end())
        {
          name_data_map[name]=str;
          cout << "Inside the if" << endl ;
        }
        cout << "Outside the if" << endl ;
        iter=name_data_map.find(name) ;
        cout << "value is " << iter->second <<  endl ;
        iter->second = str1;
}

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

        fun_call();
        fun_call();
}

输出:

printing all data 
Inside the if
Outside the if
value is Ravindra Kumar
Outside the if
value is RRRRRRRRRRRRRRRRRRRRR
于 2012-04-26T13:37:54.323 回答