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

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

>しかし、その包含したインスタンスでは、基本クラス(実際は構造体ですが)のフィールドにアクセスするためににいちいちgetter/setterを用意するか、aをpublicにして、b.a->dのようにアクセスしなければならないのです。 >まあそうすれば良いだけのことですが、何となくスマートではないなと思ったのと、いわゆるオブジェクト指向的なやり方ではないため、継承を使った構造にしたわけです。 ん~ 「100%の理想の、万全を尽くせるか?」 という観点では、確かにそうなんですよねw 目的のPOD構造体が「自分でいじれるなら」 んでも、「PODの構造体」を、「ある程度別の物」(intなどの単純な値型と同じように考える)と割り切ることによれば、十分オブジェクト指向的だと思いますよ。 下のコードだと、ポイントはクラスBの中の const A* GetA() const { return a; } このメンバにあります。 constなポインタとしてAを公開してるだけなんで クラスB自体はAの内容は、これだけなら知らなくてもいいわけです。 そんで このGetAの呼び出し側で B b(何々); const A* a = b.GetA(); とかやってれば a->メンバ ってな具合で、constに読み取りができます。 で、もし「POD構造体をもう一度」Setしたいんであれば void SetA(const A& a_){ *a = a_; } こんなコードを クラスBに追加してやればいいわけです。 単純ですよね? (もちろん、Aのメンバにポインタがあって、そのディープコピーも行うべきであればもう一行二行程度書く必要はありますが、「それだけである」とはいえます)

回答No.19

