2013-03-28 26 views
0

對於下面的代碼數組...
1)是*sumFrac,位於函數中,發佈的時候我在主程序調用[result release]
2)爲什麼當我試圖釋放分數數組對象[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; 
} 
+0

未來,不要只說「編譯器錯誤」,顯示錯誤信息。它們通常充滿了有用的信息(特別是當編譯器是鐺聲時)。 – abarnert

回答

4

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)爲什麼我試圖用[分數陣列版本]釋放分數陣列對象時收到編譯器錯誤?

由於fractionArrayFraction*[],也就是說,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。

+0

偉大的幫助!只是爲了澄清:儘管我在'result'上調用'release',它會釋放'sumFrac'(因爲我將它分配給result)?另外 - 您可能會了解爲什麼函數不計算總和?再次感謝 – user2000809

+0

好,回答更新。但是現在我更仔細地看了......是的,它會釋放'sumFrac',但這可能並不意味着你的想法。 – abarnert

+0

非常全面的答案。非常感謝! – user2000809

2

該代碼是非常奇怪的。

根本沒有數組對象;你有一些相當奇怪的託管語言數組。

我建議重構代碼以使用NSMutableArray來包含分數,因爲幾乎不會看到像在真實的ObjC應用程序中編寫的代碼。

+0

是的,這是一個迂迴的做法。我只是這樣編碼的,因爲我正在研究一些涵蓋這些主題的ObjC練習,但很高興知道我不會經常需要處理像這樣的代碼IRL – user2000809