C语言基础:指针(三)
字符指针常见错误#include stdio.h int main(int argc, char **argv) { //char *p hello; // hello 在内存中只用一份只能读取不能修改 char p[] hello; // char [] 开辟空间会把hello字符串常量复制一份给数组。 printf(%s\n, p); *(p 0) e; // 如果是指针操作是错误不能修改常量 p[0] e; // 如果是数组操作是对的修改的是数组里的内容不是字符串常量 printf(%s\n, p); return 0; } 函数指针指针函数指针函数函数的返回值是 指针类型 。char *strcpy(char *dest, const char *src); strcpy 这个函数的返回值就是一个指针。 成功指针指向 dest。 1 不能返回是局部作用域的指针。2 希望函数可以连续调用。 在同一个语句里面。 strcpy(str1,strcpy(str3,str2));3希望返回一端内存区域 (数组堆空间)。函数指针前面介绍的指针基本都是指数据。函数指针 指向一个函数。本质指针变量函数名是地址值。里面储存的代码对数据进行加减乘除操作的。目的避免代码的重复。 方便后期代码的扩展。函数功能的解耦合。回调函数 一个函数被当作参数 传递给另外一个函数。 被传递这个参数(函数指针回调函数)被动调用。主调函数只是传参(函数)。语法 int add(int a, int b) // int (*) (int,int) { return a b; } int main(int argc, char **argv) { int (*p)(int, int) add; // p 函数指针。 add 不能写成add(), 不是对add函数的调用 int a 10; int b 20; int ret 0; ret add(a, b); printf(add() is %d\n, ret); ret p(a, b); // 通过函数指针 对函数的调用 printf(p() is %d\n, ret); return 0; }int div3(int num) // div3 - int (*) (int) { return 0 num %3; } int div5(int num) // div3 - int (*) (int) { return 0 num %5; } // int (*fun) (int) 函数指针 void find_num(int* a,int size, int (*fun) (int) ) { for(size_t i0;isize;i) { if( fun(a[i])) // if( div5(a[i])) { printf(%d\n,a[i]); } } } int main(int argc, char **argv) { int a[10]{0}; fill_array(a,10); //find_num3(a,10); find_num(a,10,div5); // 传递函数名给 find_num return 0; } typedef 关键字取别名 给数据类型取别名1 普通数据类型 去别名typedef 老数据类型名 新数据类型名 typedef unsigned char u8; typedef unsigned short u16; typedef char s8; int main(int argc, char **argv) { u8 a; // unsigned char u16 b; // unsigned short s8 c; // char return 0; }简化函数指针的写法PFUN 是一个类型名 typedef int* (*PFUN)(int ,int ,char* ); // int* func(int a,int b ,char* c) // int* (*)(int ,int ,char* ) // { // return NULL; // } // int func2(int a,int b, int* (*pfun)(int ,int ,char* )) // { // return 0; // } int* func(int a,int b ,char* c) // int* (*)(int ,int ,char* ) { return NULL; } int func2(int a,int b, PFUN pfun) // int a; { char str[]{0}; pfun(1,2,str); return 0; }3.和结构体有关晚些介绍指针数组数组指针指针数组本质是一个数组。 数组中数据元素是 指针。指针是字符类型指针用的多。数据类型 * 数组名[整形常量]; int * a[4];char* a[4]{NULL}; char * b[5]{hello,ok,how,are,you}; // 指针指向了字符串常量去只可以读取不可以修改 char str[8][100]{hello,ok,how,are,you}; char *str3[5]{str[0],str[1],str[3]};// 指针指向了数组可以读取可以修改存放字符串使用字符数组操作字符串使用指针。存放多个字符串使用二维字符数组(多个字符串的话)。操作字符串数组使用 指针数组。数组指针对一维数组名执行 取地址操作() , 地址值 不变 类型升级为指向整个数组的指针对数组指针 执行 解引用操作 (*) , 地址值 不变, 类型降为指向第一个元素的指针应用1 需要和二维数组配合使用2 把二维数组作为参数的时候在定义被调函数需要声明 参数的数据类型会用到。#if 0 int a[5] {1, 2, 3, 4, 5}; // int []-- int * printf(a addr %p\n, a); printf(a[0] addr %p\n, a[0]); printf(a[1] addr %p\n, a[1]); printf(a[2] addr %p\n, a[2]); printf(*a addr %d\n, *a); // int printf(a[0] addr %d\n, a[0]); // int printf(*(a1) addr %d\n, *(a 1)); // int printf(a[1] addr %d\n, a[1]); // int printf(a1 addr %p\n, a 1); // int * printf( a %p\n, a); // 数组指针 printf(a1 %p\n, a 1); int(*p)[5] a; // int (*p)[5] 数组指针 int* p[5] // int * p1[5] a; #endif int array2[4][4] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; int(*p2)[4] array2; printf(array2 is addr%p\n, array2); // int [4][4] - int (*)[4] 1 -16byte printf(array2[0] is addr%p\n, array2[0]);// int * 1 4byte printf(array2[0][0] is addr%p\n, array2[0][0]);// int * 1 4byte printf(array2[0][0] is addr%d\n, array2[0][0]); // int printf(a[1][2] %d\n,array2[1][2]); // printf(a[1][2] %d\n,*(array2[1]2)); printf(a[1][2] %d\n,*(*(array21)2)); printf(p2[1][2] %d\n,p2[1][2]); printf(p2[1][2] %d\n,*(p2[1]2)); printf(p2[1][2] %d\n,*(*(p21)2)); printf(a[0] %p\n,array2[0]); printf(a[1] %p\n,array2[1]); printf(p2 %p\n,p2); printf(p21 %p\n,p21); int array2[4][4] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; array2 类型 -》 指针 -》 int [4][4] int(*)[4] 列是4 1 sizeof(int) *4(列) array2[0] -- 指针 -》 int * 第一行的首元素的地址 array2[0][0] array2[0][0] - int - 数据 int(*p2)[4] array2; p2 - 类型 int(*)[4] 1 sizeof(int) *4(列) p2[0] - 类型 int* 第一行的首元素的地址 array2[0][0] p2[0][0] - int - 数据 p2[1] *(p21) 下标运算符 和 解引用运算符的关系。二级指针二级指针本质还是指针是一个指针变量的地址。int **指针名称 ---》保存整形指针的指针 char **指针名称---》保存字符型指针的指针C语言中主要有两个二级指针的使用场景想要在被调函数中修改主调函数中的指针变量实参需要传递该指针变量的地址形参用二级指针接收。指针数组的数组名是一个二级指针实参传递指针数组的数组名时形参可以用二级指针接收。char *str[3] {hello, world, how}; str[0] --- char * ---保存了字符串常量hello的首地址 str str[0] char ** 二级指针值传递无法在被调中修改主调中的变量只能使用该变量指针传参可以在被调中修改主调中定义的变量也可以使用该变量值传递恰好传递的值是一个指针变量无法在被调用修改主调中定义的指针变量可以使用该指针变量。指针传参可以在被调函数中可以修改主调函数中定义的指针变量也可以使用该变量指针函数指针函数本质是函数具有指针类型返回值的函数称为指针函数。指针函数能返回什么指针局部变量的地址不能被返回局部变量局部数组char str[32] {hello world}; char *str hello world;具有静态生命周期的变量的地址可以被返回。static修饰的静态变量地址。全局变量的地址。可以返回字符串常量的地址。char *pstr “hello world”可以返回通过参数传递给该函数的地址。char *strcpy(char *dest, const char *src);可以返回堆区申请且没有被释放的空间地址。函数指针函数指针本质是指针指向函数的指针。函数函数的函数名为函数的入口地址。函数指针语法定义函数指针函数声明 int funint, int; int *pfun(int , int ); 函数指针 int (*pfun)(int , int ); 定义了一个函数指针变量该指针变量在内存占8字节该函数指针可以指向一个具有int返回值两个int类型的参数的函数。 char *(*pfun)(char *); 总结 返回值类型 (*指针名称)形参表函数指针初始化int (*pfun)(int, int) NULL;函数指针赋值int add(int num1, int num2) {} int (*pfun)(int, int) NULL; pfun add;函数指针调用函数函数名(实参表) 函数指针名称(实参表);函数指针的应用回调函数将函数作为某个函数的参数传递传递的函数称为回调函数。主要为了降低代码的耦合度关联度减少重复代码。