通常来说是
和
- typedef
定义都写。
- struct
- typedef structX{
- int x;
- }X;
为了更加清晰明了,拆成两部分来看:
- structS { // 第一部分
- int x;
- };
- typedef structS S; // 第二部分
首先第一部分,在 struct 的命名空间中,定义了唯一的
。此时,你可以用
- S
来定义变量或者函数的参数。比如这样:
- struct S
- voidf(structS argument); // 这里的struct是必需的
第二部分在全局的命名空间中添加了一个叫
的别名,这就允许你这么写了:
- S
- voidf(S argument); // 这里不再需要struct了
既然定义唯一标识的命名空间不同,在 struct 中和全局都定义
就没有问题。因为这不是重复定义唯一标识,而是相当于在不同空间创建不同的标识。
- S
让我们把差别表现得更明显一点:
- typedef struct S {
- int x;
- }
- T;
- voidS() {} // 正确
- // void T() {} // 错误:T已经被定义为struct S的别名了
对于一个变量而言,可以看做由四部分构成:
如果能够理解这两点:1. 变量是怎样存储的,2. 除了名字之外通过其他方式也可以获取变量,那么就几乎可以理解指针的概念了。
先来看一个简单的例子:
- int x = 39;
- int* y = &x;
- printf("x: \n\t value:%d \n\t addr:%p \ny: \n\t value:%d \n\t addr: %p \n",x,&x,*y,&y);
- Output:
- x:
- value:39
- addr:0x7fff5fbff728
- y:
- value:39
- addr: 0x7fff5fbff720
我们着重来看这一行:
- int *y = &x;
,所以是 32 位的 4 字节,64 位的 8 字节。
- int
是这个指针变量的名字;
- y
是把右边的值赋给左边;
- =
,读作 "xx 的地址",是引用的操作符。 引用,意味着将一个已有变量的地址赋给一个指针变量。
- &
所以这一句的意思是:把
的地址赋值给一个类型为
- x
的指针变量
- int
。
- y
反过来,一旦你获取了一个存储着地址的指针变量,通过这个指针很自然就可以获取它指向的值,比如上面例子最后一行打印
可以得到
- *y
的值,这个操作就叫做 解引用 ,也可以理解为 "按图索骥",操作符是 "*",可以读作 "被 xx 指向的值"。
- x
对指针的理解,可以类比快捷方式:
比如我在
路径下创建一个名为
- /Users/calios/Desktop
的文件,打开并输入
- aliasTest.txt
并保存。右键创建快捷方式,并将名为
- This is aliasTest file from Desktop.
的快捷方式扔到
- aliasTest.txt alias
路径下。双击
- /Users/calios/Documents
文件,将文件内容修改为
- aliasTest.txt alias
并保存。当然,聪明如你,肯定知道这时候修改的文件其实是源文件
- This is aliasTest file from Documents.
。此时,无论是从哪个路径下打开文件,看到的都是
- aliasTest.txt
。
- This is aliasTest file from Documents.
同理,身处内存不同区域的指针变量,只要存储着同一个变量的地址,那么指向的值就是相同的。
理解了上面的指针,我们来看函数指针。
- // 函数声明
- voidmyFun(intx);
- void (*funPointer)(int);
- // 函数实现
- voidmyFun(intx)
- {
- printf("myFun: %d\n",x);
- }
- // 函数调用
- funPointer = &myFun; //将myFun函数的地址赋给funPointer变量
- (*funPointer)(200); //通过函数指针变量来调用函数
函数指针和变量指针在语言层面是没有差别的。但是在运行过程中,变量指针是指向堆区、栈区、静态区和全局区;而函数指针指向 text 区,就是代码段。所以函数指针执行括号的时候,会执行汇编的 jump,就是跳转指令到 text 段的代码。
- struct box*p = …;
- p->width = 20;
在处理指向结构体类型的指针时,"->" 可以让你一步实现对指针解引用,并获取指定的字段值。如上面代码中,第二行的 "->" 实现了指针 p 的解引用,并获取了结构体中
字段。
- width
不管结构体的实例是什么——访问其成员其实就是加成员的偏移量。
在使用指针来读取或修改它指向的值时,有时候通过比较两个指针是否指向同一个值是很有用的。
- int data[2] = {
- 99,
- 99
- };
- int * m = &data[0];
- int * n = &data[1];
- if ( * m == *n) { // A
- NSLog(@"the two values are the same");
- } else {
- NSLog(@"the two values ( %p vs %p ) are different", m, n);
- }
观察 A 处的判断条件,如果是
,比较的是两个指针指向的值是否相同,所以会走第一个分支;而如果是
- (*m == *n)
,则比较的是两个指针本身的地址,所以会走第二个分支。
- (m == n)
在 C 语言中的,不指向任何数据的空指针用
表示。例如:
- NULL
- int *p = NULL;
而在 Objective-C 中通常用
表示指向一个空对象,并逐渐摒弃了 C 中用
- nil
表示的方式。
- NULL
同时也要注意,不要试图对 NULL 指针获取解引用,这会导致错误并立即退出程序。
在讲解 C 语言中的内存区块分配之前,先来看一点说明。
通常来说可以把变量分成三种:
接着我们来看五个内存区块:
1. 程序区:也用来指代文本区,是存储可执行程序的二进制代码的区域。
2. 数据区:分成以下两部分,通常位于堆的上面或者栈的上面,但绝不会在堆和栈之间的区域。
。包括未初始化的全局变量、全局常量和局部静态变量。
- bss
、
- malloc
或者
- calloc
等方法。
- realloc
的完整定义是
- malloc
,它可以根据参数、从堆中动态分配一块内存,并返回指向第一个字节的指针,或是在出错的时候返回一个 NULL。
- void *malloc(size_t size)
与
相关的函数还有:
- malloc
:为数组在内存中分配空间。
- calloc()
:重新分配指定大小的内存空间。
- realloc()
:释放之前分配的空间。
- free()
来源: http://www.tuicool.com/articles/nQbeAbe