摘要:三數組指針數組指針的定義數組指針是指針還是數組答案是指針。所以數組指針應該是能夠指向數組的指針。首先函數指針是一個指針需要先與結合然后在與結合表明指向一個函數里面放函數的形參類型。
首先我們再來回顧一下指針的概念
字符指針一般有兩種:
int main(){ //第一種,指向單個字符 char ch='w'; char* p=&ch; //第二種,指向一個常量字符串 char* ptr="hello world!";//但是ptr存放的是整個字符串嗎? return 0;}
特別容易以為是把常量字符串 hello world! 放到字符指針 ptr 里了,但是本質是把字符串 首字符的地址放到了ptr中,也就是說ptr指向的是’h’的地址,但是字符串在內存中是連續存儲,且串末尾系統自動加上’/0’結尾,所有當用%s輸出字符串時,它會從第一個元素持續輸出到’/0’結束。
那就有這樣的面試題:
#include int main(){ char str1[] = "hello world!"; char str2[] = "hello world!"; char *str3 = "hello world!"; char *str4 = "hello world!"; if(str1 ==str2) printf("str1 and str2 are same/n"); else printf("str1 and str2 are not same/n"); if(str3 ==str4) printf("str3 and str4 are same/n"); else printf("str3 and str4 are not same/n"); return 0;}
請在心中默念出你的答案。
從上面知道,字符指針,數組指針存放的都是元素的首地址,所以比較的就是首地址。
這里str3和str4指向的是一個同一個常量字符串。C/C++會把常量字符串存儲到多帶帶的一個內存區域,當幾個指針。指向同一個字符串的時候,他們實際會指向同一塊內存。但是用相同的常量字符串去初始化不同的數組的時候就會開辟出不同的內存塊。所以str1和str2不同,str3和str4相同。
前面我們也學習了指針數組
這里我們再復習一下,下面指針數組是什么意思?
int* arr1[10]; //整形指針的數組(存放整形指針)char *arr2[4]; //一級字符指針的數組(存放字符指針)char **arr3[5];//二級字符指針的數組(存放二級字符指針)
如何判斷數組存放的類型呢?
很簡單,直接去掉” 數組名[] “剩下的就是數組存放的類型。
數組指針是指針?還是數組?
答案是:指針。
我們可以根據以往的學習來推導,字符指針char* p,整型指針int* p。
所以數組指針應該是:能夠指向數組的指針。
那如何來表示呢
首先它是一個指針,那定義時就需要在變量前加*,其次它指向的類型又是一個數組,所以有以下定義
int arr[10]={0};//定義一個數組指針parr指向arrint (*parr)[10]=&arr;//*parr必須用括號括起來,因為[]的優先級高于*
也可以是從表達式來解釋
parr先和*結合,說明parr是一個指針變量,然后指著指向的是一個大小為10個整型的數組。所以p是一個指針,指向一個數組,叫數組指針。
int main(){ int a = 10; int* pi = &a;//整型的地址存放在整型指針中 char ch = 'w'; char* pc = &ch;//字符的地址存放在字符指針中 int arr[10] = {0}; int* p = arr;// -是數組首元素的地址 //int* parr[10]; //這樣寫是數組 int (*parr)[10] = &arr;//取出的是數組的地址, 應該存放到數組指針中 return 0;}
對于下面的數組:
int arr[10];
arr 和 &arr 分別是啥?
我們知道arr是數組名,數組名表示數組首元素的地址。
那&arr數組名到底是啥?
我們看一段代碼:
#include int main(){ int arr[10] = {0}; printf("%p/n",&arr[0]); printf("%p/n", arr); printf("%p/n", &arr); return 0;}
他們的值是一樣的
所以我們可以得出結論,此時的&arr和arr都是指向數組首元素,是首元素的地址,要注意的一點是他們的類型不同,分別是int ()[10]和int*。
但任何時候arr都是指向數組首元素嗎?
給出結論:arr在不同的地方有不同的含義。
當數組名(arr)除以下兩種情況外都是首元素地址
1. sizeof(數組名), 這里的數組名是表示整個數組的,sizeof(數組名)計算的是整個數組的大小,單位是字節
2. &數組名, 這里的數組名不是首元素的地址,數組名表示整個數組,所以取出的是整個數組的地址
代碼如下:
#include int main(){ int arr[10] = { 0 }; //計算整個數組大小 printf("%d/n", sizeof(arr)); //取出來的地址是整個數組的地址 int(*parr)[10] = &arr; return 0;}
我們來看一下區別
#include int main(){ int arr[10] = { 0 }; //arr是首元素地址 //&arr[0]是首元素地址 //&arr取出數組的地址 printf("%p/n",arr ); printf("%p/n",&arr[0] ); printf("%p/n", &arr); printf("%p/n", arr+1); printf("%p/n", &arr[0]+1); printf("%p/n", &arr+1); printf("%d/n", sizeof(arr)); printf("%d/n", sizeof(&arr)); int(*parr)[10] = &arr; return 0;}
總結:
那數組指針是怎么使用的呢?
既然數組指針指向的是數組,那數組指針中存放的應該是數組的地址。
看代碼:
#include int main(){ int arr[10] = {1,2,3,4,5,6,7,8,9,0}; int (*p)[10] = &arr;//把數組arr的地址賦值給數組指針變量p //但是我們一般很少這樣寫代碼 return 0;}
也就是指向函數的指針,存放函數的地址。
來看一段代碼
#include void test(){ printf("hehe/n");}int main(){ printf("%p/n", test); printf("%p/n", &test); return 0;}
兩個的值都是函數的地址。那怎么保存函數的地址呢?
需要定義一個函數指針來接收函數的地址。
首先函數指針是一個指針,需要先與 * 結合,然后在與 () 結合,表明指向一個函數,()里面放函數的形參類型。還有函數的返回值。
void test(){ printf("hehe/n");}//下面pfun1和pfun2哪個有能力存放test函數的地址?void (*pfun1)();void *pfun2();
void (*pfun1)();//先和*結合,是一個指針,()表示指向一個函數,void表示函數的返回值。void *pfun2();//先和()結合,是函數的聲明,返回值是void*。
int Add(int x,int y){ return x + y;}//定義函數指針int (*p)(int, int)=Add;//也可int (*p)(int, int)=&Add;//使用指針調用函數int ret = p(3, 4);int ret = (*p)(3, 4);
兩段有趣的代碼
//代碼1(*(void (*)())0)();// void (*)() 是一個函數指針類型,函數無返回值,無參//首先將整數0的類型強制轉換為一個函數指針,此時0就是一個函數指針,存放函數的地址,然后對0解引用,再()調用函數,被調用的函數,無參//所以這個代碼是一次函數調用//代碼2void (*signal(int , void(*)(int)))(int);//首先signal先和()結合,是一個函數,函數的參數有兩個,一個類型是int,一個類型是 void(*)(int) 函數指針類型,既然是函數就應該有返回類型//把signal(int , void(*)(int)),去掉后就是函數的返回類型 void(*)(int) ,是一個函數指針,該函數返回類型為空,參數為空。//所以語句本質是一個函數聲明//函數名是signal
函數指針類型看著很復雜,也不方便使用,我們可以使用 typedef 定義一個別名
//我們知道typedef int DataType;//類似定義typedef void(* pfun )(int);//pfun就是類型別名//我們可以直接使用,來定義函數指針變量pfun pAdd = &Add;//同樣也可以把上述void (*signal(int , void(*)(int)))(int);簡化pfun signal(int, pfun);
類似于指針數組,把函數的地址存到一個數組中,那這個數組就叫函數指針數組,那函數指針的數組如何定義呢?
首先,是一個數組,那就要先和下標運算符[]結合,其次才是函數指針類型
int (* arr[10])(int, int);//數組有十個元素,每個元素類型是int (*)(int, int) 函數指針,該函數返回類型是int,有兩個參數,都是int類型。
轉移表
也就是將返回類型,參數個數和類型相同的函數放在一個數組里面,然后應對不同的情況使用數組來調用每個函數。
例如,定義加、減、乘、除四個函數,他們的返回類型,參數個數和類型相同,將他們放在一個數組里面。
int (* arr[4])(int, int)={add, sub, mul, div };//調用int ret = (*p[input])(x, y);
指向函數指針數組的指針是一個 指針 指針指向一個 數組 ,數組的元素都是 函數指針。
定義
首先它是一個指針,先與 * 結合-(*parr),然后再和 [] 結合,表明指向一個數組- (*parr)[4],然后是數組的元素類型-函數指針 int (*) (int, int)
int (*(*parr)[4])(int, int) = &arr;
定義
回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。
#include int Add(int x, int y){ return x + y;}int Sub(int x, int y){ return x - y;}void test(int (*pfun)(int, int)){ int ret = pfun(3, 4);//通過函數指針去調用其他函數 printf("%d/n", ret);}int main(){ test(Add);//將函數的地址作為參數 test(Sub); return 0;}
希望能對你理解深入的指針有所幫助!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/122423.html
摘要:另外,通過指針可以更便捷地操作數組。在一定意義上可以說,指針是語言的精髓。野指針成因除了未初始化還有就是越界訪問或者指針指向空間已經釋放。所以不難知道兩個地址相減就是元素的個數,這個表達式的前提是兩個指針指向同一塊空間。 ...
摘要:指針的大小在位平臺是個字節,在位平臺是個字節。比如的指針解引用就只能訪問一個字節,而的指針的解引用就能訪問四個字節。所以是一個指針,指向一個數組,叫數組指針。 準備...
摘要:自己實現時返回值可根據實際情況而定源字符串必須以結束。語言中給了一些長度受限的字符串函數,而前面的函數是長度不受限的字符串函數。拷貝個字符從源字符串到目標空間。 目錄 字符函數和字符串函數 函數介紹 strlen strcpy strcat strcmp strncpy ?strncat s...
閱讀 713·2023-04-25 19:43
閱讀 3910·2021-11-30 14:52
閱讀 3784·2021-11-30 14:52
閱讀 3852·2021-11-29 11:00
閱讀 3783·2021-11-29 11:00
閱讀 3869·2021-11-29 11:00
閱讀 3557·2021-11-29 11:00
閱讀 6105·2021-11-29 11:00