1) メインプログラムで [result release] を呼び出すと、関数内にある *sumFrac が解放されますか?
これは一種のひっかけ問題です。
sumFrac
それ自体は、オブジェクトへの単なるポインターです。ポインターをコピーする場合 ( を使用した直接代入=
、パラメーターとして渡す、関数から返すなど) は、ポインターをコピーするだけです。したがって、result
は と同じオブジェクトへのポインタsumFrac
です。したがって、 に送信すると、release
にリリースを送信するのと同じようになりsumFrac
ます。
(ARC を使用していた場合、ポインターをコピーするだけで refcount が自動的に行われることがあるため、これは実際にはもっと複雑になります。しかし、適切な名前や属性を使用している限り、それはあなたの問題ではなくコンパイラの問題にもなります。)
ただし、繰り返し新しい値を に割り当てますsumFrac
。これを行うたびに、古い値を指しなくなります。release
古い値retain
も新しい値もありません。したがって、返される値sumFrac
は解放されますが、arrayLength
0 でない限り、最初の行で割り当てた値とは異なります。別のオブジェクトを優先して無視するだけなのに、なぜオブジェクトを割り当てているのかさえわかりませんFraction
が、これを機能させたい場合は、次のことができます。
for ( fractsPtr = fracArray; fractsPtr < arrayLength; ++fractsPtr )
[sumFrac release];
sumFrac = [[*fractsPtr add: *(fractsPtr + 1)] retain];
これで、 を再割り当てするたびにsumFrac
、最初に古いオブジェクトを解放して新しいオブジェクトを保持するため、それぞれFraction
が開始時の同じ数の参照になります (参照が 0 の役に立たない新しいオブジェクトを含む)。後でrelease
メイン関数で使用する 1 つの追加の参照。-[add:]
(ここでは、新しい autoreleased を返すと仮定していますFraction
。代わりに、オブジェクトをその場で変更するか、新しい +1 などを返す場合、Fraction
それは別の話です。)
参照カウントを正確に保つのに苦労している場合は、標準の命名規則に従うか、自動解放プールや ARC を使用することを検討してください。(すでに自動解放プールがあることに注意してください。) または、Leaks や Xcode に付属の他のツールを使用して監視するか、後で参照できるように参照カウントをダンプするコードを追加します。
2) Fraction 配列オブジェクトを [fractionArray release] で解放しようとすると、コンパイラ エラーが発生するのはなぜですか?
fractionArray
これは、オブジェクトではなく、オブジェクトFraction*[]
の C スタイルの配列であるためです。メッセージを C スタイルの配列に送信することはできません。オブジェクトにのみ送信できます。Fraction
Fraction
実際、ここで表示されるエラーまたは警告 (コンパイラの設定によって異なります) で、次のことが説明されています。
frac.m:61:6: warning: receiver type 'Fraction **' is not 'id' or interface pointer,
consider casting it to 'id'
[fractionArray release];
それを理解するには、 anid
が「任意の ObjC オブジェクトへのポインター」を意味する型であり、オブジェクトへのポインターへのポインターがオブジェクトへのポインターと同じではないことを知っておく必要があります。あなたには十分でした。しかし、単に「コンパイラ エラーが発生しました」と言うのではなく、エラー メッセージを投稿していれば、すぐに回答が得られたはずです。
このようにしたい場合は、配列内のrelease
各オブジェクトに送信する必要があります。Fraction
などですでに行っていることです[a release]
。配列はスタックに割り当てられているため、配列に対して何もする必要はありません(たとえば、で割り当てた場合malloc
はfree
、そうではありませんrelease
。) これで完了です。
しかし、より良い方法は、オブジェクトである ObjC 配列を作成することです。
NSArray *fractionArray = [NSArray arrayWithObjects: a, b, c, nil];
// ...
[fractionArray release];
(その場合を除いて、自動解放された配列を返し、自動解放プールを持っているので、プールの邪魔にならないので、release
とにかくそれを望んでいません。)arrayWithObjects:
3) 最後に、この関数は実際には合計を返しませんが、0/0 を返します。これはなぜでしょうか?
あなたのループを見てみましょう:
for ( fractsPtr = fracArray; fractsPtr < arrayLength; ++fractsPtr )
C スタイルのことをしようとすると、ObjC エラーの代わりに C エラーが発生し始めます… 比較しているのですfractsPtr < arrayLength
。これにより、2 つが比較可能な型に変換され、比較されます。fractsPtr
はスタック上の配列へのポインターであるため、明らかに 2 未満ではありません。次のいずれかを実行する必要があります。
for ( fractsPtr = fracArray; fractsPtr < fracArray+arrayLength; ++fractsPtr )
… また
for (i = 0; i < arrayLength; ++i) {
fractsPtr = fracArray[i];
これが警告なしでコンパイルされた場合、私は非常に驚くでしょう。自分で試してみると、次のようになります。
frac.m:34:44: warning: ordered comparison between pointer and integer
('Fraction **' and 'int')
for ( fractsPtr = fracArray; fractsPtr < arrayLength; ++fractsPtr )
警告には理由があります。何が起こっているのかを推測しようとして時間を無駄にするのではなく、これを見ていればすぐに答えを見つけたでしょうadd:
。警告が問題を説明していなくても、少なくとも質問で言及してください。
これを修正すると、どうなりますか?さて、ループのたびにsumFracs
、[*fractsPtr add: *(fractsPtr+1)];
最後の割り当てのみが重要になります。したがって、すべての分数を合計するのではなく、最後の 2 つだけを合計します。つまり、 と同じになり[fracArray[arrayLength-1] add:fracArray[arrayLength]]
ます。
arrayLength
また、実際には配列の長さより 1 少ないことを意味する名前のパラメーターを使用すると、災害への誘いになります。コードを書いたばかりなので、電話することはわかっていarraySum(fractionArray, 2)
ましたが、数週間後に戻ってきたときにarraySum(fractionArray, 3)
(またはarraySum(fractionArray, sizeof(fractionArray)/sizeof(*fractionArray))
) を書くと、明らかに正しく見えるので、理由がわかりません。ガベージ値またはセグメンテーション違反を読んでいます。