【问题标题】:C: Double Pointers and Objective-C NSError Double Pointers UsageC:双指针和 Objective-C NSError 双指针的用法
【发布时间】:2014-01-08 16:52:48
【问题描述】:

我偶然在 SO 上偶然发现了关于双星 (**) 与 NSError 的用法的帖子。决定更深入地挖掘它,这导致我重新访问C

我已经在NSError阅读了很多帖子(此处不重复),我理解他们为什么这样做。

所以,我决定在 IDE (Xcode) 中编写一个小 sn-p 来亲自查看它的实际效果。

int a = 10;
int b = 20;

int *c = &a;
int *d = &b;

int **e = &d;

NSLog(@"Before: a is: %d b is: %d", a, b);

[self testSingleStar:c]; 
[self testDoubleStar:e]; 

NSLog(@"After: a is: %d b is: %d", a, b);

方法:

- (void)testDoubleStar:(int**)x
{
    int anotherValue1 = 22;
    **x = anotherValue1;
}

- (void)testSingleStar:(int*)x
{
    int anotherValue2 = 33;
    *x = anotherValue2;
}

输出:

之前:a 为:10 b 为:20

之后:a 为:33 b 为:22

a(通过单指针)和b(通过双指针)的值都发生了变化。

那么,如果我们可以使用仅使用单个指针来更改(a)的值,为什么我们需要使用指向@的指针987654330@ 以便我们可以在方法调用中修改NSError 对象,其中NSError 对象在其参数中传递(&error)?

另外:

关于上述,在C 中向参数传递一些东西实际上是向参数传递一个副本(即使在单个指针的情况下也只会传递它的一个副本),因此在内部进行的任何更改该方法的范围不会影响传递给它的原始值(这就是他们使用双星的原因)。

但上面只使用了一个指针的示例似乎与此相矛盾,因为值(即由单个指针指向的a - c)确实发生了变化?

【问题讨论】:

  • 使用 Objective-C 对象实例而不是原语重新评估您的测试。
  • @trojanfoe 当然可以。但是即使在C的情况下,也需要一个双指针来修改方法范围内的原始值,但是从上面的示例中,一个指针就足够了?
  • @trojanfoe 试过了。你能告诉我为什么即使使用单指针它也只适用于原语?谢谢。

标签: objective-c c pointers nserror double-pointer


【解决方案1】:

您可以通过向函数或方法提供foo * 来修改foo 类型的外部变量:

+ (void)doJobReturningInt(int *) { ... }

int a;
[MyClass doJobReturningInt:&a]; // may modify the value of the variable a;

到目前为止,一切都很好。

现在我们如何声明一个存储 NSError 对象的变量?使用NSError * 类型:

NSError *error;

所以如果我们要修改它,我们需要提供一个指向它的类型的指针,也就是NSError **

+ (void)doJobReturningError:(NSError **)outError { ... }

NSError *error;
[MyClass doJobReturningError:&error]; // may modify the value of the variable error;

看到了吗?这是同样的情况:要修改类型foo,提供foo*

【讨论】:

  • 感谢您提供精美的样品。 +1。如果可以的话,我会再次投票。
【解决方案2】:

这是因为你不能只拥有一个 NSError 对象......你只能通过指针来处理 Objective-C 对象......所以虽然理论上你可以获取一个指向 NSError 的指针并交换它的内容......它会打乱封装(其他东西可能依赖于曾经存在的数据。)。

同样只是将指针重新分配给一个新值是行不通的,因为它不会影响调用者的版本。

虽然看起来很诱人:

-(void)method:(NSError *)errObject
{
    //something like
    errObject = [NSError errorWithBlah:@"blah"]; // this will only change the local variable errObject, not the callers version, that pointer is just copied by value. 
}

 /// not real code, didn't check to see if my params are in the correct places etc.
-(void)mangler:(NSError *)errObject
{
    //something like
    errObject = realloc(errObject,sizeof *errorObject);
    memcpy(errObject,[NSError new],sizeof NSError);

    // you have killed the old version that may be in use.
}

【讨论】:

  • 一切看起来都很好,除了缺少强制转换和一些括号。回到我的问题中的C 示例:所以,您是说我实际上并没有通过指针更改ab 的值(分别为ce) .?我想是这样。顺便说一句,为errorWithBlah: +1。我喜欢它。
  • 是的,您正在通过添加另一层间接来更改 a 和 b,这与您使用 NSError 双指针所做的相同。您不能只将 ab 传递给另一个函数/方法,因为更改不会渗透备份,它仅发生在函数本地副本中。
  • 但是只有一个指向a的指针。我认为在C 中,只有原始值的副本在按值传递和按引用(单指针)情况下传递给参数。但似乎单个指针确实改变了a 的值。不需要双指针。因此我的问题。
  • @Unheilig 是的,但是您不能更改 NSError 对象的实际内容,这是被禁止的……您只能更改指针指向的内存。
  • 因为您可以就地更改标量类型的值,并且与对象不同,它不会影响该值的其他副本。
猜你喜欢
  • 1970-01-01
  • 2014-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多