失礼、「コメント部分」がまだミスってました B& B::operator=(const B& b){ *a = *b.a; //あるいは memcpy( a, b.a, sizeof a ); return *this; } ↓ B& B::operator=(const B& b){ *a = *b.a; //あるいは memcpy( a, b.a, sizeof(A) ); return *this; } また、PODの構造体を受け渡せるなら、コンストラクタは B::B(double d, int i){ a = new A; a->d = d; a->i = i; } ↓ B::B( const A& a_ ){ a = new A(a_); } のがさらに構造体メンバへの依存度が低いため、良いと思います。 実際にはやはり分割した方が再コンパイルの手間は少ないですが 仮に一つの個所にまとめると こういう感じで良いんではないでしょうか? struct A{ double d; int i; }; class B{ A* a; public: B(const A& a_ ){ a = new A(a_); } B& operator=(const B& b) { *a = *b.a; return *this; } const A* GetA() const { return a; } }; A a = { 2.0, 9 }; A a2 = { 0, 0 }; B b1( a ), b2( a2 ); b2 = b1; printf("%f %d",b2.GetA()->d, b2.GetA()->i);

回答No.18

コピペミスです 下のほう B& B::operator=(const B& b){ *a = *b.a; //あるいは memcpy( a, b.a, sizeof a ); } ↓ B& B::operator=(const B& b){ *a = *b.a; //あるいは memcpy( a, b.a, sizeof a ); return *this; }

回答No.17

う~ん 私の「継承ではなく包含することについての提案」に対してノータッチですが 理解されてますか? >メンバの並びについての話がまさに質問したかった事なんですが、やはり処理系に依存する可能性もあると言うことで、このようなケースでmemcpyは使用しないようにしようと思います。ただ純粋にPOD型の構造体同士のコピーなら、つまりC言語と互換なのでmemcpyが使えると思います。 継承してフィールド追加されたりすると(PODじゃなくなると)メンバの並びの話も出てくるので当然ダメですが、継承じゃなくて包含してれば、そのメンバについてはPODになるのでそこは=やmemcpyで一発で行けるんですが… //POD struct A{ double d; int i; }; class B{ //非POD A a; public: B(double d, int i){ a.d = d; a.i = i; } B& operator=(const B& b) { a = b.a; //あるいは memcpy( &a, &b.a, sizeof a ); return *this; } }; B b1( 2.0, 9 ); B b2( 0, 0 ); // b2.a.d == 0 , b2.a.i == 0 になる b2 = b1; // b2.a.d == 2.0, b2.a.i == 9 になる >基本クラス(構造体ですが)は、5年程度のスパンで見れば割と仕様変更は発生します。またそのような構造体が何十とあります。フィールド一つの変更でも全てビルドし直すのは、結構な手間とコストになるのです。もちろんポインタ変数が追加されればディープコピー処理を追加しなければならないですが。 構造体が自分では変更不可で、かつ変わる可能性がある のなら、「ある程度は仕方ない」ですが 継承ではなく包含になっていれば、たとえ構造体のフィールドが変わったところで 「ポインタ変数が追加されて、しかもその構造体をクラスに対して一つずつ持ってる状況で、しかもクラス全体のコピーが必要になった状況で、しかもそれの参照先のディープコピーも必要になった場合」 という、「整理されたデザインパターン」上で考えればきわめて稀なケースでなければ、上記のとおり=やmemcpyで書いておくことで ほとんど書き変えずにリビルドすればいいだけです。 まして「ポインタによる包含」になっていれば メンバに直接触れてない部分は再コンパイルの必要もないですから 数個のソースぐらいの再コンパイルぐらいしかほとんど手間はないのです。 //Aのクラス定義が書かれてるヘッダはこの時点ではincludeしない struct A; class B{ //非POD A* a; public: B(double d, int i); ~B(); B& operator=(const B& b); }; ///Aが絡むところは、ソースでインクルードしておいてから、ソースに実装を書く/// B::B(double d, int i){ a = new A; a->d = d; a->i = i; } B::~B(){ delete a;} B& B::operator=(const B& b){ *a = *b.a; //あるいは memcpy( a, b.a, sizeof a ); } こうしておけば、このソースを再コンパイルする必要があるだけで 「Bのヘッダ」をインクルードしたソースは無関係です。

katorea21
質問者

お礼

包含ですか。確かにそのようなデータ構造も考えはしました。 しかし、その包含したインスタンスでは、基本クラス(実際は構造体ですが)のフィールドにアクセスするためににいちいちgetter/setterを用意するか、aをpublicにして、b.a->dのようにアクセスしなければならないのです。 まあそうすれば良いだけのことですが、何となくスマートではないなと思ったのと、いわゆるオブジェクト指向的なやり方ではないため、継承を使った構造にしたわけです。

katorea21
質問者

補足

さらに補足しますと、最初にサンプルで挙げたクラスは、中に他のクラス(構造体)型のフィールドが含まれていませんが、実際は他のクラス型(もちろん自作型です)のフィールドが複数含まれています。そして、そのクラスも元の構造体から派生したクラス型を使いたいのです。 包含の考え方ですと、包含したクラス自体がまたさらに別のクラスを包含した型となっており、継承の考え方を使わなければ、入れ子になったクラスのフィールドにアクセスするのにいくつものオブジェクトを経由するような形になり、見た目的にも良くないし、ぱっと見で人間の頭で素直に理解しにくいコードになってしまうような気がします。 class A: { int a; } class _A { A* pA; } class B: { int b; A objA; } class _B { B* pB; } _B _Bobj; こうなっていた場合、aにアクセスするためには、包含を使用する場合、_Bobj.pB->objA.pA->aのような書き方になると思います。 setter/getterを間に挟めば、ますます冗長なコードになります。

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.16

>フィールド一つの変更でも全てビルドし直すのは、結構な手間とコストになるのです。 「修正するのに手間とコストがかかる」ではなく 「ビルドし直すの手間とコストがかかる」なのですか? Makefileなどをちゃんと書いているなら makeを起動しコンパイルが終わるのを待つだけで 手間もコストもないと思うのですが・・・ memcpyでもビルドし直さないといけないのは同じだし。

katorea21
質問者

お礼

はい、作業自体はそれほど時間のかかるものではありませんが、製品ですのでテストや出荷等の事務手続きも伴うためなるべくそういったことは発生しないようにしたいと言うことです。

回答No.15

まぁ、一つのPODの構造体から、同じ型の一つの構造体 での話なら 変数名 = 変数名; でも最適化で同じコードになるかもしれませんし、違うコードが生成されたとしても、計測上の誤差のが勝る事のが遥かに多いんじゃないでしょうか。 memmoveやmemcpyはどっちかっていうと「配列とループ」のかわりに使われることの方が割合はずっと多いんじゃないでしょうか。 「VC++7.1では,PODのポインタに対するcopyはmemmoveで実装されています.」 とかCryoliteさんの日記で見た気がしますが STL使うと その辺意識しなくても良いって言う意味はあると思います。 自分の手では「全く使うコードを書かない」でも、プログラムが書けないわけじゃないです。 (まぁ、あくまで「もしコピーをやんなくて済む手がある状況だったら、それがいっちばん速い」ですw memmoveやmemcpyは最適化が許されてますし、それは相当なものですが 「何もやらない」には確実に勝てませんw)

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.14

>「構造体のサイズ」だけ意識してmemcpyで構造体全体をコピーするようにしておけば、構造体の定義が変わっても修正は不要となります。 だから、それを「省略することに異常にこだわっている」といってるんですけどね。 構造体に追加されるのがポインタ変数だと修正不要ともいえないでしょうし。 正直、私はmemcpy、Cでも文字列やバイナリデータのコピーくらいにしか使わないけど。

katorea21
質問者

お礼

本ケースで確実な方法は、単純にメンバ個別に=で代入することだと分かりましたので、memcpyは使用しないようにしたいと思います。色々とありがとうございました。 ただ補足するなら、基本クラス(構造体ですが)は、5年程度のスパンで見れば割と仕様変更は発生します。またそのような構造体が何十とあります。フィールド一つの変更でも全てビルドし直すのは、結構な手間とコストになるのです。もちろんポインタ変数が追加されればディープコピー処理を追加しなければならないですが。

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

ぶっちゃけた話, C でもそれほど memcpy が必要とは思えない. 単に代入で書いておいて, コンパイラにまかせた方がいいと思うけどねぇ. 配列データのコピーだって std::copy を使う手もある. あれ? よく考えてみたら lpszStr = NULL; ってアウトじゃない? このメンバは HOGE から継承してるんだけど, HOGE で (デフォルトの) private とされているのでアクセスできないはず.... あと, 最後のメンバの並びについては「それぞれのクラスでかたまっている」ように配置しないと困りますよね. 配置する順序は決まっていないと思ういます. つまり, コンパイラによっては「基本クラス→派生クラス」かもしれないしその逆かもしれない.

katorea21
質問者

お礼

ご回答ありがとうございます。 元のクラスHOGEは実際は構造体でした。説明のために多少改変しましたが、lpszStrのディープコピーの部分は質問の本質ではありませんので、適当に書いてしまいましたm(_)m メンバの並びについての話がまさに質問したかった事なんですが、やはり処理系に依存する可能性もあると言うことで、このようなケースでmemcpyは使用しないようにしようと思います。ただ純粋にPOD型の構造体同士のコピーなら、つまりC言語と互換なのでmemcpyが使えると思います。

katorea21
質問者

補足

>ぶっちゃけた話, C でもそれほど memcpy が必要とは思えない. 単に代入で書いておいて, コンパイラにまかせた方がいいと思うけどねぇ 単なる値型のデータならそれで良いし、こんなに悩むことはないと思います。 ただ単純に=で代入すれば良いだけの話しです。 コンパイラがデフォルトの=演算子を定義してくれて、各メンバが全てコピーされるわけですね。しかし、ポインタが含まれているとそうはいかない。そのため=演算子をオーバーロードするわけですが、この中で第二オペランドを=で第一オペランドに代入することは出来ません。(無限ループになる) なので、内部を直接コピーしてやる必要があるのですが、その手段が正しいかどうかの質問でした。

回答No.12

>>それ以外のオブジェクト型をmemcpyでコピーするには常に危険がつきまとうと言う感じでしょうか。 >はい、そう理解しておくのが確実ですね。 おっと、一応 今までのやりとりから、書く必要はないとは思いますが、PODでありさえすればmemcpyやmemmoveなどOKです。

回答No.11

>ただ、基本クラスは外部が設計したクラスで、これを変更することは出来ません。 な~るほど。 >なので、それを内部的に使い勝手の良いように派生クラスを作成したと言うわけです。 派生クラス同士、及び基本クラス⇔派生クラスのコピーは必要になる場面があるのです。 ホントにダメですか?(w 包含じゃ 例) struct A{int i;}; //こいつが目的のPODとして class Base { //別途抽象クラス protected: A a; //または A* a; public: virtual ~Base(){} const A* GetA() const { return &a; } virtual void CopyTo(Base*) const = 0; }; class Sub1 : Base { virtual void CopyTo(Base*) const override { 何々; } }; >それ以外のオブジェクト型を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のメモリの取り方が大きすぎる とは思うんですが他にいい手もなくて・・

専門家に質問してみよう