// - 在 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
C 语言指针最强解析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.