[Objective-C语言教程]指针(15)
每个变量都是一个内存位置,每个内存位置都定义了它的地址,可以使用符号(&
)运算符进行访问,该运算符表示内存中的地址。
考虑以下示例,它将打印定义的变量的地址 -
1 #import <Foundation/Foundation.h> 2 3 int main () { 4 int var1; 5 char var2[10]; 6 7 NSLog(@"Address of var1 variable: %x\n", &var1 ); 8 NSLog(@"Address of var2 variable: %x\n", &var2 ); 9 10 return 0; 11 }
执行上面示例代码,得到以下结果:
1 2018-11-15 03:56:08.348 main[108988] Address of var1 variable: fe8568c0 2 2018-11-15 03:56:08.351 main[108988] Address of var2 variable: fe8568c6
通过上面代码,了解了什么是内存地址以及如何访问它,到此,概念的基础知识已经结束。 接下来看看什么是指针。
1. 指针是什么?
指针是一个变量,它的值是另一个变量的地址,即存储单元的直接地址。 与任何变量或常量一样,必须先声明指针,然后才能使用它来存储任何变量地址。 指针变量声明的一般形式是 -
type *var_name;
这里,type
是指针的基类型; 它必须是有效的Objective-C数据类型,var_name
是指针变量的名称。 用于声明指针的星号*
与用于乘法的星号相同。 但是,在此语句中,星号用于将变量指定为指针。以下是有效的指针声明 -
1 int *ip; /* 指向 int 类型的指针 */ 2 double *dp; /* 指向 double 类型的指针 */ 3 float *fp; /* 指向 float 类型的指针 */ 4 char *ch /* 指向 char 类型的指针 */
所有指针的值是实际数据类型的地址值,无论是整数,浮点数,字符还是其他,都是相同的,是表示内存地址的长十六进制数。 不同数据类型的指针之间的唯一区别是指针指向的变量或常量的数据类型。
2. 如何使用指针?
有一些重要的操作,经常在指针的帮助下完成。使用指针的步骤如下 -
- 定义一个指针变量,
- 将变量的地址赋给指针,
- 最后访问指针变量中可用地址的值。
这是通过使用一元运算符*
来完成的,该运算符*
返回位于操作数指定的地址处的变量值。以下示例使用这些操作 -
1 #import <Foundation/Foundation.h> 2 3 int main () { 4 int var = 20; /* 变量定义 */ 5 int *ip; /* 指针变量声明 */ 6 ip = &var; /* 在指针变量中存储 var 的地址*/ 7 8 NSLog(@"Address of var variable: %x\n", &var ); 9 10 /* 存储在指针变量中的地址 */ 11 NSLog(@"Address stored in ip variable: %x\n", ip ); 12 13 /* 使用指针访问该值 */ 14 NSLog(@"Value of *ip variable: %d\n", *ip ); 15 16 return 0; 17 }
执行上面示例代码,得到以下结果:
1 2018-11-15 04:05:36.179 main[80041] Address of var variable: 23bea2dc 2 2018-11-15 04:05:36.183 main[80041] Address stored in ip variable: 23bea2dc 3 2018-11-15 04:05:36.183 main[80041] Value of *ip variable: 20
3. NULL指针
如果没有要分配的确切地址,最好将NULL
值分配给指针变量。这是在变量声明时完成的。 指定为NULL
的指针称为空指针。
NULL
指针是一个常量,在几个标准库中定义了零值。参考以下程序 -
1 #import <Foundation/Foundation.h> 2 3 int main () { 4 int *ptr = NULL; 5 NSLog(@"The value of ptr is : %x\n", ptr ); 6 return 0; 7 }
执行上面示例代码,得到以下结果:
2018-11-15 04:26:24.203 main[40259] The value of ptr is : 0
在大多数操作系统上,程序不允许访问地址0
处的内存,因为该内存是由操作系统保留的。 但是,存储器地址0
具有特殊意义; 它表示指针不是指向可访问的内存位置。 但按照惯例,如果指针包含null
(零)值,则假定它不指向内容。
要检查空指针,可以使用if
语句,如下所示 -
1 if(ptr) /* 如果p不为null,则成立 */ 2 if(!ptr) /* 如果p为null,则成立 */
4. 指针详解
指针有许多但很简单的概念,它们对Objective-C编程非常重要。以下几个重要的指针概念,对于Objective-C程序员来说应该要清楚 -
编号 | 概念 | 描述 |
---|---|---|
1 | Objective-C指针运算 |
在指针上使用四个算术运算符:++ ,-- ,+ ,-
|
2 | Objective-C指针数组 | 可以定义数组以包含许多指针 |
3 | Objective-C指针的指针 | Objective-C允许有指向指针的指针 |
4 | Objective-C将指针传递给函数 | 通过引用或地址传递参数都可以在调用函数中更改传递的参数。 |
5 | Objective-C从函数返回指针 | Objective-C允许函数返回指向局部变量,静态变量和动态分配内存的指针。 |
4.1 指针运算
正如上篇章节中所解释的那样,Objective-C指针是一个地址,它是一个数值。 因此,可以像对数值一样对指针执行算术运算。 可以在指针上使用四个算术运算符:++
,--
,+
和 -
要理解指针运算,假设ptr
是一个整数指针,它指向地址1000
。假设32
位整数,对指针执行以下算术运算 -
ptr++
现在,在上述操作之后,ptr
将指向位置1004
,因为每次ptr
递增时,它将指向下一个整数位置,它是当前位置之后的4
个字节。 此操作将指针移动到下一个存储器位置,而不会影响存储器位置的实际值。 如果ptr
指向地址为1000
的字符,则上述操作将指向位置1001
,因为下一个字符在1001
处可用。
4.11 递增指针
在程序中使用指针比数组方便,因为变量指针可以递增,不像数组名称,它只是一个常量指针,所以不能递增。 以下程序增加变量指针以访问数组的每个后续元素 -
1 #import <Foundation/Foundation.h> 2 3 const int MAX = 3; 4 5 int main () { 6 int var[] = {10, 100, 200}; 7 int i, *ptr; 8 9 /* 在指针中存储数组地址*/ 10 ptr = var; 11 for ( i = 0; i < MAX; i++) { 12 NSLog(@"Address of var[%d] = %x\n", i, ptr ); 13 NSLog(@"Value of var[%d] = %d\n", i, *ptr ); 14 15 /* 移动到下一个位置 */ 16 ptr++; 17 } 18 return 0; 19 }
执行上面示例代码,得到以下结果:
1 2018-11-15 05:50:37.956 main[195398] Address of var[0] = 518e55a4 2 2018-11-15 05:50:37.958 main[195398] Value of var[0] = 10 3 2018-11-15 05:50:37.958 main[195398] Address of var[1] = 518e55a8 4 2018-11-15 05:50:37.958 main[195398] Value of var[1] = 100 5 2018-11-15 05:50:37.958 main[195398] Address of var[2] = 518e55ac 6 2018-11-15 05:50:37.958 main[195398] Value of var[2] = 200
4.12 递减指针
递减指针同样也适用,该指针减少其数据类型的字节数,如下所示 -
1 #import <Foundation/Foundation.h> 2 3 const int MAX = 3; 4 5 int main () { 6 int var[] = {10, 100, 200}; 7 int i, *ptr; 8 9 /* 在指针中存储数组地址 */ 10 ptr = &var[MAX-1]; 11 for ( i = MAX; i > 0; i--) { 12 NSLog(@"Address of var[%d] = %x\n", i, ptr ); 13 NSLog(@"Value of var[%d] = %d\n", i, *ptr ); 14 15 /* 移动到上一个位置 */ 16 ptr--; 17 } 18 return 0; 19 }
执行上面示例代码,得到以下结果:
1 2018-11-15 05:53:29.272 main[63838] Address of var[3] = 3667141c 2 2018-11-15 05:53:29.274 main[63838] Value of var[3] = 200 3 2018-11-15 05:53:29.274 main[63838] Address of var[2] = 36671418 4 2018-11-15 05:53:29.274 main[63838] Value of var[2] = 100 5 2018-11-15 05:53:29.274 main[63838] Address of var[1] = 36671414 6 2018-11-15 05:53:29.274 main[63838] Value of var[1] = 10
4.13. 指针比较
可使用关系运算符比较指针,例如==
,<
和>
。 如果p1
和p2
指向彼此相关的变量,例如同一数组的元素,则可以有意义地比较指针:p1
和p2
。
以下程序通过递增变量指针来修改前一个示例,只要它指向的地址小于或等于数组的最后一个元素的地址,即&var [MAX - 1]
-
1 #import <Foundation/Foundation.h> 2 3 const int MAX = 3; 4 5 int main () { 6 int var[] = {10, 100, 200}; 7 int i, *ptr; 8 9 /* 获取到指针中第一个元素的地址*/ 10 ptr = var; 11 i = 0; 12 13 while ( ptr <= &var[MAX - 1] ) { 14 NSLog(@"Address of var[%d] = %x\n", i, ptr ); 15 NSLog(@"Value of var[%d] = %d\n", i, *ptr ); 16 17 /* 指向下一个位置 */ 18 ptr++; 19 i++; 20 } 21 return 0; 22 }
执行上面示例代码,得到以下结果:
1 2018-11-15 05:55:48.173 main[60442] Address of var[0] = 6a8cb7f4 2 2018-11-15 05:55:48.175 main[60442] Value of var[0] = 10 3 2018-11-15 05:55:48.175 main[60442] Address of var[1] = 6a8cb7f8 4 2018-11-15 05:55:48.175 main[60442] Value of var[1] = 100 5 2018-11-15 05:55:48.175 main[60442] Address of var[2] = 6a8cb7fc 6 2018-11-15 05:55:48.175 main[60442] Value of var[2] = 200
4.2 指针数组
在理解指针数组的概念之前,先来看看以下示例,在这个示例中使用3
个整数的数组 -
1 #import <Foundation/Foundation.h> 2 3 const int MAX = 3; 4 5 int main () { 6 int var[] = {10, 100, 200}; 7 int i; 8 9 for (i = 0; i < MAX; i++) { 10 NSLog(@"Value of var[%d] = %d\n", i, var[i] ); 11 } 12 return 0; 13 }
执行上面示例代码,得到以下结果:
1 2018-11-15 05:57:51.168 main[13412] Value of var[0] = 10 2 2018-11-15 05:57:51.170 main[13412] Value of var[1] = 100 3 2018-11-15 05:57:51.170 main[13412] Value of var[2] = 200
如果想要维护一个数组,该数组可以存储指向int
或char
或任何其他可用数据类型的指针。 以下是一个指向整数的指针数组的声明 -
int *ptr[MAX];
这将ptr
声明为MAX
整数指针的数组。 因此,ptr
中的每个元素现在都包含一个指向int
类型值的指针。 下面的例子使用了三个整数,它们将存储在一个指针数组中,如下所示 -
1 #import <Foundation/Foundation.h> 2 3 const int MAX = 3; 4 5 int main () { 6 int var[] = {10, 100, 200}; 7 int i, *ptr[MAX]; 8 9 for ( i = 0; i < MAX; i++) { 10 ptr[i] = &var[i]; /* 分配整数的地址. */ 11 } 12 for ( i = 0; i < MAX; i++) { 13 NSLog(@"Value of var[%d] = %d\n", i, *ptr[i] ); 14 } 15 return 0; 16 }
执行上面示例代码,得到以下结果 -
1 2018-11-15 06:00:41.868 main[84495] Value of var[0] = 10 2 2018-11-15 06:00:41.870 main[84495] Value of var[1] = 100 3 2018-11-15 06:00:41.870 main[84495] Value of var[2] = 200
还可以使用指向字符的指针数组来存储字符串列表,如下所示 -
1 #import <Foundation/Foundation.h> 2 3 const int MAX = 4; 4 5 int main () { 6 char *names[] = {"Yiibai Su", "Hina Lee", "XNew Luang", "Kaops Ali",}; 7 int i = 0; 8 for ( i = 0; i < MAX; i++) { 9 NSLog(@"Value of names[%d] = %s\n", i, names[i] ); 10 } 11 12 return 0; 13 }
执行上面示例代码,得到以下结果:
1 2018-11-15 06:02:10.526 main[126578] Value of names[0] = Yiibai Su 2 2018-11-15 06:02:10.528 main[126578] Value of names[1] = Hina Lee 3 2018-11-15 06:02:10.528 main[126578] Value of names[2] = XNew Luang 4 2018-11-15 06:02:10.528 main[126578] Value of names[3] = Kaops Ali
4.3 指针的指针
指向指针的指针是多个间接或指针链的形式。 通常,指针包含变量的地址。 当定义指向指针的指针时,第一个指针包含第二个指针的地址,它指向包含实际值的位置,如下所示。
必须声明一个指向指针的指针的变量。 这是通过在名称前面放置一个额外的星号(*
)来完成的。 例如,以下是声明指向int
类型指针的指针的声明 -
int **var;
当目标值由指针指向间接指向时,访问该值需要使用两个星号(**
)运算符,如下例所示 -
1 #import <Foundation/Foundation.h> 2 3 int main () { 4 int var; 5 int *ptr; 6 int **pptr; 7 8 var = 250; 9 10 /* 取 var 变量的地址 */ 11 ptr = &var; 12 13 /* 使用运算符 & 地址获取 ptr的地址 */ 14 pptr = &ptr; 15 16 /* 使用 pptr取值 */ 17 NSLog(@"Value of var = %d\n", var ); 18 NSLog(@"Value available at *ptr = %d\n", *ptr ); 19 NSLog(@"Value available at **pptr = %d\n", **pptr); 20 21 return 0; 22 }
执行上面示例代码,得到以下结果:
1 2018-11-15 06:16:20.652 main[137834] Value of var = 250 2 2018-11-15 06:16:20.655 main[137834] Value available at *ptr = 250 3 2018-11-15 06:16:20.655 main[137834] Value available at **pptr = 250
4.4 将指针传递给函数
Objective-C编程语言允许传递指针作为参数给函数。为此,只需将函数的参数声明为指针类型即可。
下面这个例子中,将一个unsigned long
指针传递给一个函数并在函数内部的更改参数的值,它反映在调用的函数中 -
1 #import <Foundation/Foundation.h> 2 3 @interface SampleClass:NSObject 4 - (void) getSeconds:(int *)par; 5 @end 6 7 @implementation SampleClass 8 9 - (void) getSeconds:(int *)par { 10 /* 获取当前秒数 */ 11 //*par = time( NULL ); 12 *par = 111; 13 return; 14 } 15 16 @end 17 18 int main () { 19 20 int sec=100; 21 22 SampleClass *sampleClass = [[SampleClass alloc]init]; 23 [sampleClass getSeconds:&sec]; 24 25 /* 打印实际的值 */ 26 NSLog(@"Number of seconds: %d\n", sec ); 27 28 return 0; 29 }
执行上面示例代码,得到以下结果:
2018-11-15 06:23:36.731 main[14937] Number of seconds: 111
函数可以接受指针,也可以接受一个数组,如下例所示 -
1 #import <Foundation/Foundation.h> 2 3 @interface SampleClass:NSObject 4 /* function declaration */ 5 - (double) getAverage:(int *)arr ofSize:(int) size; 6 @end 7 8 @implementation SampleClass 9 10 - (double) getAverage:(int *)arr ofSize:(int) size { 11 int i, sum = 0; 12 double avg; 13 14 for (i = 0; i < size; ++i) { 15 sum += arr[i]; 16 } 17 18 avg = (double)sum / size; 19 return avg; 20 } 21 22 @end 23 24 int main () { 25 26 /* 定义一个有 5 个元素的数组 */ 27 int balance[5] = {99, 92, 93, 87, 90}; 28 double avg; 29 30 SampleClass *sampleClass = [[SampleClass alloc]init]; 31 /* 将指针传递给数组作为参数 */ 32 avg = [sampleClass getAverage: balance ofSize: 5 ] ; 33 34 /* 输出函数返回结果值 */ 35 NSLog(@"Average value is: %f\n", avg ); 36 37 return 0; 38 }
执行上面示例代码,得到以下结果:
2018-11-15 06:26:49.117 main[134265] Average value is: 92.200000
4.5 从函数返回指针
在上一节中,学习了Objective-C编程语言如何从函数返回数组。类似的,Objective-C也允许从函数返回指针。为此,必须声明一个返回指针的函数,如下例所示 -
1 int * myFunction() { 2 . 3 . 4 . 5 }
要记住的第二点是,将局部变量的地址返回到函数外部并不是一个做法,因此需要将局部变量定义为静态变量。
现在,考虑以下函数,它将生成10
个随机数并使用数组名称返回它们,该数组名称表示指针,即第一个数组元素的地址。
1 #import <Foundation/Foundation.h> 2 3 /* 用于生成和返回随机数的函数 */ 4 int * getRandom( ) { 5 static int r[10]; 6 int i; 7 8 /* 设置随机数的种子 */ 9 srand( (unsigned)time( NULL ) ); 10 for ( i = 0; i < 10; ++i) { 11 r[i] = rand(); 12 NSLog(@"%d\n", r[i] ); 13 } 14 15 return r; 16 } 17 18 /* 调用上面定义的函数的主函数 */ 19 int main () { 20 21 /* 一个指向 int 的指针 */ 22 int *p; 23 int i; 24 25 p = getRandom(); 26 for ( i = 0; i < 10; i++ ) { 27 NSLog(@"*(p + [%d]) : %d\n", i, *(p + i) ); 28 } 29 30 return 0; 31 }
执行上面示例代码,得到以下结果:
1 2018-11-15 06:32:31.948 main[61953] 1167938093 2 2018-11-15 06:32:31.950 main[61953] 1512817253 3 2018-11-15 06:32:31.950 main[61953] 1354576836 4 2018-11-15 06:32:31.950 main[61953] 1468996356 5 2018-11-15 06:32:31.950 main[61953] 965738374 6 2018-11-15 06:32:31.950 main[61953] 92597726 7 2018-11-15 06:32:31.950 main[61953] 206939477 8 2018-11-15 06:32:31.950 main[61953] 1164748971 9 2018-11-15 06:32:31.950 main[61953] 1551275529 10 2018-11-15 06:32:31.950 main[61953] 2005498026 11 2018-11-15 06:32:31.950 main[61953] *(p + [0]) : 1167938093 12 2018-11-15 06:32:31.950 main[61953] *(p + [1]) : 1512817253 13 2018-11-15 06:32:31.950 main[61953] *(p + [2]) : 1354576836 14 2018-11-15 06:32:31.950 main[61953] *(p + [3]) : 1468996356 15 2018-11-15 06:32:31.950 main[61953] *(p + [4]) : 965738374 16 2018-11-15 06:32:31.950 main[61953] *(p + [5]) : 92597726 17 2018-11-15 06:32:31.950 main[61953] *(p + [6]) : 206939477 18 2018-11-15 06:32:31.950 main[61953] *(p + [7]) : 1164748971 19 2018-11-15 06:32:31.950 main[61953] *(p + [8]) : 1551275529 20 2018-11-15 06:32:31.950 main[61953] *(p + [9]) : 2005498026
转载于:https://www.cnblogs.com/strengthen/p/10564055.html
[Objective-C语言教程]指针(15)相关推荐
- c语言教程指针,(转)C语言指针5分钟教程
指针.引用和取值 什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量.在这份教程里"引用"表示计算机内存地址.从指针指向的内存读取数据称作指针的取值 ...
- 高级C语言教程-指针和存储
讲一讲C语言中的值传递引用还有地址传递: 以下面的一段代码为例: void GetMemory(char *p) {p = (char *) malloc(100); } void Test(void ...
- c 调用易语言dll字节集,易语言教程指针到字节集及dll调用
本节课示范了易语言两个高级命令指针到文本()和指针到字节集(),以及易语言dll的制作及调用. 指针到字节集 调用格式: 〈字节集〉 指针到字节集 (整数型 内存数据指针,整数型 内存数据长度) - ...
- 史上最强C语言教程----指针(初阶)
目录 1.指针是什么? 2. 指针和指针类型 2.1 指针+-整数 2.2 指针的解引用 3. 野指针 3.1 野指针成因 3.2 如何规避野指针 4. 指针运算 4.1 指针+-整数 4.2 指针- ...
- 二十万字带你入门C语言-史上最强C语言教程(汇总篇)
一.前言 至此,史上最强C语言教程系列已经全部完成,今天是给大家来做一个汇总,笔者目前已经完成了C语言阶段的学习,一直以来感谢大家的陪伴与支持,笔者后续还会继续更新C++.数据结构.Linux.Mys ...
- Swift3.0语言教程使用指针创建和初始化字符串
Swift3.0语言教程使用指针创建和初始化字符串 Swift3.0语言教程使用指针创建和初始化字符串苹果的Swift团队花了不少功夫来支持C的一些基础特性.C语言中为我们提供了指针,Swift也不例 ...
- C语言 函数指针和指针函数区别 - C语言零基础入门教程
目录 一.函数指针和指针函数声明的区别 1.函数指针 2.指针函数 二.函数指针和指针函数调用的区别 1.函数指针的调用 2.指针函数的调用 三.猜你喜欢 零基础 Python 学习路线推荐 : C/ ...
- C语言 函数指针 - C语言零基础入门教程
目录 一.函数指针简介 1.常规函数声明 2.函数指针声明 二.函数指针实战 三.猜你喜欢 零基础 Python 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.函数指 ...
- C语言 野指针 - C语言零基础入门教程
目录 一.简介 二.野指针产生的原因 1.指针变量未初始化 2.指针释放后之后未置空 三.避免野指针产生 1.初始化时置 NULL 2.释放时置 NULL 四.猜你喜欢 零基础 C/C++ 学习路线推 ...
最新文章
- 6个你必须知道的机器学习的革命性的教训
- adf4351_使用ADF BC管理保存点
- 打印modal框中在线生成的二维码
- Python 3.x对MySQL数据库的常用操作
- MVCWebForm对照学习:文件上传(以图片为例)
- codeblock 安装debug调试
- 手机自带计算机的功能,手机上的这3个小功能,比电脑方便好用,你知道吗?...
- CCF NOI1075 F函数
- 《java就业培训教程》读书笔记
- JavaScript document对象
- 手机电脑Mac地址修改方法
- Pixelmator for mac(图片编辑处理工具) v3.8.1激活版
- 测试类型(αβ测试 、AB测试)
- keystone的详细功能
- echarts-JSON请求数据
- Unity3D 制作调色板
- 自动控制原理9.1---线性系统的状态空间描述(中上)
- 最新版本交易猫钓鱼源码
- 以色列军方对哈马斯发起“城墙卫士行动”:全球首个AI战争
- excel快速输入金额大写
热门文章
- 餐饮到底怎么做才能提升利润?
- 浅析遗传算法在规划中应用
- EMNLP 2018 | 基于短语和神经网络的无监督机器翻译
- 如何关闭苹果手机自动扣费_抖音很火,剪辑软件也很火,下载软件后岂料每月自动扣费?快看你手机有没有...
- IDEA插件外部下载好后如何使用
- springboot毕设项目餐饮管理系统qpa33(java+VUE+Mybatis+Maven+Mysql)
- 【一文学会文件上传】SpringBoot+form表单实现文件上传
- 二叉树前序遍历-迭代
- git配置用户名密码、生成ssh。添加到github
- 两个list 合并成新一个list