【问题标题】:C++ program with map - Explain the below program how it's working带有地图的 C++ 程序 - 解释下面的程序是如何工作的
【发布时间】:2012-05-07 04:32:56
【问题描述】:

在下面的程序中,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

【问题讨论】:

  • 主函数的损坏签名表明您正在使用不兼容的编译器。是哪个?
  • 添加了 c 标签,因为这实际上是一个 C 问题而不是 C++。
  • 这是一个 C 问题吗? usingnamespacecoutmapstring::,滥用&lt;&gt;都不是C!
  • @pmg,检查OP的实际问题。它与 void* 指针有关,OP malloced 两次,memcpyd 将两个 char* 文本字符串的内容放入其中。您可以将 std::map 替换为数组,将 cout 替换为 printf 并删除所有其余的 C++ 内容,而不会影响主要问题。

标签: c++ dictionary iterator


【解决方案1】:

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

更新——更详细的解释

这里

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

【讨论】:

  • 这就是我在那里所做的。我正在复制并回到主要内容,然后再次调用。但仍然 tmp_data 指向旧数据。
  • @user1044923,不,tmp_data 与此无关。您分配两个不同的内存块,将“Ravindra Kumar”复制到第一个并将其存储在地图中。然后将一系列 R 复制到第二个中,然后放弃它。第二个内存块将永远丢失,因为退出函数后,您没有指向它的指针。
  • 好的。一旦我们将其存储到地图中,我们就无法通过修改 tmp_data 来更改地图内部的值。如果我们将地图声明为非静态的,那么我们可以改变它吗?
  • tmp_data中的地址被malloc改变了,所以在第一个malloc之后,你把地址放到了map中,但是在下一个malloc之后,tmp_data中的那个地址已经改变了,与此无关地图中的地址。这与 tmp_data 是否为静态无关。
  • 如果你以“name_data_map[name]=tmp_data;”结束函数,那么你就有了结果,但你仍然有内存泄漏,而我的答案中的代码没有.
【解决方案2】:

以下代码更简单,似乎可以满足您的需求。是否有任何理由更喜欢 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

【讨论】:

    猜你喜欢
    • 2018-05-17
    • 1970-01-01
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 2023-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多