C указатели против Objective-C указатели - PullRequest
7 голосов
/ 08 декабря 2009

Я пришел из Objective-C и пытаюсь расширить свои знания в C. Однако меня смущает одна вещь, и в этом разница между указателями в C и Obj-C. Как вы можете видеть из приведенных ниже примеров, кажется, что в обоих языках дела обстоят немного по-разному, и мне было интересно, не могли бы вы помочь объяснить, почему?

Код C отлично работает:

void myFunction()
{
    int x, *pointerX; 
    pointerX = &x;
    *pointerX = 5;

    // Prints: "x is 5"
    printf("x is: %i", x);
}

Сбой кода Obj-C:

- (void)myMethod
{
    NSString *string = @"Caramel coffee", *stringPointer;
    stringPointer = &string;                    // Warning:   Assignemnt from incompatible pointer type
    *stringPointer = @"Chocolate milkshake";    // Exception: Incompatible types in assignment

    NSLog(@"string is: %@", string);
}

Вопрос: Почему я не могу присвоить stringPointer адресу памяти строки (stringPointer = &string;), и почему я могу выполнить *pointerX = 5; под C, но я не могу выполнить *stringPointer = @"Chocolate milkshake"; под Objective-C?

Я понимаю, что Obj-C имеет дело с объектами, а C - нет, но я не могу выяснить закулисные детали относительно того, почему он не работает в Obj-C. Любая помощь очень ценится. Спасибо! :)

Ответы [ 7 ]

18 голосов
/ 08 декабря 2009

В первом примере x и pointerX имеют разные типы ((int) и (int *) соответственно) Во втором примере string и stringPointer имеют одинаковый тип (NSString *) Попробуйте вместо:

NSString *string = @"Caramel coffee", **stringPointer;
10 голосов
/ 08 декабря 2009

Ваш NSString *string сам по себе является указателем. Следовательно, чтобы указать на него, вам нужно объявить stringPointer как указатель на указатель. То есть, объявить stringPointer так:

NSString **stringPointer;

Тогда все должно работать. Обратите внимание, что та же семантика указателя применяется в C и Objective-C.

5 голосов
/ 14 декабря 2009

Дело в том, что когда вы создаете объект, вы фактически всегда манипулируете им через назначенный ему указатель, следовательно (NSString *).

Попробуйте сделать то же самое в C (работая со строкой), возможно, это станет понятнее:

void myFunction()
{
    char *string = "this is a C string!";
    char **ptr=&string;


    // Prints: "this is a c string"
    printf("ptr points to %s: \n",  *ptr);
}

Как вы можете видеть, указатели работают точно так же, как и в target-c. Имейте в виду, что в target-c очень мало примитивов (наиболее очевидным является int). Большую часть времени вы создаете указатель типа объекта X (скажем, NSString), а затем выделяете кусок памяти (через [[Object alloc] init]) и назначаете начальный адрес этого блока вашему указателю. Точно так же, как мы сделали в C с нашей строкой.

3 голосов
/ 08 декабря 2009

&string имеет тип NSString **, тогда как stringPointer имеет тип NSString *, таким образом, предупреждение. Затем вы пытаетесь присвоить экземпляр NSString (с типом NSString *) переменной типа NSString, что приводит к ошибке.

2 голосов
/ 08 декабря 2009

Всегда полезно определять каждую переменную в отдельной строке. Когда вы переписываете свой исходный код цели с

NSString* string = @"Caramel coffee";
NSString* stringPointer;

многое становится понятным.

1 голос
/ 08 декабря 2009

Вопрос в том - ваши строки постоянны или нет?
Первый пример, вероятно, сработает.
Даже в нецелевых компиляторах C литеральные строки могут быть помещены в постоянную память с помощью параметров компоновщика / компилятора.

В этой строке: stringPointer = & string; Вы копируете адрес указателя в строку poitner. Явно несовместимо.

А на этой строчке:
* stringPointer = @ "Шоколадный молочный коктейль";

Вы пытаетесь записать строку в указатель (указатель является 4-байтовым адресом). Не очень хорошая идея копировать целую строку поверх нее.

0 голосов
/ 08 декабря 2009

Что вы пытаетесь сделать?

Не уверен, что он будет работать так, как вы хотели.

Вы, кажется, берете понятия из C и применяете их к классам Какао, я думал, что вы изучали C. Видели ли вы где-нибудь в коде Objective C получение адреса объекта?

Классы какао реализованы с использованием Class clusters, что означает, что они используют один и тот же интерфейс, но вы получите определенный расширенный класс, которым вы манипулируете.

В вашем случае вы берете адрес возможного класса, который расширяет NSString и присваиваете ему указатель на NSString.

Пример:

NSString * str = @"Caramel coffee";
NSString * str2 = [NSString stringWithString:@"all"];

NSLog(@"%@", [[str class] className]);
NSLog(@"%@", [[str class] className]);

Вывод (GNUStep linux):

2009-12-08 10:49:29.149 x[25446] GSCInlineString
2009-12-08 10:49:29.149 x[25446] NSConstantString

... кроме очевидных проблем определения указателя, на которые указывают другие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...