C 语言指针最强解析

// - 在 C语言中, 函数之间传值时候, 想改变谁的值, 就传递谁的地址(也就是谁*类型); 传递了谁的地址, 就可以改变谁 比如, 要改变的数据是 int 类型, 那么传递的参数是 (int *), 要改变的数据是 (int *)类型 , 则传递的参数是 int ** 类型; 相反 ,如果传入的是 int **类型, 那么能改的就是 int* 类型的数据, 如果我们传入的是 int*类型, 那么能改边的就是 int 类型; 
// - (定义类 Class Person) OC 中也是一样的, 如果想在一个函数或者方法中改变一个对象的指向, 这应该传入这个对象的地址, 例如想改变一个 (Person * person) 的指向, 则应该传入一个(Person **per 即 &person) ; 这时候在函数内部的执行 *per = nil; 外边调用的地方的 person的值才会为nil; 但是如果想改变 person 的name,时候, 传递 (Person * person)即可;
// - (定义结构体 Struct Person) C 语言的结构体和上边 OC 的类似; 想改变 (Person preson)指向, 就要传入 (Person  * preson); 想改变 (Person *) 的指向就要传入 (Person **). 想改变 (Person person)的成员, 就要传入一个 (Person *person); 想改变 (Person *person)的成员, 就传入一个 (Person *person);

// - 函数指针的调用
1. 	NSString *(*fn)(id, SEL, NSString *) = (NSString *(*)(id, SEL, NSString *))objc_msgSend;
	fn(self, @selector(method1:), @"呵呵");

