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

この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.30

>コンパイル時にクラス型のサイズも確定していて、それが固定値として実行モジュールに書き込まれてしまうと言うことですね? そう言う事です。 なので同じコードだとしても、別の環境で全く同じコードのままコンパイルしたのを使うと、死ぬ可能性があります。 そこはしっかり確認しておく必要があります。

katorea21
質問者

お礼

これに関しては、初歩的な事なのにちゃんと理解してなくて恥ずかしいです。 まあ実際それほど特殊な処理系に持って行くことはあまり想定していないため、普通にINTELの互換CPU上でさえ動作すれば十分かなと。CPUのメカニズムとデータ型のサイズの関係など、そのあたりは正直詳しくないので、必要になったら調べたいと思います。

回答No.29

そんで、テンプレートではなく 一般的に言う「インターフェース」クラス的なことであれば 既に class Base はそんな感じになっていますね。(あとはやりたい一般的な処理の概念の数に応じて仮想関数増やせばいい、という感じで)

回答No.28

>ここまで来ると、Baseはテンプレートクラスにして「A」と言う型を意識しないような作りにしておく方が良いような気もします。(テンプレートというかインタフェースクラス?) 「再コンパイルの手間」ってことを考えると、テンプレートは結構かかりかねないですよ?w 仮に下のコードの構造をBaseクラスの実装を「ヘッダに書かず」「ソースに書く」としとけば 最強にラッキーな仕様変更や実装方法(GetAとかやらずにgetterを個別に書いたうえで)の場合 再コンパイルすべきソースは「たったの一つ」で済む可能性すらあります。 まぁ、GetA()->メンバとかやってたとしても そのソースとBaseクラスのソースだけですみます。 でもテンプレートだと、Baseクラスのヘッダを書き変えることになるので それをインクルードしてるソースは全部再コンパイルの必要が生じます。 「まぁそんな頻繁に目的の構造体は仕様変更されるわけじゃないだろうから良い」なら良いですが また Aに当たる部分をテンプレート化する場合は、SetAやFreeABuf関数など部分を、対応できるようにしとかないといけません。 「テンプレートや関数オブジェクトや関数ポインタの仕様には強い」という自身があれば構いませんが、かなりの技量だとしても結構注意力を要することは確かですね。 これらを踏まえてなお それでいいという明確な理由があるなら、そうしても問題ないと思います。

回答No.27

