玩转指针与地址

96
LuisX 595a1b60 08f6 4beb 998f 2bf55e230555
2018.04.15 17:28* 字数 583
计算机的核心部件:
  • 中央处理器(CPU)
  • 随机存储器(RAM)
    • 相当于海量的“开关”,中央处理器可以打开、关闭、访问这些开关。
    • 1 个开关保存一位(bit)的信息
    • 8 个开关保存一个字节(Byte)的信息
      • 1 代表(开)
      • 0 代表(关)
内存与CPU
地址
  • 内存是有数字编号的
  • 通常地址用来指代某个特定字节的数据
32位CPU 和 64位CPU
  • 地址的大小不同
  • 32位CPU一次能处理32位,4个字节的数据
  • 64位CPU一次能处理64位,8个字节的数据
如何获取数据起始位置的地址?

程序在计算机运行时,相关的一切数据都会保存在内存中,并有各自的地址。
运算符:&
说明符:%p
输出格式:十六进制

#import <Foundation/Foundation.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {
        int i = 10;
        printf("变量i, 内存地址是 %p\n", &i);
        printf("函数main, 内存地址是 %p\n", main);
    }
}
// 变量i, 内存地址是 0x7ffeee0b855c
// 函数main, 内存地址是 0x101b47ed0

指针

为什么非要使用指针呢?
当遇到比较复杂的数据时,就很有必要用指针来传递地址了

1.很容易地通过数据的起始地址,存取数据。
2.程序不一定能通过拷贝来传递数据。
3.程序一定能通过拷贝、直接传递数据的起始地址。

1.用指针保存地址

*星号,用于声明指针

#import <Foundation/Foundation.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {      
        int i = 10;
        int *p = &i;
        printf("变量i, 内存地址是 %p\n", &i);
        printf("指针p, 内存地址是 %p\n", p);
    }
}
// 变量i, 内存地址是 0x7ffee10b155c
// 指针p, 内存地址是 0x7ffee10b155c
2.通过地址访问数据

*星号,用于访问某个地址的数据, 也成为去引用。

#import <Foundation/Foundation.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {      
        int i = 10;
        int *p = &i;
        printf("变量i, 内存地址是 %p\n", &i);
        printf("指针p, 内存地址是 %p\n", p);
        printf("指针p, 数据是 %d\n", *p);
    }
}
// 变量i, 内存地址是 0x7ffeee52c55c
// 指针p, 内存地址是 0x7ffeee52c55c
// 指针p, 数据是 10
3.通过地址保存数据

*星号,用于赋值表达式中

#import <Foundation/Foundation.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {      
        int i = 10;
        int *p = &i;
        printf("变量i, 内存地址是 %p\n", &i);
        printf("指针p, 内存地址是 %p\n", p);
        printf("指针p, 数据是 %d\n", *p);
        *p = 123;
        printf("指针p, 数据是 %d\n", *p);
        printf("变量i, 数据是 %d\n", i);
    }
}
// 变量i, 内存地址是 0x7ffee9e5e55c
// 指针p, 内存地址是 0x7ffee9e5e55c
// 指针p, 数据是 10
// 指针p, 数据是 123
// 变量i, 数据是 123

不同类型数据占用字节大小

使用sizeof()可以获取某个数据类型的大小

某个特定类型的数据会占用多少字节?sizeof()会返回一个类型为size_t的数
说明符:%zu
输出单位:byte
指针长度:

  • 4字节,32位CPU
  • 8字节,64位CPU
#import <Foundation/Foundation.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {      
        int i = 10;
        int *p = &i;
        printf("变量i, 占用字节是 %zu\n", sizeof(i));
        printf("指针p, 占用字节是 %zu\n", sizeof(p));
    }
}
// 变量i, 占用字节是 4
// 指针p, 占用字节是 8

空指针(NULL)

“空”指针 不指向任何地址,用于明确表示该指针没有指向任何地址。

NULL就是0(地址其实也是数字)
nil 和 NULL 是相等的
Objective-C 中使用 nil 来代表该地址上没有对象

#import <Foundation/Foundation.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {      
        float *a;
        a = NULL;
        if (a) {
            printf("a 不是 NULL");
        } else {
            printf("a 是 NULL");
        }
    }
}
// a 是 NULL

指针声明的代码规范

每次加深对指针的理解,保持良好的代码风格。

#import <Foundation/Foundation.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {
        // 编译会通过,代码风格不够好        
        float *one; // 正确
        float* two; // 错误
        
        // C 语言,允许一行代码生成多个变量
        float x, y, z;
        
        // 同时声明b,c为指针
        float* b, c; // 错误,(b指向float 的指针,c的类型是float)
        float *b *c; // 正确
    }
}
iOS 开源
Web note ad 1