指針_C語言

基礎(chǔ)

  • 內(nèi)存:是通過連續(xù)的內(nèi)存編號來管理的(內(nèi)存的地址)
  • 指針:指針變量里邊存儲的就是內(nèi)存地址

值和類型

不能簡單通過檢查一個值的位來判斷它的類型,值得類型取決于其使用方式

未初始化和非法指針

int *a;
*a = 12;

訪問未初始化的指針是非法的

指向指針的指針

int a = 12;
int *b = &a;
int **c = &b;
*操作符具有從右向左的結(jié)核性,所以這個表達式相當于*(*c)

定義

*a 間接訪問

通過一個指針訪問它所指向的地址的過程稱為間接訪問(indirection)或解引用指針(dereferencing the pointer),這個用于執(zhí)行間接訪問的操作符是單目操作符*

int a = 10;
int *p = &a;
  • int *p表示:表達式*p產(chǎn)生的結(jié)果類型是int類型
  • int *并不是一個類型,原因如下
int* b,c,d;

這并不是將三個變量聲明為指向整型的指針,b是一個指針,其余兩個變量為普通整型

&b 取地址符

int *pb = &b;// & scanf函數(shù)中有一個取地址符指針變量可以通過地址賦值

%p 指針占位符

printf("%p\n",p);

NULL指針

對一個NULL指針進行解引用操作是非法的

NULL類似于給普通變量賦初始值的0,其實就是地址為0

int *p =NULL;//定義了一個指針變量,初始值為NULL
float*p1 = NULL;//浮點型指針
double *p2 =NULL;
char *p3 =NULL;

指針的算術(shù)運算

int *pp =NULL;
int num1 = 10;

pp = &num1;

printf("%p\n",pp);
printf("%p\n",(pp+1));

指針的算術(shù)運算需要根據(jù)指針類型去計算,指針+ 1是向高位移動一個類型所占的字節(jié)數(shù),指針- 1是向低位移動一個類型所占的字節(jié)數(shù)

printf("%p\n",pp++);
printf("%p\n",++pp);
printf("%p\n",pp);

++ --還是遵循之前++ --運算符法則

指針的重指向

咱們可以讓指針重新指向另一個變量(內(nèi)存的另一塊區(qū)域),這就叫指針的重指向
我們可以通過指針修改內(nèi)存地址上的值

int number1 = 10;
int *pNum1 = &number1;

int number2 = 8;
pNum1 = &number2;

*pNum1 = 9;
printf("%d\n",*pNum1);
printf("%d\n",number2);

用指針交換兩個數(shù)的值

  • 函數(shù)在傳參數(shù)的時候,形式參數(shù)只是拷貝了實際參數(shù)的內(nèi)容或者值,實際參數(shù)并未發(fā)生改變
  • 有了指針我們可以直接操作指針指向的內(nèi)存區(qū)域,然后修改內(nèi)存中的值
int num1 = 12;
int num2 = 16;
swapTwoNumbers(&num1, &num2);
printf("%d %d\n",num1,num2);

指針與數(shù)組的關(guān)系

數(shù)組名就是數(shù)組的地址,它恒等于數(shù)組元素的首地址

實際上*(arr1 + i) = arr[i];

int arr1[4] = {1,2,3,4};
for(inti = 0; i < 4; i++) {
    printf("%p\n",arr1+0);
}

printf("%lu\n",sizeof(arr1));//數(shù)組名雖然是地址,但是我們利用它計算內(nèi)存空間的話,還是根據(jù)里邊存儲的數(shù)據(jù)類型而定

int *pp = &num1;

printf("%lu\n",sizeof(pp));//打印一個單純的變量地址的話,并不是根據(jù)類型而定

printf("%lu\n",sizeof(&num1));

char aa = 'w';
char *pp1 = &aa;

printf("%lu\n",sizeof(pp1));//指針類型所占的字節(jié)數(shù)與計算機本身的計算位數(shù)有關(guān),如果是32位的計算機,指針類型占4個字節(jié),如果是64位的計算機,指針類型占8個字節(jié)
   
short array[4] = {1,2,3,4};

int *p = array;//不匹配的指針類型

數(shù)組名確實能夠打印出數(shù)組元素的首地址,但是如果把數(shù)組名認為就是地址是不準確的,實際上數(shù)組名是一個常量

指針與字符串的關(guān)系

char name[] ="guozhenyan";
char *p1 = name;

printf("%p\n",p1);

for(int i = 0; i <strlen(name); i++) {
    printf("%c\n",*(p1+i));
}

