0

以下のコードの場合...
1)*sumFrac関数内にある[result release]は、メイン プログラムで呼び出したときに解放されますか?
2) で Fraction 配列オブジェクトを解放しようとすると、コンパイラ エラーが発生するのはなぜ[fractionArray release]ですか?
3) 最後に、関数は実際には合計を返しませんが、0/0. これはなぜでしょうか?

これが明らかな場合は申し訳ありませんが、私には新しいです...ありがとう

#import <Foundation/Foundation.h>
#import <Fraction.h>

Fraction * arraySum (Fraction *fracArray[], int arrayLength)
{
    Fraction *sumFrac = [[Fraction alloc] init];
    Fraction **fractsPtr;

    for ( fractsPtr = fracArray; fractsPtr < arrayLength; ++fractsPtr )
        sumFrac = [*fractsPtr add: *(fractsPtr + 1)];

    return sumFrac;
}

//Test function
int main (int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Fraction *result;

    Fraction *a = [[Fraction alloc] initWith: 3 over: 5];
    Fraction *b = [[Fraction alloc] initWith: 2 over: 7];
    Fraction *c = [[Fraction alloc] initWith: 6 over: 3];

    Fraction *fractionArray[] = { a, b, c };

    result = arraySum ( fractionArray, 2 );

    [result print];

    [result release];
    [a release];
    [b release];
    [c release];
    [fractionArray release];

    [pool drain];
    return 0;
}
4

2 に答える 2

4

1) メインプログラムで [result release] を呼び出すと、関数内にある *sumFrac が解放されますか?

これは一種のひっかけ問題です。

sumFracそれ自体は、オブジェクトへの単なるポインターです。ポインターをコピーする場合 ( を使用した直接代入=、パラメーターとして渡す、関数から返すなど) は、ポインターをコピーするだけです。したがって、resultは と同じオブジェクトへのポインタsumFracです。したがって、 に送信すると、releaseにリリースを送信するのと同じようになりsumFracます。

(ARC を使用していた場合、ポインターをコピーするだけで refcount が自動的に行われることがあるため、これは実際にはもっと複雑になります。しかし、適切な名前や属性を使用している限り、それはあなたの問題ではなくコンパイラの問題にもなります。)

ただし、繰り返し新しい値を に割り当てますsumFrac。これを行うたびに、古い値を指しなくなります。release古い値retainも新しい値もありません。したがって、返される値sumFrac 解放されますが、arrayLength0 でない限り、最初の行で割り当てた値とは異なります。別のオブジェクトを優先して無視するだけなのに、なぜオブジェクトを割り当てているのかさえわかりません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 スタイルの配列に送信することはできません。オブジェクトにのみ送信できます。FractionFraction

実際、ここで表示されるエラーまたは警告 (コンパイラの設定によって異なります) で、次のことが説明されています。

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]。配列はスタックに割り当てられているため、配列に対して何もする必要はありません(たとえば、で割り当てた場合mallocfree、そうではありません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))) を書くと、明らかに正しく見えるので、理由がわかりません。ガベージ値またはセグメンテーション違反を読んでいます。

于 2013-03-28T23:11:38.517 に答える
2

そのコードは非常に奇妙です。

配列オブジェクトはまったくありません。かなり奇妙に管理された言語配列がいくつかあります。

分数を含めるために使用するコードをリファクタリングすることをお勧めしNSMutableArrayます。これは、実際の ObjC アプリで記述したようなコードを目にすることはほとんどないためです。

于 2013-03-28T23:05:08.213 に答える