ポインタのキャストについて

このQ&Aのポイント
  • ポインタのキャストについて説明します。HOGEクラスとHOGE_Derivedクラスについてのコード例を使用して、メモリ上のデータの並びについて説明します。
  • また、HOGE_Derivedクラスで演算子のオーバーロードを行っているコードについても説明します。
  • memcpyを使用したコピーの方法について処理系の依存性や自然さについても考察しています。
回答を見る
  • ベストアンサー

ポインタのキャストについて

下記のようなクラス定義があるとします。 説明のため、関係のない要素は省略し簡略化しています。 class HOGE { int a; char c; LPSTR lpszStr; // メンバ関数定義 } class HOGE_Derived : public HOGE { LPSTR _lpszStr; HOGE_Derived& operator= (HOGE& obj_HOGE); HOGE_Derived& operator= (HOGE_Derived& obj_HOGE_Derived); // メンバ関数定義 } このとき、下記のようなコードで演算子のオーバーロードを行っていますが、これは正しいのでしょうか? HOGE_Derived& HOGE_Derived::operator= (HOGE& obj_HOGE) { memcpy((HOGE*)this, &obj_HOGE_Derived, sizeof(HOGE)); lpszStr = NULL; // lpszStrのディープコピー _lpszStr = new char[strlen(obj_HOGE.lpszStr) + 1]; strcpy(_lpszStr, obj_HOGE.lpszStr); lpszStr = _lpszStr; return *this; } HOGE_Derived& HOGE_Derived::operator= (HOGE_Derived& obj_HOGE_Derived) { memcpy((HOGE*)this, (HOGE*)&obj_HOGE_Derived, sizeof(HOGE)); lpszStr = NULL; // lpszStrのディープコピー _lpszStr = new char[strlen(obj_HOGE_Derived.lpszStr) + 1]; strcpy(_lpszStr, obj_HOGE_Derived.lpszStr); lpszStr = _lpszStr; return *this; } 期待した動作は、まず最初のmemcpyで、obj_HOGEまたはobj_HOGE_Derivedオブジェクトのうち、基本クラス(HOGE)に存在するフィールドint aとchar cのみをコピーしたいのです。 memcpyによってこのようなコピーを行った時、処理系に依存せず期待した通りコピーできるものなのでしょうか? そもそも、このようなコピーの仕方自体、自然なやり方でしょうか? 気になるのは、HOGE_Derivedクラスのオブジェクトのメモリ内のデータの並びがどのようになっているのかと言うことです。 HOGE_Derivedクラスのポインタを、その基本クラスであるHOGE型にキャストした時に、このポインタで見えるエリアが、HOGE_Derivedクラスの中のHOGEクラスの部分だけと言うことは分かっているのですが、その部分のメモリ上の並びが必ず基本クラスの各フィールド→派生クラスで定義されたフィールドの順になっているのかどうか分かりません。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.31

C++(Cの範囲まで含めると)は相当に複雑で また自由度が高い分プログラマの理解と注意力を要求する言語です。 従って 言語仕様とプログラミングの手法、設計全て込みになってくると、もはや 「知らない、分からない事がある方が遥かに普通」と思った方が良いですね。 考えようによってはプログラミングも芸術の一種です。 基本的なことほど、「調べないので逆に案外気づかない」とかいう事もあります。 世の中のC++のプラグラマー全体の内、今回の質問・回答で出てきたこと全ての内容について、なにも参照し直さず すらすら答えられる人など、1%もいないんじゃないかという気がします。 なので、もし今後分からない事が出てきたりしたら、どんどん聞いたり調べたりしてみてください。 そうした方が後で自分が助かります。 まぁ、今回の内容に関してはおそらくほとんど網羅できたんではないかと思いますし、よほどの事がない限り私はここいらで「回答サイド」は一時失礼する、かもしれませんw 何しろ、そろそろ自分のプログラムの方に集中すべき時間になってきたっぽいのでw 数年がかりの物ですが、まさにそろそろクライマックスか!?って感じです。 そんではノシ

katorea21
質問者

お礼

ご自身の作業時間を削ってまでお付き合い頂き、大変ありがとうございました。 改めて基本的な部分から見直すきっかけとなり、大変有意義なQ&Aとなりました。 ベストアンサーは決めにくいので、とりあえず本回答をベストアンサーとして、質問を締め切らせて頂きます。 ご回答頂いた全ての皆様、ありがとうございました。

その他の回答 (30)

回答No.10

>しかし、そうするとC++でmemcpy関数の出番はほとんどないのではないでしょうか? ある型がPODでなくても「ある型のポインタ」はPODですから ポインタの配列だったら移せますし(これが超便利なこともありますし、これだけでもかなりの事が出来ます) そうでなくとも巨大な配列をコピーする必要がある場合だと重宝する可能性があります。 というより、「C++11でわざわざPODの定義の見直しがされた」 ことからもわかるように、パフォーマンスが要求される場面や 標準的な機能を提供するライブラリ(や、それを自作する場合)などでは 十分使える機能です。 もちろん、「コピーその物を最小限」である方が良いプログラムですが、これはその上でさらにもう一歩踏み込む場合に使う、ということです。

katorea21
質問者

お礼

なるほど、そういうことですね。 いずれにしても、単純な値型(ポインタ型も含む)を大量にコピーする際には使えるが、それ以外のオブジェクト型をmemcpyでコピーするには常に危険がつきまとうと言う感じでしょうか。

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.9

>しかし、そうするとC++でmemcpy関数の出番はほとんどないのではないでしょうか? はい、出番はほとんどないと思います。 Cとの互換性のために残ってるようなものと思ってよいかと思います。

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.8

>もう一つ、何度も質問して申し訳ありませんが、最初の質問のサンプルコードで、基本クラス(HOGE)が、クラスではなくPOD型の構造体であったとします。(プリミティブ型の他、ポインタ型も含みます) (以下略) POD型であるなら問題ないと思います。 私ならmemcpyより可能な限り=使いますけどね。 ただまぁ・・・スマートというより、コードの記述量を減らす(省略する)ことに異常にこだわってるだけのように思えるんですけど。 私としてはスマートな記述というのは省略することではなくて 無駄なコードがないことだと思いますが。

katorea21
質問者

お礼

なるほど、確かに=でコピーした方が確実は確実でしょうね。 ただし、メリットはコードの記述量を減らすだけではありません。 メンバ一つ一つを意識したコピーをすれば、メンバが追加になった時はコードの修正が必要になります。 「構造体のサイズ」だけ意識してmemcpyで構造体全体をコピーするようにしておけば、構造体の定義が変わっても修正は不要となります。

回答No.7

う~ん >POD かどうかによらず, 自信をもって大丈夫といえる状況でなければ memcpy は避けるべきじゃないかなぁ. ですよねぇw といって独自operator = を実装したらその段階でPODじゃなくなっちゃうし 緩和されたC++11でさえもこんだけの制限があります http://ja.wikipedia.org/wiki/C%2B%2B11#Plain_Old_Data_.E5.9E.8B.E3.81.AE.E5.AE.9A.E7.BE.A9.E3.81.AE.E4.BF.AE.E6.AD.A3 >メンバ関数 は持っててもいいですが ユーザー定義のコンストラクタ持てません。 仮想関数持てません。(デストラクタも当然、virtualでも独自定義でもいけない) 全ての非静的メンバが、同じアクセス制御じゃないといけません。 従って >外部とのやりとりは基本クラス型のインスタンスで行う必要がある という状況で、しかも基底クラスがPODってことになってると 「本当にどうしても、派生したインスタンスのコピーを行う必要があるかどうか」(参照やポインタだけで済ませないか) とか 現在の構造が「継承の旨みを十分に生かせてないんではないか」というところの方を疑った方が良いように思います。 あるいは「継承じゃなく包含の方が適切ではないか?」という予感もなくはないです。 それらを踏まえてどうしても現状の方法がベストで、operator=が必要なのであれば 全体でのmemcpyなどはあきらめて、ポリモーフィズムやアクセス修飾子の強化といった、継承の旨みを十分に生かすというアプローチで「全体のコードをスマートにする」方が無難だし、確実だし、言語仕様に対して素直な方法に思います。

katorea21
質問者

お礼

おっしゃるとおりですね。 ただ、基本クラスは外部が設計したクラスで、これを変更することは出来ません。 なので、それを内部的に使い勝手の良いように派生クラスを作成したと言うわけです。 派生クラス同士、及び基本クラス⇔派生クラスのコピーは必要になる場面があるのです。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.6

POD かどうかによらず, 自信をもって大丈夫といえる状況でなければ memcpy は避けるべきじゃないかなぁ. 少なくとも, 親クラスに operator = を実装し, 子クラスからはそれを呼び出すようにすれば責任は回避できるよね.

katorea21
質問者

補足

しかし、そうするとC++でmemcpy関数の出番はほとんどないのではないでしょうか? プリミティブ型であれば普通に代入で済みますし、文字列はstrcpyでコピーできます。 プリミティブ型の配列のコピーくらいでしょうか。

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.5

>代入演算子をオーバーロードするよりは、Copy関数のようなものを作って、その中で(コンパイラがデフォルトで作成する代入演算子関数によって)通常の代入を行った上で、ポインタ部分のディープコピーを行う形にした方が良いのでしょうか? 私がもしやる場合ですが、 classとして定義するなら代入演算子をオーバーロードして 面倒でもメンバー一つづつコピーします。 structで定義するならPOD型になるようにした上でメンバは 利用する側からはわからないように必ずポインタで操作するようにし、 そのためのコンストラクタ、デストラクタ、代入演算子に対応する関数を用意します。 >クラスではなく構造体なら上記のようなmemcpyによる代入は問題ないのでしょうか? >C++の場合、クラスも構造体もほぼ同じだと思うのですが。 >違いはデフォルトのアクセス修飾子くらい? POD型を調べれば、おのずとわかりますよ。 私が「POD型」という言葉を知ったのも、この質問に回答してなので 調べるのに30分もいらないと思います。

katorea21
質問者

お礼

POD型調べてきました。 結局メンバ関数が含まれていればPOD型ではないと言うことなのですね。 この場合は構造体でもmemcpyは出来ないと。 もう一つ、何度も質問して申し訳ありませんが、最初の質問のサンプルコードで、基本クラス(HOGE)が、クラスではなくPOD型の構造体であったとします。(プリミティブ型の他、ポインタ型も含みます) 派生クラスのインスタンスを基本クラスのインスタンスにキャストした上で、sizeof(HOGE)バイト分ををmemcpyする分には問題ないのでしょうか? その上で、派生クラスで追加定義したフィールドを個別に手動でコピーすれば、比較的スマートになると思いました。(やはりメモリ上の物理的な並びが問題になる?) そもそも上記サンプルは説明のために多少改変しましたが、実際にはHOGEはPOD型の構造体なのです。この型を使いやすいようにするために、内部処理用として派生クラスを作成してメンバ関数を追加したのでした。ところが、外部とのやりとりは基本クラス型のインスタンスで行う必要があるため、型変換用にoperator=のオーバーロードが必要なのでした。

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.4

>インスタンスコピーにmemcpyを使ってはいけない理由は何でしょうか? >クラスに仮想関数は使用していないため、仮想関数ポインタ等の隠しフィールド(?)が挿入されていることもないと思います。 仮想関数がないからといってCの構造体と互換性があるとはいえないからです。 「POD型」を調べてみてください。 そしてその「POD型」の定義もC++03とC++11では異なります。 >フィールド数が何百もある場合、その一つずつをコピーするコードを書くのは大変だと思うのですが。 そのクラス設計自体がおかしい。

katorea21
質問者

お礼

POD型、調べてみます。 やはりクラスのコピーにmemcpyは使わない方が良いと言うことですね。 =演算子をオーバーロードして、ポインタを含むクラスのコピーをスマートに行おうとしたのですが。 代入演算子をオーバーロードするよりは、Copy関数のようなものを作って、その中で(コンパイラがデフォルトで作成する代入演算子関数によって)通常の代入を行った上で、ポインタ部分のディープコピーを行う形にした方が良いのでしょうか? この場合は、=演算子は使えない(使うといわゆるシャローコピーになってしまう)ため、使わないようにしなければなりませんが。 ちなみにここに似たような質問がありました。 http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1339047348

katorea21
質問者

補足

もう一つお聞きして良いでしょうか? クラスではなく構造体なら上記のようなmemcpyによる代入は問題ないのでしょうか? C++の場合、クラスも構造体もほぼ同じだと思うのですが。 違いはデフォルトのアクセス修飾子くらい?

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

一番の違いは「コンストラクタが呼ばれない」でしょう。 > 気になるのは、HOGE_Derivedクラスのオブジェクトのメモリ内のデータの並びがどのようになっているのかと言うことです。 そういうのが気になるのなら、なおさらmemcpy使わない方がいいでしょう。 どう配置するか、最終的には処理系に依存することですから。 > フィールド数が何百もある場合 これは、また別の問題。そんな無茶な設計自体を見直すのが先です。

katorea21
質問者

お礼

ご回答ありがとうございます。 コード例には省略しましたが、operator=演算子のオーバーロードの中でデストラクタを呼んでいます。内部を一旦クリアしてから、引数(第2オペランド)のデータで初期化しているわけです。 >そういうのが気になるのなら、なおさらmemcpy使わない方がいいでしょう。 どう配置するか、最終的には処理系に依存することですから。 やはりそうですか。要素一つずつコピーしてやるのが確実と言うことですね。 フィールド数に関しては、何百というのは極端でしたm(_)m でも実際10以上はあるので、一つずつ=で代入するのもスマートではないと思いました。

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.2

>インスタンスをmemcpyしているのではなく、インスタンスをコピーする演算子のオーバーロード関数でmemcpyした後、ポインタ部分をディープコピーしようとしています。 代入演算子のオーバーロード関数内だろうが、そうでなかろうが インスタンスをmemcpyしてるのには変わりないです。 >こういう場合は、memcpyではなく、各フィールドを一つずつ代入してやらなければならないのでしょうか? そういうことです。 memcpyしてよいのはプリミティブ型(char,intなど)だけと思ってください。

katorea21
質問者

お礼

インスタンスコピーにmemcpyを使ってはいけない理由は何でしょうか? クラスに仮想関数は使用していないため、仮想関数ポインタ等の隠しフィールド(?)が挿入されていることもないと思います。 外部で直接memcpyを行わないように、=演算子をオーバーロードして、内部的にmemcpyした後、間接参照部分(ポインタ)はディープコピーし、参照先を書き換えています。これでは安全ではないと言うことでしょうか? フィールド数が何百もある場合、その一つずつをコピーするコードを書くのは大変だと思うのですが。

katorea21
質問者

補足

念のため補足しますが、ここで定義しているクラスは完全自作のクラスです。また、中身を知らないオブジェクト型のフィールドはありません。プリミティブ型、ポインタ型、及び自作の他のクラス型のみです。もちろんそのクラスの中身も上記と同様です。 ポインタ型のフィールドに関しては、既に説明済みの通り、一旦memcpyにより値がコピーされますが、直後に参照先をコピーした上でそちらを参照するように書き換えています。

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.1

インスタンスのコピーにmemcpyを使ってはいけません。

katorea21
質問者

お礼

ご回答ありがとうございます。 インスタンスをmemcpyしているのではなく、インスタンスをコピーする演算子のオーバーロード関数でmemcpyした後、ポインタ部分をディープコピーしようとしています。 こういう場合は、memcpyではなく、各フィールドを一つずつ代入してやらなければならないのでしょうか?

関連するQ&A

  • C++のoperator関数でのキャストする場合の書き方がまだよく理解

    C++のoperator関数でのキャストする場合の書き方がまだよく理解できていません。 下記のコードで、 //ここから #include "stdafx.h" #include <string> #include <iostream> class AutoPtr { char *ptr; public: AutoPtr():ptr(0) { } ~AutoPtr() { delete [] ptr; } // char *operator=(char *ptr) { delete [] this->ptr; this->ptr = ptr; return this->ptr; } operator char *(){ return ptr; } char &operator[](int index) { return ptr[index]; } }; void reverse(char *str) { int i, n; AutoPtr work; n = strlen(str); work = new char[n+1]; strcpy(work, str); for(i=0; i<n; i++) { str[i] = work[n-i-1]; } printf("%s\n", str); } int _tmain(int argc, _TCHAR* argv[]) { char str[] = "ABCDEFG"; reverse(str); return 0; } //ここまで 2番目のoperator関数の定義ですが、 operator char *(){ return ptr; } これは多分、reverse()関数中の、 strcpy(work, str); のworkの展開に用いられると思うのですが、 機能としては、「operator char *」はAutoPtrをchar *にキャストするために使われているらしいのですが、何故この書き方でAutoPtrをchar *型にキャストできるのかがいまいち分かりません。また、2番目のoperator関数の記述「operator char *()」はどこまでが型で、どこからが関数の定義と見なせばよいのでしょうか? 何か勘違いしているかもしれません。理解されている方、御教示いただければと思っています。 よろしくお願い致します。

  • C++のコンストラクタを使った自動ポインタでoperator関数の使い

    C++のコンストラクタを使った自動ポインタでoperator関数の使い方で分からないところがあります。 環境下はVisual C++でC/C++のWin32コンソールアプリケーションを使って行っています。 下記のコードで実行させています。やっていることは文字列を反転させて表示させるだけのことです。 #include "stdafx.h" #include <string> #include <iostream> class AutoPtr { char *ptr; public: AutoPtr():ptr(0) { } ~AutoPtr() { delete [] ptr; } // char *operator=(char *ptr) { delete [] this->ptr; this->ptr = ptr; return this->ptr; } operator char *(){ return ptr; } char &operator[](int index) { return ptr[index]; } }; void reverse(char *str) { int i, n; AutoPtr work; n = strlen(str); work = new char[n+1]; strcpy(work, str); for(i=0; i<n; i++) { str[i] = work[n-i-1]; } printf("%s\n", str); } int _tmain(int argc, _TCHAR* argv[]) { reverse("ABCDEFG"); return 0; } これを実行させると、reverse関数のfor()文の、str[i] = work[n-i-1];を実行させた所で実行エラーになってしまいます。その前の、strcpy(work, str);でworkにstrの内容が正常にコピーされているところまでは確認できています。operator関数の、 char &operator[](int index) { return ptr[index]; } で、operator[]はAutoPtrを配列のように扱っているはずなのですが、何故かstr[i] = work[n-i-1]; の所で実行エラーになってしまいます。 operaror関数の書き方が悪いのか、何が原因なのか分かりかねています。御経験のあるかたは、御教示いただけたらと思っています。 よろしくお願い致します。

  • ポインタ(追加質問)

    http://okwave.jp/qa5092628.html の続きです。補足にいれようかとも思いましたが 以前より前の質問は占めたほうがいいと言われつづけてたので 閉めてしまいました。 #include <ctype.h> #include <string.h> #include <stdlib.h> #include <stdio.h> typedef struct{ int number; char *class_type; char *name; char *subject; } my; my *data; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char bufG[1111]; int i, non_value = 0; data = malloc(sizeof(my)*100); //最大100人分とる。それを越えたケースは今は考慮しない。ここを変更 if((fp=fopen("test.txt","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; switch(field){ case 0: data[line].number=atoi(bufG); //ここを変更 break; case 1: data[line].class_type = malloc(strlen(bufG)+1); //これを追加 strcpy(data[line].class_type, bufG); break; case 2: data[line].name = malloc(strlen(bufG)+1); //これを追加 strcpy(data[line].name, bufG); break; case 3: data[line].subject = malloc(strlen(bufG)+1); //これを追加 strcpy(data[line].subject, bufG); break; } field++; } else{ str++; non_value++; if(non_value == 2){ switch(field){ case 0: data[line].number=' '; //ここを変更 break; case 1: data[line].class_type = malloc(3); //これを追加 strcpy(data[line].class_type, " "); break; case 2: data[line].name = malloc(3); //これを追加 strcpy(data[line].name, " "); break; case 3: data[line].subject = malloc(3); //これを追加 strcpy(data[line].subject, " "); break; } non_value = 0; str++; field++; } } line++; field = 0; } //ここはおまけ for (i =0; i < line;i++){ printf("%d:%s:%s:%s\n", data[i].number,data[i].class_type,data[i].name,data[i].subject); } fclose(fp); return 0; } 前回載せてもらった解答ではcsvファイルに空欄があると 値が代入されなかったのでその機能をつけました。 具体的には,が連続してあると(csvファイルに空欄がある場合1,A,,数学のように,と,の間には何もない)場合半角スペースを入れてます。 この場合例えば1,A,,数学のように名前の欄を空白にするとdata[0].name は半角スペースが入ってますが その次の値、すなわちdata[0].subjectの値がばぐった値になっています。 改善方法を教えて下さい。 もう1点あります。上のソースでは data = malloc(sizeof(my)*100); //最大100人分とる。それを越えたケースは今は考慮しない。ここを変更 とありますがこれを while(fgets(buf,1000,fp) != NULL){ str = buf; data = malloc(sizeof(my)*100); ←このへんに  if(line > 100)){ //メモリ追加処理 } のようにすることは可能ですか?

  • return *this

    c++言語勉強中のものです。あるクラスのオブジェクトをobj とし、動的確保された メモリ領域pにobj をコピーするときコピーコンストラクターではメンバ関数は strcpy ( p. obj ); で終わるのに対し、代入演算子による代入コピーでは同じく strcpy ( p. obj ); の次に return (* this ); が追加され参考としているweb 資料では その目的は、「これは決まり文句 」で済ませていますが私には return ( *this )が 何故コピーコンストラクタの処理文には無く代入演算子処理文末尾にはあるのかわかりません。上記理由を教えていただければありがたいです。

  • ライブラリ関数

    文字列をコピーする(strcpy) 文字列の長さを調べる(strlen) 配列の長さを調べる(sizeof) #include <stdio.h> #include <string.h> int main(void) { char s1[128] = "ABCD"; char s2[128] = "EFGH"; char s3[128] = "IJKL"; strcpy(s2, s1); strcpy(s3, s2); puts("s1をs2にs2をs3にコピーしました。"); printf("s1 = %s\n", s1); printf("s2 = %s\n", s2); printf("s3 = %s\n", s3); printf("文字列%sの長さは%uです。\n",s3,(unsigned)strlen(s3)); printf("文字列%sの長さは%uです。\n",s3,strlen(s3)); return (0); } char *strcpy(char *d, const char *s) { while (*d++ = *s++) printf("pointer=%s \n",d); } /* 文字列sをdにコピーする[配列版] */ char *strcpy(char d2[], const char s2[]) { unsigned i=0; while (d2[i] = s2[i]){ i++; printf("hairetsu=%s\n",&d2[i]); } } /*--- 文字列strの長さを返す[ポインタ版] ---*/ size_t strlen(const char *s) { size_t len = 0; while (*s++) len++; return (len); } /*--- 文字列strの長さを返す[配列版] ---*/ unsigned strlen(const char str[]) { unsigned len = 0; while (str[len]) len++; return (len); } c:\program files\microsoft visual studio 8\vc\include\string.h(73) : 'strcpy' の宣言を確認してください。 メッセージ: 'This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.' c:\program files\microsoft visual studio 8\vc\include\string.h(73) : 'strcpy' の宣言を確認してください。 メッセージ: 'This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.' c:\documents and settings\owner\my documents\visual studio 2005\projects\test8-3\test8-3\test8-3.c(48) : error C2084: 関数 'char *strcpy(char *,const char *)' は既に本体を持っています。 c:\program files\microsoft visual studio 8\vc\include\string.h(73) : 'strcpy' の前の定義を確認してください c:\documents and settings\owner\my documents\visual studio 2005\projects\test8-3\test8-3\test8-3.c(68) : error C2084: 関数 'size_t strlen(const char *)' は既に本体を持っています。 c:\program files\microsoft visual studio 8\vc\include\string.h(80) : 'strlen' の前の定義を確認してください 上記の問題が解決できません。助けてください><

  • sizeof が分かりません!

    Cの予約語で"sizeof"がありますが、 普段おきまりで良く使っているのですが、 いまいち理解出来ないので誰か教えて下さい。 例えば、以下の場合sizeofの結果はどうなりますか? char s_aaa[]="ABCDE"; char s_bbb[4]; memset(s_bbb, '\0', sizeof(s_bbb)); memcpy(s_bbb, s_aaa, sizeof(s_bbb)); printf("s_aaa → :[%d],[%d]\n", strlen(s_aaa), sizeof(s_aaa)); printf("s_aaa → :[%d],[%d]\n", strlen(s_bbb), sizeof(s_bbb));

  • operator +()について

    --------------------------------------- 文字列クラスを作りたいと思っています。 以下のようなところまでは作れましたが、 全てのstrをdelete[] str;しているのかわかりません。 delete[] str;を確認するにはどうすればいいですか? --------------------------------------- #include<stdio.h> #include<string.h> #include<conio.h> class stt { public: char *str; int len; bool maked; stt::stt() { len=0; str=NULL; maked=false; } stt::~stt()// ちゃんとデストラクタ内で、全てのstrがdeleteされているのでしょうか? { if(maked) { delete[] str; } else { maked=true; } } stt &operator =(char *c) { if(maked) { delete[] str; maked=false; } len=strlen(c); str=new char[len+1]; strcpy(str,c); maked=true; return (*this); } stt &operator =(stt &ste) { if(maked) { delete[] str; maked=false; } len=strlen(ste.str); str=new char[len+1]; strcpy(str,ste.str); maked=true; return (*this); } stt operator +(stt ste) { stt tet; int len1=strlen(str); int len2=strlen(ste.str); tet.str=new char[len1+len2+2]; strcpy(tet.str,str); strcat(tet.str,ste.str); tet.str[len1+len2+1]='\0'; ste.maked=false;//不安部分 return tet; } virtual operator char*() { return str; } }; int main() { stt ss,ww,pp; ss="a"; ww="b"; pp=ss+ww; printf(pp); printf("\n"); getchar(); return 0; }

  • 文字列クラスを作りたいと思っています。-2

    文字列クラスを作りたいと思っています。 以下のようなところまでは作れましたが、 エラーがでてしまいます。 どこかおかしいところがあるのでしょうか? ********************************************** #include<stdio.h> #include<string.h> #include<conio.h> class stt { public: char *str; int len; bool maked; stt::stt() { len=0; str=NULL; maked=false; } stt::~stt() { delete[] str; } stt &operator =(char *c) { if(maked) { delete[] str; maked=false; } len=strlen(c); str=new char[len+1]; strcpy(str,c); maked=true; return (*this); } stt &operator =(stt &ste) { if(maked) { delete[] str; maked=false; } len=strlen(ste.str); str=new char[len+1]; strcpy(str,ste.str); maked=true; return (*this); } stt operator +(stt ste) { static stt tet; int len1=strlen(str); int len2=strlen(ste.str); tet.str=new char[len1+len2+2]; strcpy(tet.str,str); strcat(tet.str,ste.str); tet.str[len1+len2+1]='\0'; return tet; } virtual operator char*() { return str; } }; int main() { stt ss,ww,pp; pp="Hello"; ss="Nice to meet you.\n"; ww="I am studing Visual C++"; pp=ss+ww; printf(pp); getchar(); return 0; } **********************************************

  • 構造体の配列のアロケート等の方法

    基本的な事かもしれないのですが、 構造体の配列をダブルポインタで返すような関数を作成したいのですが、アロケートの仕方と、そもそも配列をダブルポインタで扱う方法が良く分かってないのかもしれません。 どなたかご教授頂けないでしょうか? Webで調べてもなかなか合ったものが見つからないため、こちらに質問させて頂きました。 イメージしているものを↓に途中まで作ってみました。これも合っていない部分があるかもですが。。。 要はアロケートして構造体の配列を作成する部分と、それをfor文で回して参照する方法が、分かっていない主なところです。 #include <stdio.h> #include <memory> typedef struct member{   int  id;   char*  name; } *member_t; int get_result(member_t *pobj) {   member_t* obj = NULL;   obj = (member_t*)malloc(sizeof(member_t));   memset(obj, 0x00, sizeof(member_t));   char* nm = NULL;   char cnmtmp[] = "nakayama";   nm = (char*)malloc(strlen(cnmtmp)+1);   memset(nm, 0x00, strlen(cnmtmp)+1);   memcpy(nm, cnmtmp, strlen(cnmtmp));   obj->id = 100;   obj->name = nm;   *pobj = obj;   return 0; } int get_resultList(member_t **ppobj) {   /*    * ココ    */   return 0; } void main() {   member_t* obj = NULL;   get_resultList(&obj);   for(int i = 0;;){     /*      * ココ      */     printf("[%d]\n",i+1);     printf("ID : %d\n", ->id);     printf("NAME : %s\n", ->name);     free( ->name);     free( );   }   free(obj); } 長々とすみません。

  • ポインタ(続)

    http://okwave.jp/qa5092628.html の続きです。 #include "stdafx.h" #include <ctype.h> #include <string.h> #include <stdlib.h> typedef struct { int number[6]; char *class_type; char *name; char *subject; } my; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char *bufNum,*bufClass,*bufName,*bufSub; int i; if((fp=fopen("test.txt","r"))==NULL){ printf("ファイルが開けません"); } my *data; data = (my *)calloc(112, sizeof(my)); if(!data){ printf("memoryが足りません\n"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; bufNum = (char *)malloc(strlen(buf) + 1); bufClass = (char *)malloc(strlen(buf) +1); bufName= (char *)malloc(strlen(buf) + 1); bufSub = (char *)malloc(strlen(buf) +1); while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ switch(field){ case 0: *bufNum = *Str; data[line].number[line] = atoi(bufNum); break; case 1: *bufClass= *str; data[line].class_type = bufClass; break; case 2: *bufName = *str; data[line].name = bufName; break; case3: *bufSub = *str; data[line].subject = bufSub; break; } } str++; } switch(field){ case 0: bufNum[i] = '\0'; break; case 1: bufClass[i] = '\0'; break; case 2: bufName[i] = '\0';break; case 3: bufSub[i] = '\0'; break; } field++; } else{ str++; } } line++; field = 0; } printf("%s", data[0].name); fclose(fp); return 0; } と作ってみましたがまぁこれも上手く動かないんですが・・ 1、構造体をつくる 2、構造体のメモリをとる 3、ファイルをよみこむ 4、ポインタで宣言した構造体のメンバのメモリをとり実体をつくる 5、一行ずつよみこむ 6、カンマごとに格納 7、格納後終端文字を入れる 格納の区別はカンマごとにfieldを+しfieldの値にて行なう lineは行数 8,printfでテスト表示 終わり という一連のプログラムです。 class_typeまでは正常にでるんですが nameからが入っていません。 他にもここが微妙とかいうのがあったら教えて下さい。 個人的にはbufNum~bufSubのメモリの取り方が大きすぎる とは思うんですが他にいい手もなくて・・