Objective-C中的指针简单易学。使用指针可以更轻松地执行某些Objective-C编程任务,并且在不使用指针的情况下无法执行其他任务(如动态内存分配)。 所以有必要学习指向成为一个完美的Objective-C程序员。在这小节中将通过简单的步骤学习指针。
每个变量都是一个内存位置,每个内存位置都定义了它的地址,可以使用符号(&
)运算符进行访问,该运算符表示内存中的地址。 考虑以下示例,它将打印定义的变量的地址 -
#import <Foundation/Foundation.h>
int main () {
int var1;
char var2[10];
NSLog(@"Address of var1 variable: %x\n", &var1 );
NSLog(@"Address of var2 variable: %x\n", &var2 );
return 0;
}
Objective-C
执行上面示例代码,得到以下结果:
2018-11-15 03:56:08.348 main[108988] Address of var1 variable: fe8568c0
2018-11-15 03:56:08.351 main[108988] Address of var2 variable: fe8568c6
Shell
通过上面代码,了解了什么是内存地址以及如何访问它,到此,概念的基础知识已经结束。 接下来看看什么是指针。
1. 指针是什么?
指针是一个变量,它的值是另一个变量的地址,即存储单元的直接地址。 与任何变量或常量一样,必须先声明指针,然后才能使用它来存储任何变量地址。 指针变量声明的一般形式是 -
type *var_name;
C
这里,type
是指针的基类型; 它必须是有效的Objective-C数据类型,var_name
是指针变量的名称。 用于声明指针的星号*
与用于乘法的星号相同。 但是,在此语句中,星号用于将变量指定为指针。以下是有效的指针声明 -
int *ip; /* 指向 int 类型的指针 */
double *dp; /* 指向 double 类型的指针 */
float *fp; /* 指向 float 类型的指针 */
char *ch /* 指向 char 类型的指针 */
C
所有指针的值是实际数据类型的地址值,无论是整数,浮点数,字符还是其他,都是相同的,是表示内存地址的长十六进制数。 不同数据类型的指针之间的唯一区别是指针指向的变量或常量的数据类型。
2. 如何使用指针?
有一些重要的操作,经常在指针的帮助下完成。使用指针的步骤如下 -
- 定义一个指针变量,
- 将变量的地址赋给指针,
- 最后访问指针变量中可用地址的值。
这是通过使用一元运算符*
来完成的,该运算符*
返回位于操作数指定的地址处的变量值。以下示例使用这些操作 -
#import <Foundation/Foundation.h>
int main () {
int var = 20; /* 变量定义 */
int *ip; /* 指针变量声明 */
ip = &var; /* 在指针变量中存储 var 的地址*/
NSLog(@"Address of var variable: %x\n", &var );
/* 存储在指针变量中的地址 */
NSLog(@"Address stored in ip variable: %x\n", ip );
/* 使用指针访问该值 */
NSLog(@"Value of *ip variable: %d\n", *ip );
return 0;
}
Objective-C
执行上面示例代码,得到以下结果:
2018-11-15 04:05:36.179 main[80041] Address of var variable: 23bea2dc
2018-11-15 04:05:36.183 main[80041] Address stored in ip variable: 23bea2dc
2018-11-15 04:05:36.183 main[80041] Value of *ip variable: 20
Shell
3. Objective-C NULL指针
如果没有要分配的确切地址,最好将NULL
值分配给指针变量。这是在变量声明时完成的。 指定为NULL
的指针称为空指针。
NULL
指针是一个常量,在几个标准库中定义了零值。参考以下程序 -
#import <Foundation/Foundation.h>
int main () {
int *ptr = NULL;
NSLog(@"The value of ptr is : %x\n", ptr );
return 0;
}
Objective-C
执行上面示例代码,得到以下结果:
2018-11-15 04:26:24.203 main[40259] The value of ptr is : 0
Shell
在大多数操作系统上,程序不允许访问地址0
处的内存,因为该内存是由操作系统保留的。 但是,存储器地址0
具有特殊意义; 它表示指针不是指向可访问的内存位置。 但按照惯例,如果指针包含null
(零)值,则假定它不指向内容。
要检查空指针,可以使用if
语句,如下所示 -
if(ptr) /* 如果p不为null,则成立 */
if(!ptr) /* 如果p为null,则成立 */
Objective-C
4. Objective-C指针详解
指针有许多但很简单的概念,它们对Objective-C编程非常重要。以下几个重要的指针概念,对于Objective-C程序员来说应该要清楚 -
编号 | 概念 | 描述 |
---|---|---|
1 | Objective-C指针运算 | 在指针上使用四个算术运算符:++ ,-- ,+ ,- |
2 | Objective-C指针数组 | 可以定义数组以包含许多指针 |
3 | Objective-C指针的指针 | Objective-C允许有指向指针的指针 |
4 | Objective-C将指针传递给函数 | 通过引用或地址传递参数都可以在调用函数中更改传递的参数。 |
5 | Objective-C从函数返回指针 | Objective-C允许函数返回指向局部变量,静态变量和动态分配内存的指针。 |
正如上篇章节中所解释的那样,Objective-C指针是一个地址,它是一个数值。 因此,可以像对数值一样对指针执行算术运算。 可以在指针上使用四个算术运算符:++
,--
,+
和 -
要理解指针运算,假设ptr
是一个整数指针,它指向地址1000
。假设32
位整数,对指针执行以下算术运算 -
ptr++
C
现在,在上述操作之后,ptr
将指向位置1004
,因为每次ptr
递增时,它将指向下一个整数位置,它是当前位置之后的4
个字节。 此操作将指针移动到下一个存储器位置,而不会影响存储器位置的实际值。 如果ptr
指向地址为1000
的字符,则上述操作将指向位置1001
,因为下一个字符在1001
处可用。
1. 递增指针
在程序中使用指针比数组方便,因为变量指针可以递增,不像数组名称,它只是一个常量指针,所以不能递增。 以下程序增加变量指针以访问数组的每个后续元素 -
#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(@"Address of var[%d] = %x\n", i, ptr );
NSLog(@"Value of var[%d] = %d\n", i, *ptr );
/* 移动到下一个位置 */
ptr++;
}
return 0;
}
Objective-C
执行上面示例代码,得到以下结果:
2018-11-15 05:50:37.956 main[195398] Address of var[0] = 518e55a4
2018-11-15 05:50:37.958 main[195398] Value of var[0] = 10
2018-11-15 05:50:37.958 main[195398] Address of var[1] = 518e55a8
2018-11-15 05:50:37.958 main[195398] Value of var[1] = 100
2018-11-15 05:50:37.958 main[195398] Address of var[2] = 518e55ac
2018-11-15 05:50:37.958 main[195398] Value of var[2] = 200
Shell
2. 递减指针
递减指针同样也适用,该指针减少其数据类型的字节数,如下所示 -
#import <Foundation/Foundation.h>
const int MAX = 3;
int main () {
int var[] = {10, 100, 200};
int i, *ptr;
/* 在指针中存储数组地址 */
ptr = &var[MAX-1];
for ( i = MAX; i > 0; i--) {
NSLog(@"Address of var[%d] = %x\n", i, ptr );
NSLog(@"Value of var[%d] = %d\n", i, *ptr );
/* 移动到上一个位置 */
ptr--;
}
return 0;
}
Objective-C
执行上面示例代码,得到以下结果:
2018-11-15 05:53:29.272 main[63838] Address of var[3] = 3667141c
2018-11-15 05:53:29.274 main[63838] Value of var[3] = 200
2018-11-15 05:53:29.274 main[63838] Address of var[2] = 36671418
2018-11-15 05:53:29.274 main[63838] Value of var[2] = 100
2018-11-15 05:53:29.274 main[63838] Address of var[1] = 36671414
2018-11-15 05:53:29.274 main[63838] Value of var[1] = 10
Shell
3. 指针比较
可使用关系运算符比较指针,例如==
,<
和>
。 如果p1
和p2
指向彼此相关的变量,例如同一数组的元素,则可以有意义地比较指针:p1
和p2
。
以下程序通过递增变量指针来修改前一个示例,只要它指向的地址小于或等于数组的最后一个元素的地址,即&var [MAX - 1]
-
#import <Foundation/Foundation.h>
const int MAX = 3;
int main () {
int var[] = {10, 100, 200};
int i, *ptr;
/* 获取到指针中第一个元素的地址*/
ptr = var;
i = 0;
while ( ptr <= &var[MAX - 1] ) {
NSLog(@"Address of var[%d] = %x\n", i, ptr );
NSLog(@"Value of var[%d] = %d\n", i, *ptr );
/* 指向下一个位置 */
ptr++;
i++;
}
return 0;
}
Objective-C
执行上面示例代码,得到以下结果:
2018-11-15 05:55:48.173 main[60442] Address of var[0] = 6a8cb7f4
2018-11-15 05:55:48.175 main[60442] Value of var[0] = 10
2018-11-15 05:55:48.175 main[60442] Address of var[1] = 6a8cb7f8
2018-11-15 05:55:48.175 main[60442] Value of var[1] = 100
2018-11-15 05:55:48.175 main[60442] Address of var[2] = 6a8cb7fc
2018-11-15 05:55:48.175 main[60442] Value of var[2] = 200