字符指針變量
在指針的類型中我們知道有一種指針類型為字符指針char* ;
一般使用:
char arr[] = "abcdef";
char* p = arr;
char* pa = "abcdef";//常量字符串,無法修改
char* pa = “abcdef” 這樣編寫的時候,字符的內容是不能修改的,這也變成了常變量,如果強行修改,程序會奔潰(寫入衝突),所有一般使用的時候,會用:
const char* pa ="abcdef";//這樣編寫,如果不小心寫成要修改內部內容時,編譯器會報錯的(提醒)
即
#include <stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%c\n", arr[2]);
printf("%c\n", "abcdef"[2]);
const char* pstr = arr;
printf("%s\n", pstr);
return 0;
}//輸出結果:
//c
//c
//abcdef
代碼const char* pstr = arr; 特別容易讓人以為是把字符串hello bit 放到字符指針pstr 裏了,但是本質是把字符串arr. 首字符的地址放到了pstr中。
數組指針變量是什麼?
之前我們學習了指針數組,指針數組是一種數組,數組中存放的是地址(指針)。
數組指針變量是指針變量?還是數組?
答案是:指針變量。
我們已經熟悉:
• 整形指針變量: int * pint; 存放的是整形變量的地址,能夠指向整形數據的指針。
• 浮點型指針變量: float * pf; 存放浮點型變量的地址,能夠指向浮點型數據的指針。
那數組指針變量應該是:存放的應該是數組的地址,能夠指向數組的指針變量。
數組指針變量:
int arr[10] = 0;
int (*parr)[10] = &arr;
//數組的地址,指向的是數組 --指向的是所有的元素,並不僅僅是第一個元素
解釋:parr先和*結合,説明parr是一個指針變量,然後指針指向的是一個大小為10個整型的數組。所以p是一個指針,指向一個數組,叫 數組指針。
這裏要注意:[]的優先級要高於號的,所以必須加上()來保證p先和結合。
用數組指針訪問數組:
#include <stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int (*p)[10] = &arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0;i < sz;i++)
{
printf("%d ", (*p)[i]);//用數組指針訪問數組
}
//p == &arr
//*p == *&arr -> arr
//*P == arr
//於此類似
//p == arr
//*p == *arr -> arr[0]
return 0;
}
類比 arr 訪問數組,但一般不這麼用
二維數組傳參的本質
有了數組指針的理解,我們就能夠講一下二維數組傳參的本質了。
過去我們有一個二維數組的需要傳參給一個函數的時候,我們是這樣寫的:
#include <stdio.h>
void Print(int arr[3][5],int r,int c)
{
for (int i = 0;i < r;i++)
{
for (int j = 0;j < c;j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,0,1,2,3,4,5,6,7,8,9 };
Print(arr, 3, 5);
return 0;
}//輸出結果:
//1 2 3 4 5
//0 1 2 3 4
//5 6 7 8 9
這裏實參是二維數組,形參也寫成二維數組的形式,那還有什麼其他的寫法嗎?
首先我們再次理解一下二維數組,二維數組其實可以看做是每個元素是一維數組的數組,也就是二維數組的每個元素是一個一維數組。那麼二維數組的首元素就是第一行,是個一維數組。
如下圖:
這是上篇博客中的圖片,這裏可以類比一下:
二維數組的每一個元素其實就是一維數組。
所以二維數組的首元素的地址其實就是一整個一維數組的地址。
所以,根據數組名是數組首元素的地址這個規則,二維數組的數組名錶示的就是第一行的地址,是一維數組的地址。根據上面的例子,第一行的一維數組的類型就是int [5] ,所以第一行的地址的類型就是數組指針類型int(*)[5] 。那就意味着二維數組傳參本質上也是傳遞了地址,傳遞的是第一行這個一維數組的地址,那麼形參也是可以寫成指針形式的。如下:
#include <stdio.h>
void Print(int (*p)[5], int r, int c)
{
for (int i = 0;i < r;i++)
{
for (int j = 0;j < c;j++)
{
printf("%d ", p[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,0,1,2,3,4,5,6,7,8,9 };
Print(arr, 3, 5);
return 0;
}//輸出結果:
//1 2 3 4 5
//0 1 2 3 4
//5 6 7 8 9
形參變化: int arr[3][5] -> (*p)[5]
使用變化: arr[i][j] -> p[i][j]
怎麼理解?
把 arr[] 看成一個數組指針 p
p[i][j] 怎麼理解?p先在二維數組上偏移 i -> p[i] 這樣就得到一個一維數組的數組指針
然後一維數組的數組指針怎麼使用?看上面可知 p[i] 在一維數組的內部上偏移 j 即 p[i][j]。
p[i][j]是二維數組中,int個單位的指針,對此解引用即可。。。
p -> p[i] -> (p+i) -> *(p+i) -> *(p+i)+j -> *(*(p+i)+j)
用這個理解怎麼重新寫這個上面代碼呢?
#include <stdio.h>
void Print(int (*p)[5], int r, int c)
{
for (int i = 0;i < r;i++)
{
for (int j = 0;j < c;j++)
{
printf("%d ", *(*(p + i) + j));//p[i][j] 完全等價
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,0,1,2,3,4,5,6,7,8,9 };
Print(arr, 3, 5);
return 0;
}//輸出結果:
//1 2 3 4 5
//0 1 2 3 4
//5 6 7 8 9
二維數組傳參的本質就是傳遞一維數組的數組指針,(【5】是提示一維數組有幾個元素)。
函數指針變量
函數指針變量的創建
什麼是函數指針變量呢?
函數指針變量應該是用來存放函數地址的,未來通過地址能夠調用函數的。
那麼函數是否有地址呢?
我們做個測試:
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
printf("%p\n", &Add);
printf("%p\n", Add);
return 0;
}//輸出結果:
//00CD13B6
//00CD13B6
確實打印出來了地址,所以函數是有地址的,函數名就是函數的地址,當然也可以通過&函數名的方式獲得函數的地址。
&函數名 和 函數名 都是函數的地址。
如果我們要將函數的地址存放起來,就得創建函數指針變量咯,函數指針變量的寫法其實和數組指針非常類似。如下:
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
//printf("%p\n", &Add);
printf("%p\n", Add);
int (*pf)(int, int) = &Add;//pf 就是函數指針變量
printf("%p\n", pf);
return 0;
}//輸出結果:
//002913B6
//002913B6
(pf)為一個整體,不然變成int * ,就變成普通 int類型 的指針變量了。(int,int)是表示該函數的參數。他是什麼類型?去掉名字的就是該指針的類型 -> int ()(int,int)。
*是優先跟着後面的變量名,提示後面的變量名是一個指針
int *p,q;//p 是int*類型,q是int類型。
函數指針變量的使用
函數的指針變量怎麼使用呢?直接看代碼:
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = &Add;
int ret = (*pf)(2,3);//函數指針的使用 -> * + 指針變量名 + 參數
printf("%d\n", ret);
//正常調用
ret = Add(23, 27);
printf("%d\n", ret);
//剛剛提到,函數名 就是函數地址,那麼能否不用 解引用 直接調用?
ret = pf(29, 46);
printf("%d\n", ret);
//發現 * 是擺設,那麼能否多寫?原則上不行,不方便閲讀,實際上可以。
ret = (*****************************************pf)(12, 7);
printf("%d\n", ret);
return 0;
}//輸出結果:
//5
//50
//75
//19
1.有趣的代碼
2.有趣的代碼
函數指針數組
數組是一個存放相同類型數據的存儲空間,那要把函數的地址存到一個數組中,那這個數組就叫函數指針數組,那函數指針的數組如何定義呢?如:
int Add(int x,int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int main()
{
int (*pf_A)(int, int) = Add;
int (*pf_S)(int, int) = Sub;
int (*pf_arr[2])(int, int) = { Add,Sub };
return 0;
}
函數指針數組的 類型 必須是一致的(int (*)(int,int))
怎麼使用?
#include <stdio.h>
int Add(int x,int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int main()
{
int (*pf_A)(int, int) = Add;
int (*pf_S)(int, int) = Sub;
int (*pf_arr[2])(int, int) = { Add,Sub };
int c = pf_arr[0](8,2);
printf("%d ", c);
c = pf_arr[1](8, 2);
printf("%d ", c);
return 0;
}
使用的時候,先用數組存儲起來,然後調用對應的元素,並且傳參,他會有返回值。
完