类型本质
变量:一个内存地址的别名
例如 int a = 0;
a : 0x0004,int 32位,那么 a 的范围是 [0x0004, 0x0006)
a
0x4 0x5 0x6
00000000 00000000 00000000 00000000 00000000
值类型:变量对应的内存地址的内容当做数值。
例如 int a = 0; a 的范围取出来,按照int的方式转出来,当做值,&a 可以取到 a 的地址。
引用类型:变量对应的内存地址的内容当做内存地址,再去取改地址的内容。
例如 int *b; b 的内容是个地址,通过 *b 取得该地址内容。
如果定义了三级指针 int ***b; 那么需要 &&&b 取得内容。
- 需要注意的点
int a = 10;
int *b = &a;
int *c = &a;
b, c 两个指针指向同一个地址的数据,那么很可能 b 的数据被 c 改掉。
如果你允许多个指针改同一份数据,那可以这样用。例如
void fun() {
Person *me = new Person();
editName(me);
editAge(me);
editSex(me);
// me 里就收集到了全部数据
}
如果不希望多个指针改同一份数据,造成数据错误,那么应该copy一份。例如
int a = 10;
int *b = malloc(sizeof(int));
*b = a;
int *c = malloc(sizeof(int));
*c = a;
// 那么修改 b 不会影响到 c
如果是 Person 这样的类,例如
Class Person {
int a;
int *b;
Hand *h; // h 里面还有指针变量
};
Person p, p1, p2;
p1 = p.copy;
p2 = p.copy;
在浅拷贝的时候,只复制 Person,a 会被复制,p1.a 和 p2.a 修改不影响,但是 p1.b 和 p2.b 还是指向同一块数据,还是有可能被错误修改。
需要深拷贝,对 p 中的指针也进行拷贝,对指针中的指针,一直下去,直到它不是个指针为止的数据都要进行拷贝,才是完全的两个 p1, p2。
可变与不可变
有些指针的数据是可变的,有些指针的数据是肯定不会变化的(那么在copy的时候可以只copy指针而不copy内容),为了区分数据可不可变,那么定义了可变与不可变的类型。
C++ 中用 const 区分
int const *p = &a; // 内容不可变
int * const p = &a; // 指针不可变
int const * const p = &a; // 指针,内容都不可变
oc 中用 Mutable 区分, swift 中 var 与 let
NSString *s1 = @"abcd"; // 内容不可变,但指针可变,p 可以指其他
NSMutableString *s2 = [[NSMutableString alloc] init]; // 指针,内容都可变
oc中少了指针不可变。
oc中第二个风险
@interface NSMutableString : NSString
NSMutableString 是继承 NSString 的,可变和不可变通过继承来实现。
基类指针可以指向子类,那么 NSString *s1 可以指向 NSMutableString,那 NSString 不可变的意义就没了。
实际中 NSString 可能是可以变的,当他指向 NSMutableString 的时候。
怎么避免,类型要对上
// 传入时
NSMutableString *s2 = [[NSMutableString alloc] init];
for (int i=0; i<10; i++) {
[s2 appendString:@"xxx"];
[self dealString:[s2 copy]]; // 防止改变string
}
- (void)dealString:(NSString *)str {
NSString *a = [str copy]; // 防止别人传 NSMutableString 进来
}
// 传出时
- (NSArray *)personArray {
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:p1];
[array addObject:p2];
...
return [array copy]; // 按照类型传出
}
网友评论