-3

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

#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
打印所有映射值
如果里面
如果在外面
key =disk1 值为 ravindradisk1
如果里面
如果在外面
key =disk2 值为 ravindradisk2
如果里面
如果在外面
key =disk3 值为 ravindradisk3
如果里面
如果在外面
key =disk4 值为 ravindradisk4
======================
磁盘 pos disk1
如果在外面
key =disk1 值为 ravindradisk4
磁盘 pos disk2
如果在外面
key =disk2 值为 ravindradisk4
磁盘 pos disk3
如果在外面
key =disk3 值为 ravindradisk4
磁盘 pos disk4
如果在外面
key =disk4 值为 ravindradisk4

知道为什么第二次迭代将所有数据都提供为:“ravindradisk4”

4

4 回答 4

3

len在 的开头设置为 0 fun_call,因此如果在第二次运行中它没有进入您的ifmemcpy最后复制 0 个字节。所以第一次迭代value的最后main()一个保持不变,不管key.

于 2012-04-26T15:13:56.013 回答
1

如果您的代码旨在成为一个有效的(或远程惯用的)C++ 程序,那么它有很多问题。

正如@starbugs 指出的那样,您第二次没有使用正确的长度来复制结果。单行“修复”将是更改:

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

...至:

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

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

学习标准 C++ 作为一种新语言 (PDF) by Bjarne

一旦您掌握了这一点,您可能更能够接受应该使用 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。

于 2012-04-26T15:37:52.550 回答
0

首先,我什至不确定您的代码是如何编译的。您的 main 函数缺少返回类型,而 void/no-return 只是不好的做法。重组它以适应简单的返回 0 并使其返回类型int

此外,甚至在编译之前就缺少几个包含(即 iostream 和 string)。不要使用 using using namespace std,而是尝试从 std 命名空间中仅“提取”您需要的东西。一般来说,将其全部引入是一种潜在的危险和不好的做法,因为您将来可能会遇到命名约定冲突(这会带来很多麻烦)。

回到手头的问题。如果您不尝试/惩罚您的思想,那么您就是在这里应用一些非常糟糕的做法。即使我正在使用移动顶点缓冲区,我也不会做这么多的内存复制和指针移动。并将您的分配与解除分配相匹配,这是一些非常糟糕的内存管理。而在 C++ 中,我们使用 new/delete。

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

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

*tmp = iter->second;

无论如何,这是我的两分钱......我什至不明白你想要做什么。祝你好运!

于 2012-04-26T15:39:16.260 回答
0

首先,一般来说,C++考虑使用new/delete而不是malloc()/ free()

我不确定你到底想要完成什么(即为什么你不断地复制值),但你没有设置长度,所以memcpy()不复制任何东西。

此问题的另一个简单解决方法是使用存储在其中的指针iter->second(请注意,您将能够修改data并更新该映射条目 - 所以这可能不是您想要的)。

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

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

*tmp = iter->second;

现在将datain main 的指针地址设置为存储在 map 中的指针地址。

于 2012-04-26T15:17:24.867 回答