指針數(shù)組

char *a[10] = {"ddd","sdq","das","qwe","cva","btg","aaa","ccc","eee","fff"};

printf("%p\n",a);//數(shù)組指針的地址
printf("%p\n",a+1);//對數(shù)組指針地址進行操作
printf("%p\n",a[0]);//對存的數(shù)據(jù)地址進行操作
printf("%p\n",a[1]);

printf("%p\n",*a);//存的是地址
printf("%p\n",*(a+1));

printf("%c\n",**a);
printf("%c\n",**(a+1));

printf("%c\n",*a[0]);
printf("%c\n",*a[1]);

結(jié)構(gòu)體指針

typedef struct person {
   char name[20];
   int age;
   int score;
}Person;

Person p1 = {"guangguang",16,90};
Person p2 = {"jintao",18,99};
Person p3 = {"wangce",17,88};
      
void printArr(Person*p,intcount){
for(int i = 0; i < count; i++) {
printf("%s,%d,%d\n",(*(p+i)).name,(p+i)->age,(*(p+i)).score);
}
    //使用指針去訪問結(jié)構(gòu)體數(shù)組的成員變量的時候,可以使用-> 
Person arr[3] = {p1,p2,p3};

函數(shù)指針

函數(shù)名跟數(shù)組名類似,實際上它也是一個地址

printf("%p\n",helloWorld);

我們也可以找一個指針,指向函數(shù)名所在的地址.這個指針就是所謂的函數(shù)指針

函數(shù)的指針類型根據(jù)函數(shù)的返回值和參數(shù)而定
返回值類型+ (*指針名) +參數(shù)的類型=函數(shù)指針

void (*p1)() =NULL;
p1 =helloWorld;//聲明
p1();//調(diào)用方式
void (*p2)(int) =NULL;

p2 =printNumber;
p2(31415);

BOOL (*p3)() =backYes;

printf("%d\n",p3());

int (*p4)(int,int) =sum;
printf("%d\n",p4(8,4));

函數(shù)指針可以重新指向別的函數(shù),只要函數(shù)類型一樣就可以重指向

char a[10];

printf("請輸入函數(shù)名:\n");

scanf("%s",a);

int(*p5)(int,int) =NULL;

printf("請輸入a,b的值:\n");

int b,c;
scanf("%d%d",&b,&c);

if(strcmp(a,"maxValue") == 0){
p5 =max;
}else if(strcmp(a,"sum") == 0){
p5 =sum;
}else{
printf("輸入有誤\n");
return 0;
}
//現(xiàn)在p5這個指針并沒有指向認可地址,也可以導致程序崩潰,這種情況叫作野指針

printf("%d\n",p5(b,c));

替換指針類型

typedef int (*pGet)(int,int);//重新定義函數(shù)指針的類型:pGet
//我們利用typedef這個關(guān)鍵字還可以重新定義函數(shù)指針的類型變成一個新的類型*后邊跟上我們新類型的名字

函數(shù)指針的作用

  1. ?函數(shù)指針是OC中block的底層實現(xiàn),OC中block得形式跟函數(shù)指針一模一樣.
  2. ?函數(shù)指針因為可以重指向不同函數(shù),可以起到簡化代碼和解耦合的作用

函數(shù)回調(diào)(用函數(shù)指針作為函數(shù)參數(shù))

int(*p)(int,int) =NULL;
p = max;//函數(shù)指針指向的函數(shù)可能實現(xiàn)的功能比較復雜,或者是公司核心代碼,我們一般程序員不需要知道里面的詳細內(nèi)容,只需要會調(diào)用即可.(面向?qū)ο笳Z言,封裝特性的底層(雛形))

函數(shù)轉(zhuǎn)移表

//常規(guī)寫法
switch ( oper ){
    case ADD:
        result = add( oper1, oper2 );
        break;
    case SUB:
        result = sub( oper1, oper2 );
        break;
    case MUL:
        result = mul( oper1, oper2 );
        break;
    case DIV:
        result = div( oper1, oper2 );
        break;
    ...
}
//使用轉(zhuǎn)移表之后的寫法
double add( double, double );
double sub( double, double );
double mul( double, double );
double div( double, double );
...
double (*oper_func[])( double, double ) = {
    add, sub, mul, div, ...
};
//下面的語句替換前面整條switch語句
result = oper_func[ oper ]( op1, op2 );

范指針

void *p;
memcpy;

類型轉(zhuǎn)換

fptr = (float *) iptr;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容