要明确这两者的差异,首先需要了解一下 指针 的定义(以下是我个人的理解,有出入欢迎指正)
1.指针的定义
指针说得简单就是就是一个内存的地址,能理解这一步对指针的理解就很简单了,常见的比较绕的定义
指针变量: 一个 存储了 内存地址 的变量--简单说就是指针
变量的指针:一个变量的 内存地址
2.指针的代码表现
与指针挂钩的 特殊字符 常见的有 “*”、"&"
*:可以理解为 取某指针变量指向的内存值
&:可以理解为取 某变量 的内存地址
能理解这两个特殊字符的含义,对于指针变量的赋值就可以很好地理解了
例如:
最简单的:
int number = 1;
int *ptr = &number;
用上面的解释来解读一下这个很常见的 代码:
*ptr:取变量ptr 指向的内存值
int *ptr :变量ptr 指向的内存值 为int型
得出:ptr为一个指向int型的 内存地址
所以有赋值:
ptr = &number:取number的内存地址赋给 ptr变量
稍微复杂一点的:
int number = 1;
int *ptr = &number;
int **ptr2 = &ptr;
printf("%d",**ptr2);
看第三行代码:
先不看ptr2的赋值,反向解读代码
**ptr2为int型 -> *ptr2 为一个指向int型的内存地址 -> ptr2 为指向 一个指向int型内存地址 的内存地址
看等式右边:ptr为一个指向int型的内存地址-> &ptr 取 一个指向int型内存地址 的内存地址
所以可以将右边赋值给左边
(这个的确有点绕0.0b,但是在OBJC中有时候还是不得不用)
3.C语言中函数形参的处理
一个很简单的例子:
在xcode中新建一个Command Line
#include <stdio.h>
void function(int i,int *prt)
{
i = 8;
*prt = 4;
}
int main(int argc, const char * argv[])
{
int number = 1;
int number2 =3;
function(number, &number2);
printf("%d\n",number);// 1
printf("%d",number2);// 4
return 0;
}
由输出结果可猜测,C函数对传入的形参会复制一份内存,所以在function无法直接改变number的值,因为此时的函数内的i已经不再是外面传进来的number了,
但是 虽然此时ptr 已经不再是传进来的 &number2 ,但是 他们却指向同一个内存块,所以 使用 *ptr(取指针ptr指向的内存) 就能直接操作number2的值了
一个稍微复杂一点的例子:
void setValue2(char *str)
{
str = "yyyyy";
}
void setValue3(char **str)
{
*str = "yyyyy";
}
char *str = "xxxxx";
setValue2(str);
printf("%s\n",str);//xxxxx
setValue3(&str);
printf("%s",str);//yyyyy
使用上例中的猜想结论,setValue2中对 str(字符串中首字母的内存地址) 进行了一次内存复制,并将"yyyyy"首字母的内存地址赋给拷贝后的str(不再是原来的str了),所以在后面使用printf输出str时,依然是从原首字母地址开始读取,直到读到\0,所以输出的依然是xxxxx
setValue3 中 copy的是 指向 xxxxx 首字母内存地址 的内存地址,所以使用 *str就相当于直接改变原 str 指向的内存地址,所以输出的就是 yyyyy
4.OBJC中函数形参的处理
OBJC中比较常见的函数形参的传递是 3 中的第二种情况:
- (void)setValue:(NSString *)string
{
string = @"test String";
}
- (void)setValue2:(NSString **)string
{
*string = @"test String";
}
NSString *str = nil;
[self setValue:str];
NSLog(@"%@",str);//null
[self setValue2:&str];
NSLog(@"%@",str);//test String
结果成因参考3