-3

次のプログラムがあります。これは、4 つの文字列をマップに保存し、初めて印刷します。今度は、保存された値を取得するためにもう一度実行します。しかし、2 回目の結果は 1 回目の結果と同じではありません。

#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
マップされたすべての値を印刷する
if の内部
ifの外で
キー =disk1 値は ravindradisk1 です
if の内部
ifの外で
キー =disk2 値は ravindradisk2 です
if の内部
ifの外で
キー =disk3 値は ravindradisk3 です
if の内部
ifの外で
キー =disk4 値は ravindradisk4 です
=====================
ディスク位置 disk1
ifの外で
キー =disk1 値は ravindradisk4
ディスク位置 disk2
ifの外で
キー =disk2 値は ravindradisk4
ディスク位置 disk3
ifの外で
キー =disk3 値は ravindradisk4
ディスク位置 disk4
ifの外で
キー =disk4 値は ravindradisk4 です

2回目の反復ですべてのデータが「ravindradisk4」として提供される理由

4

4 に答える 4

3

lenの先頭で 0 に設定されているfun_callため、2 回目の実行で に含まれない場合、は最後に 0 バイトをコピーifします。memcpyしたがって、最初の反復からの最後の入力は、 に関係なく同じままvalueです。main()key

于 2012-04-26T15:13:56.013 に答える
1

コードが有効な (または少し慣用的な) C++ プログラムであることを意図している場合、コードには多くの問題があります。

@starbugs が指摘しているように、結果をコピーするために 2 回目に正しい長さを使用していません。1行の「修正」は変更することです:

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

...に:

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

壊れやすい C 文字列の手法を C++ の方法論に置き換えるのが最適な理由に関するいくつかの基本事項について、私は人々に次のことを示したいと思います。

Bjarne による新しい言語としての標準 C++ の学習 (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 を使用してください。

于 2012-04-26T15:37:52.550 に答える
0

まず、一般的に、/の代わりに/C++を使用することを検討してください。newdeletemalloc()free()

あなたが正確に何を達成しようとしているのか (つまり、値を継続的にコピーする理由) はわかりませんが、長さが設定されていないため、memcpy()何もコピーしません。

この問題に対するもう 1 つの簡単な修正方法は、に格納されているポインターを使用するiter->secondことです (その後、変更してそのマップ エントリを更新できることに注意してくださいdata。したがって、これは望ましくない可能性があります)。

たとえばdata、メインの変数にメモリを割り当てず、この行を変更するだけです

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

*tmp = iter->second;

これでdata、main のポインター アドレスが、マップに格納されたポインター アドレスに設定されます。

于 2012-04-26T15:17:24.867 に答える
0

まず第一に、あなたのコードがどのようにコンパイルされるかさえわかりません。メイン関数には戻り値の型がなく、void/no-return は悪い習慣です。単純な戻り値 0 に対応するように再構築し、戻り値の型を にしintます。

さらに、コンパイルする前にいくつかのインクルードが不足しています (つまり、iostream と文字列)。を使用する代わりにusing namespace std、 std 名前空間から必要なものだけを「プル」してみてください。将来的に命名規則の衝突に遭遇する可能性があるため (そしてそれは多くの頭痛の種になるでしょう)、すべてを持ち込むことは潜在的な危険であり、一般的に悪い習慣です。

手元の問題に戻ります。あなたは、自分の心を実験したり罰したりしていないのであれば、ここでいくつかの非常に悪い習慣を適用しています. 頂点バッファーを移動する作業をしている間でさえ、これほど多くのメモリ コピーとポインターの移動を行うことはできません。そして、割り当てを解放と一致させます。これは、非常に悪いメモリ管理です。C++ では、new/delete を使用します。

データ変数へのポインタのアドレスを渡しているので、*tmp を使用してデータのポインタを簡単に変更できます。

name_data_map は静的であるため、ループを生き延びます。したがって、 の 2 番目のデータ メンバは、iter手元のデータ オブジェクトへの実際のポインタです。2 番目の関数のコードの最後の行を変更するだけです。

*tmp = iter->second;

とにかく、それは私の 2 セントです.私はあなたが何をしようとしているのかさえわかりません。幸運を!

于 2012-04-26T15:39:16.260 に答える