指標 Pointer
int main(int argc, const char * argv[]) { @autoreleasepool { NSString * ptr = @"Content"; NSLog(@"The value of ptr : %p",ptr); NSLog(@"The address of @\"Content\" : %p",@"Content"); NSLog(@"The address of ptr : %p",&ptr); } return 0; }
我們先來看這一行,NSString * ptr = @"Content"; ,這裡宣告了一個指標ptr,指向一個NSString的物件,而這個物件的值是@"Content",數值於電腦運算時,都存儲於記憶體中,可以想成一條馬路上有許多房子,大小固定,都有門牌,而物件有大有小,有些可能需要好幾間房子打通才放得下。示意圖如下,Ptr所存的值( 0x100001040 )剛好是這個字串的記憶體位置,ptr本身也有個Address是 0x7fff5fbff898。由這個例子可以知道要知道門牌位置必須使用 & 取址運算子,在NSLog中用%p列印出來。
那你也可能會問,ptr這個指標名稱又是存在哪裡了,應該也需要一塊記憶體去記錄吧!!沒錯,它在編譯執行後,作業系統記錄了它的名稱與Address,當你需要用ptr時,系統去找有沒有ptr這個東西,有的話又在記憶體的哪裡,這個你沒有辦法操作,也遠離了今天的主題,所以我們暫不討論。
&取址運算子,告訴我這個變數的記憶體位置。
*取值運算子,告訴我這個變數所指過去的物件值是什麼。
現在可以來看看方法參數的傳遞是如何運作的:
#import <Foundation/Foundation.h> void someOperate(NSString *m); int main(int argc, const char * argv[]) { @autoreleasepool { NSString *o = @"Origin"; NSLog(@"The address of o : %p",&o); NSLog(@"The value of o : %p",o); NSLog(@"The address of @\"Origin\" : %p",@"Origin"); someOperate(o); NSLog(@"%@",o); NSLog(@"The address of o : %p",&o); NSLog(@"The value of 0 : %p",o); } return 0; } void someOperate(NSString *m) { NSLog(@"**********"); NSLog(@"The address of m : %p",&m); NSLog(@"The value of m :%p",m); m = @"Modify"; NSLog(@"After"); NSLog(@"The address of m : %p",&m); NSLog(@"The value of m :%p",m); NSLog(@"The address of @\"Modify\" : %p",@"Modify"); NSLog(@"**********"); }
那如果我們想要的是直接更改原本的值,該怎麼做呢。有幾種方法,先講最容易的,把NSString改為NSMutableString,這樣在改值時,就會把原先的值,在原位置直接改變,而不是新產生一個新的物件。
#import <Foundation/Foundation.h> void someOperate(NSMutableString *m); int main(int argc, const char * argv[]) { @autoreleasepool { NSMutableString *o = [[NSMutableString alloc]initWithString:@"Origin"]; NSLog(@"The address of o : %p",&o); NSLog(@"The value of o : %p",o); someOperate(o); NSLog(@"%@",o); NSLog(@"The address of o : %p",&o); NSLog(@"The value of 0 : %p",o); } return 0; } void someOperate(NSMutableString *m) { NSLog(@"**********"); NSLog(@"The address of m : %p",&m); NSLog(@"The value of m :%p",m); [m setString:@"Modify"]; NSLog(@"After"); NSLog(@"The address of m : %p",&m); NSLog(@"The value of m :%p",m); NSLog(@"**********"); }但是如果沒有辦法更改為Mutable的類別時該怎麼辦,這時候有個迂迴的用法,指標的指標,既然無法更動指標所指的值,那就變動指標所存儲的記憶體Address,看一段代碼。
#import <Foundation/Foundation.h> void someOperate(NSString **m); int main(int argc, const char * argv[]) { @autoreleasepool { NSString *o = @"Origin"; NSLog(@"The address of o : %p",&o); NSLog(@"The value of o : %p",o); NSLog(@"The address of @\"Origin\" : %p",@"Origin"); someOperate(&o); NSLog(@"%@",o); NSLog(@"The address of o : %p",&o); NSLog(@"The value of o : %p",o); } return 0; } void someOperate(NSString **m) { NSLog(@"**********"); NSLog(@"The address of m : %p",&m); NSLog(@"The value of m :%p",m); NSLog(@"The value of *m : %p",*m); *m = @"Modify"; NSLog(@"After"); NSLog(@"The value of *m : %p",*m); NSLog(@"The address of m : %p",&m); NSLog(@"The value of m :%p",m); NSLog(@"The address of @\"Modify\" : %p",@"Modify"); NSLog(@"**********"); }
這邊宣告一個變數o指向@"Origin",o的記憶體位置是f898,o的值是1048,也就是@"Origin"的記憶體位置,someOperate方法接受的參數為指標的指標,而也就是o指標的Address,傳入後,發現它複製了一份o指標,m所指的位置並不是o,接著把m所指向的值由1048改為1168 ( *m = @"Modify"),到目前為止都懂,奇妙的是原本o所存儲的值也跟著變了,藉由這個方式,可以在方法中修改原先傳入的指標的存儲值,使他指向新的物件。不過我疑惑的是,為什麼修改的是m所指向的值,o卻也跟著改變,這個我尚未明白,請高手指點明燈。
沒有留言:
張貼留言