2.	((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
	((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);

    // - 调用 IMP 方法
3.	IMP result7 = class_getMethodImplementation([ViewController class], @selector(method0:));
	int (*px)(id, SEL, NSString *) = (int (*)(id, SEL, NSString *))result7;
  // - 下边的两种写法都可以
    1. px(nil, nil, @"ssss");      2. px(self, @selector(method0:), @"ssss");
4.	ivar 和 void *
	// - OC 数据类型和 void* 互转 
    Person *person = [[Person alloc]init];
    void *vp = (__bridge void*)person;
    __unsafe_unretained Person *person = (__bridge Person *)vp;
 
    // - 用 runtime 和 KVC 修改 基本数据类型的值
    int age = 30;
 
    // - 使用 KVC 修改基本数据类型的值
    [person setValue:@(100) forKey:@"age"];
    
    // - 使用 runtime 修改基本数据类型的值
    int age = 10;
    Ivar i = class_getInstanceVariable([person class], "_age");
 
    // - 下边两个效果是一样的  只是上边的有警告, 所以使用下边的方法
    object_setIvar(person, i, (__bridge id)(void *)age);
    object_setIvar(person, i, (__bridge id)(*((void **)&age)));
 
    // -  C语言修改
    /**1. 使用 ivar_getOffset 获取非指针类型的数据 */
    ptrdiff_t ageOffset = ivar_getOffset(class_getInstanceVariable(person.class, "_age"));
    int *ageP = (int *)(person + ageOffset);
    *ageP = 10;
    
    /** 使用2. ivar_getOffset 修改指针类型的数据 */
    ptrdiff_t nameOffset = ivar_getOffset(class_getInstanceVariable(person.class, "_name"));
    void **namePP = (void **)(vp + nameOffset);
    *namePP = @"WXC";
 
    /** 使用3. ivar_getOffset 获取指针类型的数据 */
    ptrdiff_t sonOffset = ivar_getOffset(class_getInstanceVariable(person.class, "_son"));
    void **sonPP = (void **)(person + sonOffset);
    *sonPP = (__bridge_retained void *)son;

/ - 二级指针++;
uint16_t *left_pcm_data;
uint16_t **dst_pcm_data;  
dst_pcm_data = &left_pcm_data; dst_pcm_data =  0x000000016b71e2e8; *dst_pcm_data = 0x0000000162834c00; left_pcm_data = 0x0000000162834c00;
(*dst_pcm_data)++; *dst_pcm_data = 0x0000000162834c02; left_pcm_data = 0x0000000162834c02;
(*dst_pcm_data)++; *dst_pcm_data = 0x0000000162834c04; left_pcm_data = 0x0000000162834c04;
(*dst_pcm_data)++; *dst_pcm_data = 0x0000000162834c06; left_pcm_data = 0x0000000162834c06;
(*dst_pcm_data)++; *dst_pcm_data = 0x0000000162834c08; left_pcm_data = 0x0000000162834c08;
(*dst_pcm_data)++; *dst_pcm_data = 0x0000000162834c0a; left_pcm_data = 0x0000000162834c0a;

// - C语言
#include<stdio.h>

int main(){
/**
指针变量的作用:能够根据一个地址,访问指针变量指向的存储空间(包括取值和赋值)
*/
   int a =90;
   
   // - 定义了一个指针变量 变量名是 p;
   int *p;
   
   // - 指针变量p指向了变量 a (把 a的地址赋值给指针变量 p);
    p = &a;
    
   //    *p // - 访问指针变量 p 指向的存储空间;
    *p =10;

   /**
     *p = 10; 给指针变量 p 所指向的存储空间赋值
     *p       访问指针变量 p 指向的存储空间的值
     */
   printf("%d\n",*p);

int * p  (p = 0xcc08); p + N
就是 p 里边存储的地址 + N* 指针所指向的数据类型所占的字节数 上边的就是加4个字节 就是 0xcc0a

double * p; (p = 0xcc08);p - N
就是 p 里边存储的地址 - N* 指针所指向的数据类型所占的字节数 上边的就是减8个字节 就是 0xcc00
p+N  就是 p + (N * 8)


数组名代表着这个数组的首元素的地址;
numbers[0][0] + 1 的跨度是4 (因为相当于&numbers[0][0][0] + 1 就是 p 里边存储的地址地址+1个指向的数据类型(这里是整数 10)所占的字节数)

numbers[1] + 1 的跨度是 8 (因为相当于&numbers[1][0] + 1 就是 p 里边存储的地址地址+1个指向的数据类型(这里是整形数组{50,60})所占的字节数)

numbers + 1 的跨度是 16 (因为相当于&numbers[0] + 1 就是 p 里边存储的地址地址+1个指向的数据类型(这里是整形二维数组{{10,20}, {30, 40})所占的字节数)

&numbers + 1 的跨度是32 (因为相当于指向整个 numbers 的数组 就是整个三维数组 所占的字节数)

X *p; p =  &X; 这里就是指向 X 整个数据类型的 X 类型的指针;

& Y + N ; 就是 Y 原来存储的地址 + ( N * Y这个数据类型所占的字节数)
   return0;
}

#import "C.h"
@implementation C

- (void)test{
    int a = 10;
    /**普通指针 */
    int *p;
    p = &a;
    
    // 作用同上两句
//    int *p1 = &a; ==  int *p; p = &a;
===========================================================================================================

   /**指向指针的指针 */
    int *po1 = &a;

    // 两个*的作用
    /**
     *  1.第一个作用是指向 int *类型的数据

     *  2.第二个作用是定义一个指针类型的数据
     */

    int **po2 = &po1;
    
    // 分开写 int *(*po2);   po2 = &po1;
    /**
     *  这里 po2是 po1的地址 *po2是 po1的地址里存储的数据 **po2是po1的地址里存储的指针存储的地址指向的数据

     即 **po2 = a;
     *  po1的地址里存储的数据是 a的地址
     */
===========================================================================================================

    /**指针和数组 */
    int ages[5] = {2,4,5,6,70};
    int * p2 = &ages[0];

    // 作用同上
   //    p2 = ages; == int * p2 = &ages[0]
 
   /**三种方式打印数组元素 */
    //    打印数组的第3个元素

    int c;
    c = ages[3];
    c = p2[3];
    c = *(p2 + 2);
===========================================================================================================

    /**指针和字符串 */
    //这个指针变量指向字符串的首字符如果打印 *po3打印的是 i如果打印 po3打印的是 itcase;
    char * po3 = "itcase";
===========================================================================================================
   /**指向函数的指针 */
   1.没有参数和返回值的函数

    // - (*p)是固定写法代表指针变量 p将来会指向一个函数

    // - void 指针变量 p 指向的函数没有返回值

    // -右边的()代表指针变量 p指向的函数没有形参

    // -这句话只是定义一个指向函数的指针

    void (*p)();

    // - 指针变量 p 指向了 test函数(函数名就代表着函数地址)
    p = test;
    // - 调用函数
    (*p)();
//    (*p)(); 同上也是一种调用函数的方式

    2.有参数和返回值的函数

    // - (*p)是固定写法代表指针变量 p将来会指向一个函数

    // - int 指针变量 p 指向的函数返回值是 int类型

    // - 右边的(int, int)代表指针变量 p指向的函数有两个 int类型的参数


    int (*p)(int,int);
     // - 指针变量 p 指向了 sum函数(函数名就代表着函数地址)
    p = sum;

     // - 调用函数
    int c =  p(4,6);
//   int c =  (*p)(4, 6); 同上
}

int sum (int a,int b){

    return a + b;

}

@end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章