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