1)當我在主程序中調用[結果釋放]時,位於函數中的* 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
最後都以相同數量的引用開始(包括無用的新引用),除了你返回的引用有一個額外的參考,你後來release
在主要功能。 (我在這裏假設-[add:]
返回一個新的自動發佈的Fraction
。如果它改變了對象的位置,或者返回一個新的+1 Fraction
或其他的東西,那麼這是一個不同的故事。)
如果您很難保持refcounts直接,您可能需要考慮遵循標準的命名約定和/或使用autorelease池和/或ARC。 (值得注意的是,你已經有有一個自動釋放池。)或者,也可以使用Leaks和Xcode附帶的其他工具來觀察事物,或者添加代碼來刪除refcounts,以便稍後可以看到它們。
2)爲什麼我試圖用[分數陣列版本]釋放分數陣列對象時收到編譯器錯誤?
由於fractionArray
是Fraction*[]
,也就是說,Fraction
對象,而不是一個對象Fraction
的C數組。您不能將消息發送到C風格的數組,只能發送給對象。
事實上,錯誤或警告(取決於你的編譯器設置),你到這裏已經說明了這一點:
frac.m:61:6: warning: receiver type 'Fraction **' is not 'id' or interface pointer,
consider casting it to 'id'
[fractionArray release];
爲了理解這一點,你必須知道的id
是一類意思是「指向任何ObjC對象的指針」,並且指向一個對象的指針與指向一個對象的指針不是同一件事,因此對於你來說可能不夠。但是,如果您發佈了錯誤消息而不是僅僅說「我遇到了編譯器錯誤」,那麼您會立即得到答案。
如果你想這樣做,你必須發送release
到陣列中的每個Fraction
對象。你已經在使用[a release]
等等。你不需要對數組做任何事情,因爲它已經分配在堆棧上了(如果你已經分配了它,例如,malloc
,你想要free
它,而不是release
它)。所以,你完成了。
但更好的方法來做事是創建一個ObjC陣列,這是一個對象:
NSArray *fractionArray = [NSArray arrayWithObjects: a, b, c, nil];
// ...
[fractionArray release];
(除了在這種情況下,你實際上並不仍要release
,因爲arrayWithObjects:
返回一個autoreleased數組,和你有一個自動釋放池,所以在池的方式沒有得到。)
3)最後,函數實際上並不返回的總和,但0/0。爲什麼會這樣呢?
讓我們來看看你的循環:
for (fractsPtr = fracArray; fractsPtr < arrayLength; ++fractsPtr)
如果你打算做的事情C風格,你開始運行爲C錯誤,而不是ObjC錯誤...你比較fractsPtr < arrayLength
。這會將兩者轉換成可比較的類型,然後比較它們。 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)];
只有最後一個分配很重要。因此,它仍然不會將所有分數相加,只是最後兩個分數 - 換句話說,它將與[fracArray[arrayLength-1] add:fracArray[arrayLength]]
相同。
此外,使用名爲arrayLength
的參數時,它實際上表示1小於數組長度是對災難的邀請。你知道打電話arraySum(fractionArray, 2)
是因爲你剛剛寫了代碼,但是當你幾周後回來時,你會寫arraySum(fractionArray, 3)
(或arraySum(fractionArray, sizeof(fractionArray)/sizeof(*fractionArray))
),它看起來很明顯,你會有不知道爲什麼你閱讀垃圾值或segfaulting。
未來,不要只說「編譯器錯誤」,顯示錯誤信息。它們通常充滿了有用的信息(特別是當編譯器是鐺聲時)。 – abarnert