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

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