带有map的C ++程序没有给出与上次存储相同的结果

时间:2012-04-26 14:53:31

标签: c++ map iterator

我有以下程序,它在地图中存储四个字符串并第一次打印。现在它再次运行以检索存储的值。但第二次结果与第一次结果不同。

#include <map>
using namespace std;

void fun_call(void **,char * );
main(){
        void *data=NULL;
        char value[100];
        int i=0,j=0;

        char key[][10]={"disk1","disk2","disk3","disk4"};

        cout << "printing all mapped values " << endl ;
        data = (void *) malloc( 100);

        for(j=0;j<2;j++){
        for(i=0;i<4;i++){
                fun_call(&data,key[i]);
                memcpy(value,data,100);
                cout << "key ="<<key[i]<<" value is " << value << endl;
        }
        cout <<"====================="<< endl;
        }
}

void fun_call(void **tmp,char name[10])
{
        void *tmp_data;
        char str[100]="ravindra";
        int len =0;

        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())
        {
                len=strlen(str)+strlen(name)+1;
                tmp_data = (void *) malloc ( len );
                strcat(str,name);
                memcpy(tmp_data,str,len);
                name_data_map[name]=tmp_data;
                cout << "Inside the if" << endl ;
        }
        else
                cout << "disk pos "<< iter->first << endl;
        cout << "Outside the if" << endl ;
        iter=name_data_map.find(name) ;
        memcpy(*tmp,iter->second,len);

}

输出:

$ ./a.out
printing all mapped values
Inside the if
Outside the if
key =disk1 value is ravindradisk1
Inside the if
Outside the if
key =disk2 value is ravindradisk2
Inside the if
Outside the if
key =disk3 value is ravindradisk3
Inside the if
Outside the if
key =disk4 value is ravindradisk4
=====================
disk pos disk1
Outside the if
key =disk1 value is ravindradisk4
disk pos disk2
Outside the if
key =disk2 value is ravindradisk4
disk pos disk3
Outside the if
key =disk3 value is ravindradisk4
disk pos disk4
Outside the if
key =disk4 value is ravindradisk4

任何想法为什么第二次迭代给出所有数据:“ravindradisk4”

4 个答案:

答案 0 :(得分:3)

lenfun_call的开头设置为0,因此如果在第二次运行中它不会进入ifmemcpy复制0个字节结束。因此,无论value如何,第一次迭代中main()的最后key都保持不变。

答案 1 :(得分:1)

如果您的代码是有效的(或远程惯用的)C ++程序,那么您的代码有很多问题。

正如@starbugs指出的那样,你没有在第二次使用合适的长度来复制你的结果。单行“修复”将改变:

memcpy(*tmp,iter->second,len);

...为:

memcpy(*tmp,iter->second,strlen((char*)iter->second)+1);

关于为什么脆弱的C字符串技术最好用C ++方法取代的一些基础知识,我想向人们展示:

Bjarne

Learning Standard C++ As A New Language (PDF)

一旦你掌握了,你就可以更好地接受应该使用C ++和标准库的精神。

您的程序非常简单,很容易展示如何简化它以生成更加健壮且易于阅读的惯用代码:

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

using namespace std;

string fun_call(string name)
{
    static map<string,string> name_data_map;

    map<string,string>::iterator iter;
    iter = name_data_map.find(name);

    if (iter == name_data_map.end()) {
        string mapvalue = "ravindra";
        mapvalue += name;
        name_data_map[name] = mapvalue;
        cout << "Inside the if" << endl ;
    }
    else
        cout << "disk pos "<< iter->first << endl;

    cout << "Outside the if" << endl;
    iter = name_data_map.find(name) ;
    return iter->second;
}

int main() {
    string keys[] = {"disk1","disk2","disk3","disk4"};

    cout << "printing all mapped values " << endl ;

    for(int j = 0; j < 2; j++) {
        for(int i = 0; i < 4; i++){
            string value = fun_call(keys[i]);
            cout << "key =" << keys[i] <<" value is " << value << endl;
        }
        cout << "=====================" << endl;
    }
}

我将在那里提供一个基本相同的程序,具有相同的输出和控制流程。

注意:

  • 在标准C ++中,main必须有一个int作为返回类型(虽然它不需要参数或return语句,奇怪的是)

  • using namespace std;行使您无需在标准库类前面的事物前面键入std::,如字符串,映射及其迭代器。但是不要把它放在头文件中,因为它可能会导致包含它们的其他源文件出现问题,并且在没有歧义的情况下有自己的定义可能与标准名称冲突。

  • 如果您使用标准库,那么值类型会在内部进行内存管理,并且它们使用的内存将在类中分配并在析构函数中释放。如果您需要进行显式内存管理,请使用new和delete。

答案 2 :(得分:0)

首先,一般情况下,C++考虑使用new / delete代替malloc() / free()

我不确定您要完成的是什么(例如,为什么要连续复制值),但您没有设置长度,因此memcpy()不会复制任何内容。

此问题的另一个简单修复是使用存储在iter->second中的指针(请注意,您可以修改data然后更新该地图条目 - 所以这可能不是您想要的)。

例如,不要为main中的data变量分配内存,只需更改此行

即可
memcpy(*tmp, iter->second, len);

*tmp = iter->second;

现在main中data的指针地址被设置为存储在地图中的指针地址。

答案 3 :(得分:0)

首先,我甚至不确定您的代码是如何编译的。你的主要功能缺乏一个返回类型,无效/不返回只是不好的做法。重构它以容纳0的简单返回并使其返回类型为int

此外,在编译之前缺少几个包含(即iostream和string)。而不是使用using namespace std,尝试仅从std命名空间“拉”你需要的东西。总而言之,这是一个潜在的危险和不良做法,因为您将来可能会遇到命名约定冲突(这会带来许多麻烦)。

回到手头的问题。你是,如果你没有试验/惩罚你的思想,在这里应用一些非常糟糕的做法。这个大量的内存复制和指针移动我甚至在我正在使用移动顶点缓冲区时都无法做到。并将您的分配与解除分配相匹配,这是一些非常糟糕的内存管理。在C ++中,我们使用new / delete。

由于您传入指向数据变量的指针的地址,因此您可以使用* tmp简单地修改数据的指针。

由于您的name_data_map是静态的,因此它可以在循环中存活。因此,iter的第二个数据成员是指向手头数据对象的实际指针。只需更改第二个函数的最后一行代码:

*tmp = iter->second;

无论如何,这是我的两分钱......我甚至没有得到你想要做的事情。祝你好运!