flash网站收录怎样建设邮箱网站
news/
2025/9/23 9:26:14/
文章来源:
flash网站收录,怎样建设邮箱网站,网络公司经营范围和管理条例,机械厂网站建设欢迎来到白刘的领域 Miracle_86.-CSDN博客
系列专栏 C语言知识
先赞后看#xff0c;已成习惯 创作不易#xff0c;多多支持#xff01; 目录 一、 字符指针变量
二、数组指针变量
2.1 数组指针变量是什么
2.2 数组指针变量如何初始化 三、二维数组传参本质 四、函数…欢迎来到白刘的领域 Miracle_86.-CSDN博客
系列专栏 C语言知识
先赞后看已成习惯 创作不易多多支持 目录 一、 字符指针变量
二、数组指针变量
2.1 数组指针变量是什么
2.2 数组指针变量如何初始化 三、二维数组传参本质 四、函数指针变量
4.1 函数指针变量的创建
4.2 函数指针的使用
4.3 两段有意思的代码
4.3.1 typedef关键字 五、函数指针数组 六、转移表 一、 字符指针变量
指针的类型中有一种为字符指针char*。
一般我们使用的时候是这么使用的
int main()
{char ch w;char *pc ch;*pc w;return 0;
}
其实还有一种方法
int main()
{const char* pstr hello bit.;//这⾥是把⼀个字符串放到pstr指针变量⾥了吗printf(%s\n, pstr);return 0;
}
其实上述方法是将字符串的首字符的地址放在了指针pstr里了也就是字符h的地址。 《剑指offer》中收录了这样一道题
#include stdio.h
int main()
{char str1[] hello bit.;char str2[] hello bit.;const char* str3 hello bit.;const char* str4 hello bit.;if (str1 str2)printf(str1 and str2 are same\n);elseprintf(str1 and str2 are not same\n);if (str3 str4)printf(str3 and str4 are same\n);elseprintf(str3 and str4 are not same\n);return 0;
}
来看运行结果 你猜对结果了嘛下面我们来简单讲解一下这道题。
首先四个字符串str1.2.3.4在3和4的前面用const修饰了所以这里的str3和str4是常量字符串。
而在C/C中对于一个常量字符串是不会额外开辟空间的所以str3和str4的首地址是一个地址所以两个字符串也是相同的。而str1和str2不是常量字符串是可修改操作的所以分别开辟了两个空间来存放这两个字符串因此它俩的首字符地址也不相同所以两个字符串也不相同。
二、数组指针变量
2.1 数组指针变量是什么
前面我们学习了一个类似非常容易混淆的叫指针数组当时也挖坑了说以后会讲这个。 灵魂指针教给二-CSDN博客 我们之前说指针数组它是数组那数组指针呢是指针
我们已经熟悉 整型指针变量int * pint; 用来存放整型变量的地址能指向整型数据的指针。 浮点型指针变量float * pint; 用来存放浮点型变量的地址能指向浮点型数据的指针。 所以我们能推断出数组指针它是用来存放数组地址能指向数组的指针。
来思考下面两行代码分别是什么
int *p1[10];
int (*p2)[10];
第一行是在前面我们学的指针数组第二行为数组指针。
如何去记忆呢我们要记住一个点就好就是[ ]的优先级是比 * 高的我们去看变量名和谁先结合就好第一行先和中括号结合所以是数组变量名为数组名第二行加了小括号所以先和*结合成了数组指针。
那数组指针的类型是什么呢我们在学习数组的时候说去掉数组名剩下的就是类型那来看看数组指针的类型怎么写呢
int (*)[10];
2.2 数组指针变量如何初始化 数组指针用来存放数组的地址那怎么获取数组的地址呢没错就是我们之前说的arr。
int arr[10] {0};
arr;//得到的就是数组的地址
如果要存放整个数组的地址就存放在数组指针中
int(*p)[10] arr; 我们调试也能看到arr和p的地址是一样的。
数组指针类型解析
int (*p) [10] arr;| | || | || | p指向数组的元素个数| p是数组指针变量名p指向的数组的元素类型 三、二维数组传参本质
有了数组指针我们就能详细了解二维数组传参本质了。
之前我们将一个二维数组传给一个函数的时候我们往往会这么写
void test(int a[3][5], int r, int c)
{int i 0;int j 0;for (i 0; i r; i){for (j 0; j c; j){printf(%d , a[i][j]);}printf(\n);}
}
int main()
{int arr[3][5] { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}
我们学完数组指针之后还有其它的写法嘛
我们再次理解一下二维数组其实它就可以看成一个一维数组只不过里面元素装的也是一维数组所以二维数组的每一行都是一个数组。 所以根据数组名是首元素地址这个规则二维数组的数组名也就代表着第一行的地址也就是一个一维数组的地址。根据上面的例子第一行的数组的类型也就是int [5]所以第一行的地址类型就是int (*)[5]。那就意味着二维数组传参的本质也是传递了地址传递的是第一行的一维数组的地址那么形参也可以写成指针形式
#include stdio.h
void test(int(*p)[5], int r, int c)
{int i 0;int j 0;for (i 0; i r; i){for (j 0; j c; j){printf(%d , *(*(p i) j));}printf(\n);}
}
int main()
{int arr[3][5] { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}
总结二维数组传参形参部分可以写成数组也可以写成指针。
四、函数指针变量
4.1 函数指针变量的创建
通过类比关系不难理解函数指针。它应该是存放指针地址的可以通过函数地址调用函数的。
那函数指针到底是不是这样的呢我们来做个测试
#include stdio.h
void test()
{printf(hehe\n);
}
int main()
{printf(test: %p\n, test);printf(test: %p\n, test);return 0;
}
运行结果如下 我们确实打印出来了地址所以函数确实是有地址的并且函数名就是地址所以可以用函数名的方式获得函数的地址。
我们如果想将函数的地址存放起来也非常简单这就用到了函数指针变量写法其实和数组指针的写法非常类似
void test()
{printf(hehe\n);
}
void (*pf1)() test;
void (*pf2)() test;
int Add(int x, int y)
{return x y;
}
int(*pf3)(int, int) Add;
int(*pf3)(int x, int y) Add;//x和y写上或者省略都是可以的
就是后面的改成参数了而已非常简单。
函数指针类型详解
int (*pf3) (int x, int y)| | ------------ | | || | pf3指向函数的参数类型和个数的交代| 函数指针变量名pf3指向函数的返回类型int (*) (int x, int y) //pf3函数指针变量的类型
4.2 函数指针的使用
通过函数指针调用指针指向的函数。
#include stdio.h
int Add(int x, int y)
{return x y;
}
int main()
{int(*pf3)(int, int) Add;printf(%d\n, (*pf3)(2, 3));printf(%d\n, pf3(3, 5));return 0;
}
运行结果 我们发现写(*pf3)(2,3)或者pf3(3,5)都可以。
4.3 两段有意思的代码
代码1 (*(void (*)())0)();
//首先void(*)() --这是指针变量
//( void(*)() )0 --强制类型转换
//这就意味着我们假设0地址这个位置放着无参返回类型为void的函数
代码2
void (*signal(int , void(*)(int)))(int);
//void(* signalintvoid(*)(int))(int);
//声明了一个函数signal(int,void(*)(int))
//它有两个参数一个是int一个是函数地址
//把signal的地址放进了void类型的函数指针参数为int
这两段代码均出自于《C陷阱与缺陷这本书》。
4.3.1 typedef关键字
我们好久没讲关键字了今天就新认识一个叫typedef。它是用来干什么的呢用来给类型重命名的可以将复杂的类型简单化。
举个栗子比如说你觉得unsigned int 写起来不方便你想给它改成uint代码如下
typedef unsigned int uint;
//将unsigned int 重命名为uint
如果是指针类型能否重命名呢当然可以比如将int*改成ptr_r
typedef int* ptr_t;
但是对于数组指针和函数指针稍微有点不同。
比如我们要将int(*arr)[5]改写成parr_t我们就需要这么改
typedef int(*parr_t)[5]; //新的类型名必须在*的右边
同理函数指针也是这样比如我们将void(*)(int)改成pf_t就要这么写 typedef void(*pfun_t)(int);//新的类型名必须在*的右边
练练手如果我们将刚刚的代码2进行简化我们可以这么写
typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);
五、函数指针数组
数组是一个存放相同类型数据的存储空间我们已经学习了指针数组。
比如
int *arr[10];
//数组的每个元素是int*
如果我们想把函数的地址都存储到一个数组中那这个数组就叫函数指针数组它是怎么定义的呢
int (*parr1[3])();
int *parr2[3]();
int (*)() parr3[3]; 答案是parr1 parr1先和[3]结合说明其是数组然后数组的内容是什么呢是int(*)( )类型的函数指针。 六、转移表
讲完了函数指针数组我们来说一个听起来比较牛逼的东西——转移表。 虽然听起来很牛逼但是它的本质就是我们刚刚学过的函数指针数组。
举个栗子假如我们现在要写一个计算器的小程序正常我们会这么写
#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;do{printf(*************************\n);printf( 1:add 2:sub \n);printf( 3:mul 4:div \n);printf( 0:exit \n);printf(*************************\n);printf(请选择);scanf(%d, input);switch (input){case 1:printf(输入操作数);scanf(%d %d, x, y);ret add(x, y);printf(ret %d\n, ret);break;case 2:printf(输入操作数);scanf(%d %d, x, y);ret sub(x, y);printf(ret %d\n, ret);break;case 3:printf(输入操作数);scanf(%d %d, x, y);ret mul(x, y);printf(ret %d\n, ret);break;case 4:printf(输入操作数);scanf(%d %d, x, y);ret div(x, y);printf(ret %d\n, ret);break;case 0:printf(退出程序\n);break;default:printf(选择错误\n);break;}} while (input);return 0;
}
很好想但是这么写稍微有点冗余了就是switch里有许多重复或者相似的代码片段。
而我们学完了函数指针数组我们就可以这么写我们把加减乘除的函数都装到数组里代码如下
#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 }; //转移表do{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(输入操作数);scanf(%d %d, x, y);ret (*p[input])(x, y);printf(ret %d\n, ret);}else if (input 0){printf(退出计算器\n);}else{printf(输⼊有误\n);}} while (input);return 0;
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/912044.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!