上一章Objective-C开发教程请查看:Objective-C数组用法介绍
相对于C++中的引用,Objective-C的指针还是比较好的,而且在OC中编程推荐使用指针,因为使用指针更快。指针是用来动态申请内存的,对于如何回收的问题,后面的章节会详细讲解。
由前面的章节我们可以知道,一个变量对应于一个内存区域,每个内存区域都有一个地址,可以使用&操作符获取变量对应内存区域的地址,打印内存地址使用格式符%x,如下面的例子:
#import <Foundation/Foundation.h>
int main () {
int var1;
char var2[10];
NSLog(@"var1的地址: %x", &var1 );
NSLog(@"var2的地址: %x", &var2 );
return 0;
}
什么是指针?
一个指针是一个变量,我们可以做一个类比,整数类型的变量使用int声明,如int a;,其中a是一个变量。那么指针其实也是一个类型,只不过不同数据类型有不同类型的指针。声明一个指针一定要带上类型,即使是void类型,语法如下:
type *pointer;
如上pointer就是一个type类型的指针,只能储存type类型的指针,它的值是一个地址,下面是更多的例子:
int *intPointer;
double *doublePointer;
char *charPointer;
NSString *str;
再说一下,指针类型的变量的值是一个地址,这个地址是一个long类型的十六进制数,知道这个对你的编程也有帮助。long在mac中是8字节,也就是64位。
如何使用指针?
首先我们需要定义一个指针变量,然后将变量的地址分配给这个指针变量,最后就可以使用该指针变量访问数据了。使用指针取值需要使用*操作符,下面是一个使用示例:
#import <Foundation/Foundation.h>
int main () {
int var = 20;
int *ip;
ip = &var;
NSLog(@"var变量的地址: %x", &var );
NSLog(@"ip地址值: %x", ip );
NSLog(@"*ip的值: %d", *ip );
return 0;
}
Objective-C中的NULL指针
我们可以给指针初始化为NULL值,这样的指针称为空指针,NULL指针的值一般为0,下面是空指针的例子:
#import <Foundation/Foundation.h>
int main () {
int *ptr = NULL;
NSLog(@"ptr的值 : %x", ptr );
return 0;
}
在大多数操作系统上,程序不允许访问地址0处的内存,因为该内存是由操作系统保留的。但是,内存地址0具有特殊的意义,它表示指针不打算指向可访问的内存位置。但是按照惯例,如果指针包含null(0)值,则假定它不指向任何东西。
要检查空指针,可以使用if语句,如下所示:
if(ptr) /* 如果ptr不是null则为true */
if(!ptr) /* 如果ptr是null则为true */
指针算术运算
Objective-C指针是一个地址,它是一个数值。因此,可以对指针执行算术运算,就像可以对数值执行算术运算一样。指针上可以使用四种算术运算符:++、–、+和-
为了理解指针算法,让我们考虑ptr是一个整数指针,它指向地址1000。假设32位整数,让我们对指针执行以下算术运算:
ptr++
现在,在上述操作之后,ptr将指向位置1004,因为每次ptr递增时,它将指向下一个整数位置,即当前位置旁边的4/8个字节。这个操作将把指针移动到下一个内存位置,而不会影响内存位置的实际值。如果ptr指向地址为1000的字符,那么上述操作将指向位置1001,因为下一个字符将在1001处可用。
递增一个指针
我们喜欢在程序中使用指针而不是数组,因为变量指针可以递增,不像数组名称不能递增,因为它是常量指针。下面的程序增加变量指针来访问数组的每个后续元素:
#import <Foundation/Foundation.h>
const int MAX = 3;
int main () {
int var[] = {10, 100, 200};
int i, *ptr;
ptr = var;
for ( i = 0; i < MAX; i++) {
NSLog(@"var[%d]地址 = %x", i, ptr );
NSLog(@"var[%d] = %d", i, *ptr );
ptr++;
}
return 0;
}
其它指针递减和比较的运算也是类似。
指针数组
在我们理解指针数组的概念之前,让我们考虑一下下面的例子,它使用了一个有3个整数的数组:
#import <Foundation/Foundation.h>
const int MAX = 3;
int main () {
int var[] = {10, 100, 200};
int i;
for (i = 0; i < MAX; i++) {
NSLog(@"var[%d] = %d", i, var[i] );
}
return 0;
}
当我们想要维护一个数组时,可能会出现这样的情况,它可以存储指向int或char或任何其他可用数据类型的指针。下面是指向整数的指针数组的声明:
int *ptr[MAX];
这将ptr声明为一个最大整数指针数组。因此,ptr中的每个元素现在都有一个指向int值的指针。下面的例子使用了三个整数,它们将被存储在指针数组中,如下所示:
#import <Foundation/Foundation.h>
const int MAX = 3;
int main () {
int var[] = {10, 100, 200};
int i, *ptr[MAX];
for ( i = 0; i < MAX; i++) {
ptr[i] = &var[i];
}
for ( i = 0; i < MAX; i++) {
NSLog(@"var[%d] = %d", i, *ptr[i] );
}
return 0;
}
二级指针
指向指针的指针是多个间接指针或指针链的一种形式。通常,指针包含一个变量的地址。当我们定义一个指针时,第一个指针包含第二个指针的地址,第二个指针指向包含实际值的位置,如下所示。
作为指针指针的变量必须这样声明。这是通过在它的名字前面加上一个星号来实现的。例如,下面是声明一个指向int -类型指针的声明:
int * * var;
当一个指向指针的指针间接指向一个目标值时,访问该值需要应用两次星号操作符,如下例所示:
#import <Foundation/Foundation.h>
int main () {
int var;
int *ptr;
int **pptr;
var = 3000;
ptr = &var;
pptr = &ptr;
NSLog(@"var = %d", var );
NSLog(@"*ptr = %d", *ptr );
NSLog(@"**pptr = %d", **pptr);
return 0;
}
在Objective-C中传递指向函数的指针
Objective-C编程语言允许你传递一个指向函数的指针。为此,只需将函数参数声明为指针类型。
下面是一个简单的例子,我们将一个无符号的长指针传递给一个函数,然后改变函数内部的值,这个值会在调用函数中得到反映:
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void) getSeconds:(int *)par;
@end
@implementation SampleClass
- (void) getSeconds:(int *)par {
*par = time( NULL );
return;
}
@end
int main () {
int sec;
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass getSeconds:&sec];
NSLog(@"seconds: %d\n", sec );
return 0;
}
函数返回指针
正如我们在上一章中看到的,Objective-C编程语言允许从函数中返回数组,类似的,Objective-C允许从函数中返回指针。为此,必须声明一个返回指针的函数,如下面的示例所示
int * myFunction() {
.
.
.
}
要记住的第二点是,将局部变量的地址返回给函数外部不是一个好主意,因此必须将局部变量定义为静态变量。
现在,考虑下面的函数,它将生成10个随机数并使用数组名返回它们,数组名表示一个指针,即第一个数组元素的地址。
#import <Foundation/Foundation.h>
int * getRandom( ) {
static int r[10];
int i;
srand( (unsigned)time( NULL ) );
for ( i = 0; i < 10; ++i) {
r[i] = rand();
NSLog(@"%d", r[i] );
}
return r;
}
int main () {
int *p;
int i;
p = getRandom();
for ( i = 0; i < 10; i++ ) {
NSLog(@"*(p + [%d]) : %d\n", i, *(p + i) );
}
return 0;
}
评论前必须登录!
注册