0

对于下面的代码...
1)当我在主程序中*sumFrac调用时,位于函数内的 是否被释放? 2) 当我尝试使用 释放 Fraction 数组对象时,为什么会收到编译器错误? 3) 最后,该函数实际上并没有返回一个总和,而是. 为什么会这样? 如果这很明显,我很抱歉,这对我来说是新的......谢谢[result release]
[fractionArray release]
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 确实被释放了——但是,除非arrayLength是 0,否则这与您在第一行中分配的值不同。我什至不确定你为什么要分配一个Fraction对象,而你只是要忽略它以支持另一个对象,但如果你想让这个工作,你可以:

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

现在,每次你 reassignsumFrac时,你首先释放旧对象并保留新对象,所以每个对象都Fraction以相同数量的引用结束(包括无用的新对象有 0 个引用),除了你返回的那个有一个额外的 ref,稍后release将在 main 函数中使用。(我在这里假设它-[add:]返回一个新的 autoreleased Fraction。如果它改为修改对象,或者返回一个新的 +1Fraction或其他东西,那就是另一回事了。)

如果您很难保持引用计数正常,您可能需要考虑遵循标准命名约定和/或使用自动释放池和/或 ARC。(值得注意的是,您已经一个自动释放池。)或者,或者,使用 Leaks 和 Xcode 附带的其他工具来观察事物,或者添加转储引用计数的代码,以便以后查看它们。

2) 当我尝试使用 [fractionArray release] 释放 Fraction 数组对象时,为什么会收到编译器错误?

因为fractionArray是一个Fraction*[]——也就是说,一个 C 风格的Fraction对象数组,而不是一个Fraction对象。您不能将消息发送到 C 样式数组,只能发送到对象。

事实上,您在这里看到的错误或警告(取决于您的编译器设置)已经解释了这一点:

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 风格的事情,你会开始遇到 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))),它看起来很明显正确,你不知道为什么您正在读取垃圾值或段错误。

于 2013-03-28T23:11:38.517 回答
2

该代码非常奇怪。

你根本没有数组对象;你有一些相当奇怪的管理语言数组。

我建议重构NSMutableArray用于包含分数的代码,因为您几乎永远不会看到像您在真正的 ObjC 应用程序中编写的那样的代码。

于 2013-03-28T23:05:08.213 回答