Cの構造体とポインタのmalloc


84

ベクトルの長さとその値を表す構造を次のように定義するとします。

ここで、ベクトルyを定義し、それにメモリを割り当てたいとします。

インターネットで検索したところ、xにメモリを個別に割り当てる必要があることがわかりました。

しかし、y-> xにメモリを2回割り当てているようで、1つはyにメモリを割り当て、もう1つはy-> xにメモリを割り当てているようで、メモリの浪費のようです。コンパイラが実際に何をするのか、yとy-> xの両方を初期化する正しい方法を教えていただければ幸いです。

前もって感謝します。


5
paxdiabloが著名に指摘しているようにmalloc()、Cの戻り値をキャストしないでください。なぜ誰もがそうする必要があると感じるのか理解できません。:(
2013

14
@unwind、多分彼らはCにアップグレードする古いC ++プログラマーです:
paxdiablo 2013

@unwind CコードでNvidiaのnvccコンパイラを使用しているときに、mallocの結果をキャストしないと、エラーがスローされます。
Nubcake 2017

@Nubcakeこのリンクによると、CUDAインターフェイスがC ++であるため、nvccが基盤となるコンパイラをC ++モードで実行していることが原因である可能性があります。Cでは、このエラーは発生しません。C ++void *では、他のポインターに自動的に変換されず、キャストが必要です(または、malloc()もちろん、C ++では使用しないでください)。
2017

@unwindうん、後でこれについて見つけた:)結果をキャストしないと、エラーがスローされる状況を述べたかっただけです。
nubcake 2017

回答:


156

いいえ、あなたはしていないためにメモリを割り当てるy->x二回。

代わりに、あなたは(ポインタを含む)構造のためのメモリ割り当てているプラスポイントにまでそのポインタのために何かを。

このように考えてください:

したがって、実際には、すべてを格納するために2つの割り当て(1および2)が必要です。

さらに、型はstruct Vector *yポインターである必要がありmalloc、Cで戻り値をキャストしないでください。隠したくない特定の問題を隠すことができるため、Cはvoid*戻り値を他のポインターに暗黙的に変換することができます。

そしてもちろん、次のように、これらのベクトルの作成をカプセル化して、それらの管理を容易にすることをお勧めします。

このように作成をカプセル化することで、ベクターが完全に構築されているか、まったく構築されていないかを確認できます。ベクトルが半分構築される可能性はありません。また、将来、クライアントに影響を与えることなく、基になるデータ構造を完全に変更することもできます(たとえば、スペースと速度のトレードオフのためにクライアントをスパース配列にしたい場合)。


28
私のアスキーアートスキルに震える:
paxdiablo 2013

どうもありがとう。本当に役に立ちました。
Pouya 2013

1
もしでは(retvalを== NULL)、RETVALはRETVALでなければなりません
レジオンDaeth

5

初めて、メモリをVectorに割り当てます。これは、変数x、を意味しますn

しかしx 、まだ有用なものを指していません

そのため、2番目の割り当ても必要です


3

いくつかのポイント

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector)); 間違っている

それはする必要がありますstruct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));ので、yへのポインタを保持していますstruct Vector

1つ目malloc()は、Vector構造(double + intへのポインター)を保持するのに十分なメモリのみを割り当てます。

2番目はmalloc()実際に10倍を保持するためにメモリを割り当てます。


2

ベクターと配列を同時に割り当てることで、実際には単一のmallocでこれを行うことができます。例えば:

これにより、Vector'y 'が割り当てられ、y-> xがVector構造体の直後(ただし同じメモリブロック内)に追加で割り当てられたデータを指すようになります。

ベクトルのサイズ変更が必要な場合は、推奨されている2つの割り当てを使用して行う必要があります。内部のy-> x配列は、ベクトル構造体 'y'をそのままにして、サイズを変更できます。


なぜキャストyをcharに具体的に入力したのですか?なぜ(double *)y + sizeof(struct Vector)ではないのですか?
Vishnu Prasath 2014

sizeofは、構造体のサイズをバイト単位で返します。ポインタ演算の「+」演算子は、「y」ポインタにsizeof(y)の倍数を追加します上記のように行った場合、yはsizeof(double)* sizeof(struct)だけ増加しますが、これは多すぎます。yをcharにキャストすると、yをsizeof(char)* sizeof(struct)= 1 * sizeof(struct)でインクリメントできます
PQuinn 2014

2

原則として、あなたはすでにそれを正しくやっています。あなたが望むもののためにあなたは2つを必要としますmalloc()

いくつかのコメント:

する必要があります

最初の行では、Vectorオブジェクトにメモリを割り当てます。 malloc()割り当てられたメモリへのポインタを返すため、yはベクトルポインタである必要があります。2行目では、10個のdoubleの配列にメモリを割り当てます。

Cでは、明示的なキャストは必要ありません。タイプの安全性のために、sizeof *y代わりに書くsizeof(struct Vector)方が優れているだけでなく、タイピングを節約できます。

構造体を再配置して、次のように1つ実行できますmalloc()


「タイピングの節約」は、プログラミングの決定にとって決して有効な議論ではありません。* yを使用する本当の理由は、安全上の理由から、対応する変数に必要なだけのスペースを割り当てるようにするためです。
Lundin 2013

@Lundin回答を更新しましたが、私にとって「型安全性」の議論は、執筆とほぼ同じリーグですif(NULL == foo)
Wernsey 2013

あなたは使用するように説教している人sizeof *yです。他の引数なしで5文字少なく入力するためだけにそれを行う場合(sizeof * y対sizeof(Vector))、キーボードで5文字を入力するタスクが大きな障害であることがわかったためである必要があります。もしそうなら、プログラミングにはたくさんのキーボード入力が含まれるので、おそらく別のキャリアの選択を検討してください...
Lundin 2013

@Lundin書き込みは、sizeof *yあなたが書くようなエラーを戦うことができますsizeof(Vector)あなたが意味する場合sizeof(Matrix)。どのくらいの頻度でそのような間違いをしますか?あなたがそうするとき、あなたはどれくらい早くそれらを見つけて修正しますか?私はそれが型の安全性を高めることに同意しsizeof *y、私は自分のコードで書きますが、のタイプミスを防ぐために書くのとほぼ同じくらいパラノイアです。if(NULL == foo)==
Wernsey 2013

1
@ShmuelKamenskyこれらは機能的に同等です。yは「yが指すもののサイズ」と言っているstruct Vectorのでsizeof *ysizeof struct Vector
Wernsey

1

メモリを割り当てるときはstruct Vector、ポインタx、つまりアドレスを含む値が配置されるスペースにメモリを割り当てるだけです。したがって、このような方法でy.xは、参照するブロックにメモリを割り当てません。


1

最初のmallocは、xのメモリ(doubleへのポインタ)を含むメモリを構造体に割り当てます。2番目のmallocは、xが指すdouble値にメモリを割り当てます。


0

malloc(sizeof(struct_name))構造体のフルサイズにメモリを自動的に割り当てる場合、内部の各要素をmallocする必要はありません。

使用し-fsanitize=address、あなたのプログラムメモリを使用する方法チェックするフラグ。


違う。xは単なるポインタであり、xが指す値にメモリを割り当てる必要があります。詳細については、他の回答をお読みください。(例:stackoverflow.com/a/14768280/5441253
MaximeAshurov20年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.