>再ビルドは必要になります。 もちろん、再ビルドは必要です。 それはkatorea21さんも十分承知なんではないでしょうか?(言葉のあや?) んでもその時に再コンパイルする必要のある箇所がどの程度大きいかは コードの書き方一つで 全然変わってきます。 あ、一応コードで書いてはなかったので >受け渡しするデータ型に値型のデータフィールドしかなければ、ただ単純に=でコピーできますが、どうしても動的にメモリ確保してデータコピーしてやらなければならない場面(ポインタ型フィールド)があるのです。 ↓構造はこんな感じですかね ※実際には分割しておいてください。また、伝えたいのは「構造」の方で、長くなりすぎるのはあれなので、呼び出し側の「単なる簡易実験」コードは非常に分かり辛くなっていますが、実際に「送り手がfreeする部分」については書く必要がないはずですし、実際のコードでは可能な限り分かりやすいように配慮しておいてください。 struct A{ //目的のPODとする double d; void* buf; //確保したメモリ size_t bufsize; //確保したメモリ量 int i; }; class Base { //Aのコピーや内部のポインタの管理は基底クラスが行う A* pa; void FreeABuf() const { free( pa->buf ); pa->buf = NULL; } protected: Base(){ pa = new A; pa->buf = NULL; } public: virtual ~Base(){ FreeABuf(); delete pa; } //このSetAを使うだけで、Aのコピーは出来てしまう。 void SetA( const A* a ) const { FreeABuf(); *pa = *a; pa->buf = malloc(a->bufsize); memcpy( pa->buf, a->buf, a->bufsize ); } const A* GetA() const { return pa; } virtual void Func() = 0; }; class Sub1 : public Base { int i; public: Sub1( const A* a ){ SetA(a); } virtual void Func() override { printf( (char*)GetA()->buf ); } }; /////////////構造ここまで。ここからは呼び出しコード(実験)////////////////// int main(void){ A a1 = { 1.0, NULL, 100, 3 }; a1.buf = malloc(100); strcpy( (char*)a1.buf, "abc " ); Base* b = new Sub1( &a1 ); free(a1.buf); //ここで解放されても問題なし b->Func(); a1.buf = "zzz "; a1.bufsize = strlen("zzz ") + 1; b->SetA( &a1 ); b->Func(); delete b; } 結果 abc zzz 実際には Sub1 b2: b2 = *b; こんな風に、「自分の方でもう一個さらに余分に作る」必要はさすがにないでしょうが 万が一必要になったら Sub1に用意したoperator =のなかで 「SetAを呼び出してから」 派生クラスのメンバは別途コピーすればいい、というだけになります。 また もし派生クラスに「メンバ変数」 が必要なければ 継承はなしで、Baseクラスだけで switch文とかでも事足りるかもしれません。 どっちがより良いかは状況によります。

katorea21
質問者

お礼

再ビルドは少なくとも必要でした。言葉が間違っていました。 言いたかったのは、自作のクラスに手を入れる必要がないと言うことです。これはこれで大きいのです。再ビルドだけなら誰でも出来ますが、コードの修正は分かっている人にしか出来ませんから。 コード例かなりシンプルに分かり易く書いて頂いてありがとうございます。ほぼイメージ通りです。 ここまで来ると、Baseはテンプレートクラスにして「A」と言う型を意識しないような作りにしておく方が良いような気もします。(テンプレートというかインタフェースクラス?)

  • wormhole
  • ベストアンサー率28% (1621/5657)
回答No.26

>その通りです。 「memcpyにしておけば~再ビルドの必要はない」と本当に思われてるのでしたら それは気のせいです。 >memcpy((HOGE*)this, &obj_HOGE_Derived, sizeof(HOGE)); という記述をしている限り再ビルドは必要になります。 sizeofはコンパイル時点のサイズを求める演算子ということを理解されてますか? またクラスにしても基底クラスが変更になったのであれば、 その派生クラスの再ビルドは必要です。 memcpyを使用することで再ビルド、テスト、出荷作業をなくしたいようですが それはなくしたらいけません(なくせません)。面倒がらずにしてください。

katorea21
質問者

お礼

>sizeofはコンパイル時点のサイズを求める演算子ということを理解されてますか? それは、実行時に処理系に応じて必要なメモリサイズを動的に算出して返す演算子だと思っていました。改めて調べて見ると、コンパイル時に固定値になるような事を書いてありました。 となると、コンパイル時の環境に依存した値になるという事ですか?コンパイル時にsizeof(int)が4と評価される環境でコンパイルした実行モジュールを、int型が2バイトの環境に持って行って実行したら、上記のようなコードではその環境における実際のサイズ分コピーできませんね。Javaのように動的にクラスロードするわけではないから、コンパイル時にクラス型のサイズも確定していて、それが固定値として実行モジュールに書き込まれてしまうと言うことですね?

回答No.25

>外部にデータを受け渡す時に、別途メモリを確保してそこにコピーし、渡した先はデータを受け取った後、そのエリアをfreeします。外部とのインタフェースに関しては、そのような仕様になっているので、勝手に変更は出来ません。 なるほど、そういうことですか。 もし「派生クラスにメンバ変数を追加しなくていい」 状況であるならば この状況下では、やはり基本的な処理に関しては そのPOD構造体を扱うための、ラッパーとしての、基底クラス(抽象クラス)に包含で含んでおいて もうちょっと具体的な処理は派生クラスで切り分ける、といった形にしておき 包含しているPODのコピーに関しては 一括=やmemcpyなどがベストな感じに思います。 リファクタリングした方が良さそうな状況だと判明した場合は 既に大量のコードを書いてらっしゃるのでしたら 大変かもしれません。 そこはもう「頑張ってください」、と言うしかありませんが 何年か先になった時に、その見返りは結構なものになる可能性は十分あると思いますから ここでまだ公開されていない現在の状況含め、じっくりとご検討してみてください。

回答No.24

>「基本クラスに変更が入ってもmemcpyにしておけば、 >ポインタの追加でもないかぎりmemcpyの部分のコードに修正しないので >再ビルドの必要がなくなり、 >結果それに伴うテストや出荷などの事務手続きも発生しない」って >ことになりそうなのですが、あってます? 包含であれば、その部分(POD)に対してmemcpyや一括で=でOKですが 継承だと=等で毎回メンバ毎に書くことに で、私(や先人)のお勧めとしては「継承は最小限のが良いんでない?」(そうすりゃ再コンパイルの手間も最小限だし) という流れだと思いますよw

katorea21
質問者

お礼

ご教示頂いている意味がだんだん理解できてきました。 もう一度、元々の目的に立ち返って考え直してみたいと思います。 色々とアドバイスありがとうございました。

回答No.23

>外部から受け取ったデータをクラスで保持する必要があるのです。 なるほど、そのデータはその後「外部から破壊される、あるいは外部から書き換えされる」ものですか? そうであればコピーは確かに必要かもしれません。 でも継承とかの構造に関しては…… 「結合を最小にせよ」というのは、実は私だけが自分の経験からだけで言ってるんじゃなくて 一般的な、C++にディープに触れてる本には、結構書いてあるようなことなんじゃないでしょうか 例えば、今私の手元にある More Exceptional C++(ハーブ・サッター 著 浜田 真理 訳 浜田 光之 監修) とかにもふつーに書いてあります。 p157,p158から少し引用させていただきますと ------------- 以前にも主張したように、経験を積んだ開発者でさえ、継承を使いすぎる傾向がある。ソフトウェアエンジニアリングの健全なるルールは、「結合を最小にせよ」だ。複数の方法でクラス間の関係を表現できる場合、最も弱く、かつ実用上十分な関係を採用しよう。継承は、C++のクラス間の関係としてはほとんど最強であり、これより強い関係はfriendしかない (以下略) 弱い結合は、(例外安全も含め)プログラムの正しさを向上させる。そして、強い結合は、(例外安全も含め)プログラムの正しさの到達可能レベルを下げる。 ------------- こんな感じですよね。 作ってる最中はいいかもしれませんが、ずっと後で見た時や、別の人が見た時 継承使いまくりだと 派生クラスのメンバは、全体として何があるのか って把握するのも苦労しますし 基底クラスに変更があると、全部コンパイルしなおしになりますし… 包含にしとけば、「例外安全にもしやすい」ですから エラーとかに強い構造、あとで機能拡張、バグフィックスがしやすいようにしっかり組み上げようとすると 結局、一部で「最初は」多少長く感じても 総合的に見たときに包含の方がシンプルになりやすい、という感覚です。 もちろん、「意味的に継承が最適」なのであればこの限りではありませんが。

katorea21
質問者

お礼

外部にデータを受け渡す時に、別途メモリを確保してそこにコピーし、渡した先はデータを受け取った後、そのエリアをfreeします。外部とのインタフェースに関しては、そのような仕様になっているので、勝手に変更は出来ません。 継承より包含、に関してはもっと専門書等を当たって調べたいと思います。 ただ、今回の場合は、あくまで内部処理用のユーティリティ的な機能を追加したかっただけの継承なので、包含でも確かに問題はないと思います。 アドバイスありがとうございました。

  • wormhole
  • ベストアンサー率28% (1621/5657)
回答No.22

>はい、作業自体はそれほど時間のかかるものではありませんが、製品ですのでテストや出荷等の事務手続きも伴うためなるべくそういったことは発生しないようにしたいと言うことです。 今までの流れからすると、これって 「基本クラスに変更が入ってもmemcpyにしておけば、 ポインタの追加でもないかぎりmemcpyの部分のコードに修正しないので 再ビルドの必要がなくなり、 結果それに伴うテストや出荷などの事務手続きも発生しない」って ことになりそうなのですが、あってます?

katorea21
質問者

お礼

その通りです。

回答No.21

>こうなっていた場合、aにアクセスするためには、包含を使用する場合、_Bobj.pB->objA.pA->aのような書き方になると思います。 setter/getterを間に挟めば、ますます冗長なコードになります。 それは「概念的に、絶対継承しなくちゃいけない」類の物なのでしょうか? もし「継承する『必然性』」がないのであれば、冗長でもsetter/getterを挟むほうが「後々遥かに楽に」なりますし、直交した概念のものであれば縦のつながりは少なく、横方向に広げられるはずです。 「多重継承」もそうですが「多段な継承」もまた、しすぎるのはお勧めできません。 あるいは「別途データ受け渡し用の構造体」を作って、Getは一本化してしまうという手もあります。 というより、本当にそんなに「継承する必要のあるクラス」 であるなら、インスタンスのコピーをとらないことに集中するのが本筋です。 コピーがぜーーーーーーったいにいるとしたら それは 「全く同じデータ群を持つ巨大なものが2つ以上存在する瞬間がないとぜーーーーーーったいに困る」 というケースのみです。 本当に2つ以上存在する瞬間がないとぜーーーーーーったいに困る状況ですか?

katorea21
質問者

お礼

外部から受け取ったデータをクラスで保持する必要があるのです。これを、内部的に扱いやすいように派生させた型のインスタンスとして保持します。つまり、コピー(代入)が発生します。しかも、基本クラス型→派生クラス型への代入(コピーコンストラクタ)となります。 またその逆もあります。この場合は、派生クラス型→基本クラス型へのコピーとなります。 受け渡しするデータ型に値型のデータフィールドしかなければ、ただ単純に=でコピーできますが、どうしても動的にメモリ確保してデータコピーしてやらなければならない場面(ポインタ型フィールド)があるのです。

関連する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のメモリの取り方が大きすぎる とは思うんですが他にいい手もなくて・・

専門家に質問してみよう