風(fēng)鈴做的網(wǎng)站能否推廣seo搜索引擎優(yōu)化的內(nèi)容
指針基礎(chǔ)知識:C語言學(xué)習(xí)筆記之指針(一)-CSDN博客
目錄
字符指針
?代碼分析
指針數(shù)組
數(shù)組指針
函數(shù)指針
代碼分析(出自《C陷阱和缺陷》)
函數(shù)指針數(shù)組
指向函數(shù)指針數(shù)組的指針
回調(diào)函數(shù)
qsort()
字符指針
一般用法:
特殊用法:
? ? ? ? 上述代碼的本質(zhì)是把字符串 "hello bit." 的首字符的地址放到了pstr中。因?yàn)?#34;hello bit."是一個常量字符串,是存放在代碼段的數(shù)據(jù),所以不能被修改,因此要用const 修飾來防止權(quán)限的放大。
?代碼分析
????????這里str3和str4指向的是一個同一個常量字符串。C/C++會把常量字符串存儲到單獨(dú)的一個內(nèi)存區(qū)域,當(dāng)幾個指針指向同一個字符串的時(shí)候,他們實(shí)際會指向同一塊內(nèi)存。但是用相同的常量字符串去初始化不同的數(shù)組的時(shí)候就會開辟出不同的內(nèi)存塊。所以str1和str2不同,str3和str4相同。
指針數(shù)組
????????指針數(shù)組是一種數(shù)組,數(shù)組內(nèi)的每個元素的類型是指針類型。
用指針數(shù)組模擬實(shí)現(xiàn)一個二維數(shù)組:
#include <stdio.h>void print(int** arr, int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf("%d ", *(*(arr + i) + j)); //等價(jià)于 printf("%d ", arr[i][j]);//printf("%d ", arr[i][j]);}printf("\n");}}
int main()
{int arr1[] = { 1, 2, 3, 4, 5 };int arr2[] = { 2, 3, 4, 5, 6 };int arr3[] = { 3, 4, 5, 6, 7 };int* arr[] = { arr1, arr2, arr3 };print(arr, 3, 5);return 0;
}
注:模擬的二位數(shù)組在內(nèi)存中并不一定連續(xù)存放,因此它不是真的二維數(shù)組。
數(shù)組指針
????????我們已經(jīng)熟悉:
- ? 整形指針: int * pint; 能夠指向整形數(shù)據(jù)的指針。
- ??浮點(diǎn)型指針: float * pf; 能夠指向浮點(diǎn)型數(shù)據(jù)的指針。
? ? ? ? 同理,數(shù)組指針就是指向數(shù)組的指針,即存放數(shù)組地址的指針變量。
寫一個打印二維數(shù)組的函數(shù),形參是數(shù)組指針:
#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf("%d ", arr[i][j]);}printf("\n");}
}
void print_arr2(int(*arr)[5], int row, int col) //數(shù)組指針接收
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf("%d ", *(*(arr + i) + j));}printf("\n");}
}
int main()
{int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };print_arr1(arr, 3, 5);//數(shù)組名arr,表示首元素的地址//但是二維數(shù)組的首元素是二維數(shù)組的第一行(二維數(shù)組可以看成是一維數(shù)組的數(shù)組,即二維數(shù)組的每個元素是一個一維數(shù)組)//所以這里傳遞的arr,其實(shí)相當(dāng)于第一行的地址,是一維數(shù)組的地址//可以數(shù)組指針來接收printf("\n");print_arr2(arr, 3, 5);return 0;
}
類型分析:
函數(shù)指針
? ? ? ? 函數(shù)也是有地址的,顧名思義,函數(shù)指針就是指向函數(shù)的指針,即存放函數(shù)地址的指針變量。
? ? ? ? 函數(shù)指針類型:函數(shù)返回值類型 (*指針變量名)(函數(shù)參數(shù))。
#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("%p\n", test);printf("%p\n", &test);return 0;
}
? ? ? ? 根據(jù)上述代碼的執(zhí)行結(jié)果我們可以看出,函數(shù)名表示函數(shù)地址,&地址函數(shù)名也表示函數(shù)地址,即 函數(shù)名 == &函數(shù)名,所以?*(&函數(shù)名)== * 函數(shù)名 ,而*(&函數(shù)名)== 函數(shù)名,因此 函數(shù)名 == &函數(shù)名 == * 函數(shù)名。
????????首先,能存儲地址,就要求pfun1或者pfun2是指針,那哪個是指針? 答案是:pfun1可以存放。pfun1先和*結(jié)合,說明pfun1是指針,指針指向的是一個函數(shù),指向的函數(shù)無參數(shù),返回值類型為void。pfun2先和()結(jié)合,表示pfun2是一個沒有參數(shù),返回類型是void* 的函數(shù)。
代碼分析(出自《C陷阱和缺陷》)
(*(void (*)())0)();
void (*signal(int , void(*)(int)))(int);
利用 typedef 簡化上述代碼:
函數(shù)指針數(shù)組
? ? ? ? 存放函數(shù)指針的數(shù)組就叫做函數(shù)指針數(shù)組。
????????parr1 先和 [] 結(jié)合,說明 parr1是數(shù)組,數(shù)組的內(nèi)容是什么呢? 是 int (*)() 類型的函數(shù)指針。
????????函數(shù)指針數(shù)組的用途:轉(zhuǎn)移表
示例(計(jì)算器):
#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //轉(zhuǎn)移表while (input){printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("請選擇:");scanf("%d", &input);if ((input <= 4 && input >= 1)){printf("輸入操作數(shù):");scanf("%d %d", &x, &y);ret = (*p[input])(x, y);}else if (input == 0){printf("程序退出\n");break;}elseprintf("輸入有誤\n");printf("ret = %d\n", ret);}return 0;
}
指向函數(shù)指針數(shù)組的指針
? ? ? ? 顧名思義,指針指向的是一個每個元素是函數(shù)指針的數(shù)組。
回調(diào)函數(shù)
????????回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù),當(dāng)這個指針被用來調(diào)用其所指向的函數(shù)時(shí),我們就說這是回調(diào)函數(shù)。回調(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對該事件或條件進(jìn)行響應(yīng)。回調(diào)函數(shù)是一種泛型編程思維,庫函數(shù) qsort() 就運(yùn)用了回調(diào)函數(shù)。
qsort()
? ? ? ? qsort()可以給任意類型(整型,浮點(diǎn)型,結(jié)構(gòu)體等)的數(shù)據(jù)排序,但是需要我們按要求提供一個比較函數(shù)。
用冒泡排序模擬實(shí)現(xiàn)一個類似 qsort() 的函數(shù):
#include <stdio.h>void swap(char* p1, char* p2, size_t size) //交換arr[j],arr[j+1]這兩個元素
{int i = 0;for (i = 0; i < size; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void*, const void*))
{int i = 0;//趟數(shù)for (i = 0; i < num - 1; i++){int j = 0;//一趟內(nèi)部比較的對數(shù)for (j = 0; j < num - 1 - i; j++){//假設(shè)需要升序cmp返回>0,交換if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0) //兩個元素比較,需要將arr[j],arr[j+1]的地址要傳給cmp{//交換swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}int cmp_int(const void* p1, const void* p2) //回調(diào)函數(shù)
{return *(int*)p1 - *(int*)p2;
}//測試bubble_sort 排序整型數(shù)據(jù)
void test1()
{int arr[10] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(int), cmp_int);
}struct Stu
{char name[20];int age;
};int cmp_stu_by_age(const void* p1, const void* p2) //回調(diào)函數(shù)
{return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}//測試bubble_sort 排序結(jié)構(gòu)體數(shù)據(jù)(比較年齡)
void test2()
{struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 50},{"wangwu", 15} };int sz = sizeof(arr) / sizeof(arr[0]); bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}int cmp_stu_by_name(const void* p1, const void* p2) //回調(diào)函數(shù)
{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}//測試bubble_sort 排序結(jié)構(gòu)體數(shù)據(jù)(比較名字)
void test3()
{struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 50},{"wangwu", 15} };int sz = sizeof(arr) / sizeof(arr[0]);printf("%d\n", sizeof(struct Stu));bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}int main()
{test1();test2();test3();return 0;
}