当前位置: 首页 > news >正文

惠州网站搭建找谁wordpress注册跳过邮箱验证码

惠州网站搭建找谁,wordpress注册跳过邮箱验证码,wordpress 不同面包屑,磁力棒C语言#xff1a;数组指针 函数指针 数组指针数组名 数组访问二维数组 函数指针函数指针使用回调函数 typedef关键字 数组指针 数组本质上也是一个变量#xff0c;那么数组也有自己的地址#xff0c;指向整个数组的指针#xff0c;就叫做数组指针。 我先为大家展示… C语言数组指针 函数指针 数组指针数组名 数组访问二维数组 函数指针函数指针使用回调函数 typedef关键字 数组指针 数组本质上也是一个变量那么数组也有自己的地址指向整个数组的指针就叫做数组指针。 我先为大家展示一个数组指针再做数组指针的语法解析。 数组int arr[10]的指针 int (*p)[10](*p) 代表p是一个指针[10] 代表这个指针指向的数组有10个元素int 代表这个指针指向的数组元素类型为int 不能写成 int *p[10] [] 的优先级高于 *所以p会先和 [] 结合此时p就是一个数组变量了而指向的元素类型为 int*。所以需要一个 () 来改变操作符的结合顺序让 p 和 * 先结合代表p是一个指针。 数组指针的类型就是去掉指针名剩下的部分比如 int (*p1)[10] arr1; //p1的类型为int (*)[10]char (*p2)[3] arr2; //p2的类型为char (*)[3]数组名 学习指针后其实我们的数组名就已经不单纯是一个数组名了我们先来观察现象 int arr[10] { 1,2,3,4,5,6,7,8,9,10 }; printf(arr[0] %p\n, arr[0]); printf(arr %p\n, arr); printf(arr %p\n, arr);输出结果 arr[0] 009BFEB0 arr 009BFEB0 arr 009BFEB0可以看到数组名本质上是地址数组名 也是地址而且arr arr arr[0]也就是说它们都是首元素的地址。 数组名的本质是首元素的地址 那么 数组名 与 数组名 有什么区别吗 我们再看一段代码 int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf(arr[0] %p\n, arr[0]); printf(arr[0]1 %p\n, arr[0]1);printf(arr %p\n, arr); printf(arr1 %p\n, arr1);printf(arr %p\n, arr); printf(arr1 %p\n, arr1);输出结果 arr[0] 0077F820 arr[0]1 0077F824 arr 0077F820 arr1 0077F824 arr 0077F820 arr1 0077F848这⾥我们发现arr[0]和arr[0]1相差4个字节arr和arr1相差4个字节是因为arr[0]和arr都是⾸元素的地址1就是跳过⼀个元素。 但是arr和arr1相差40个字节这是因为arr是数组的地址1操作是跳过整个数组的。 也就是说 arr 本质是数组首元素的指针 arr 本质是整个数组指针 但是有关数组名也有特例 sizeof(arr)sizeof内单独放数组名此时数组名表示整个数组得到整个数组的大小 数组访问 现有如下数组 int arr[10] { 1,2,3,4,5,6,7,8,9,10 };现在我们以一般的方式来遍历这个数组 for (int i 0; i 10; i) {printf(%d , arr[i]); }由于数组的内存是连续存储的我们也可以通过指针的方式来遍历这个数组 int* p arr;for (int i 0; i 10; i) {printf(%d , *(p i)); }我们刚刚辨析过arr本质就是首个元素的地址所以int* p arr;就是把第一个元素的地址交给指针p。在循环内部我们通过指针偏移量i与首元素的指针p来定位元素再解引用访问*(p i)。这样就可以完成数组的遍历。 有没有发现arr[i]与*(p i)非常像它们之间有没有什么联系 arr的本质是首元素的指针而p也是arr那么我们可不可以用p代替arr进行下标访问 比如这样 int* p arr;for (int i 0; i 10; i) {printf(%d , p[i]); }答案是可以的这就要讲一讲下标访问的本质了。 arr数组本质上是首元素的地址通过第一个地址与偏移量我们就可以访问到所有数组元素。而数组下标的本质就是指针偏移量。 而数组的下标访问本质上也是指针的访问 arr[i] *(arr i)这条规则并不局限于数组名任何指针都可以使用p[i]来替代*(p i)的效果。 此外由于加法支持交换律所以 *(arr i)与*(i arr)是等效的故有以下代码 arr[i] *(arr i) *(i arr) i[arr]因为i[arr]最后会被解析为*(i arr)所以这个写法也是可以的。 二维数组 了解数组指针后我们就可以深入理解二维数组的底层实现了。 其实二维数组的本质是存储一维数组的数组二维数组的每一个元素都是一维数组。 接下来我们模拟实现一个二维数组 int arr1[5] { 1,2,3,4,5 }; int arr2[5] { 2,3,4,5,6 }; int arr3[5] { 3,4,5,6,7 };int* parr[3] { arr1,arr2,arr3 };我们一开始创建了三个一维数组arr1arr2arr3然后创建了一个parr把前三个一维数组放进去了此时我们就模拟实现了一个二维数组。即将三个一维数组放进了另外一个数组中接下来我们用访问二维数组的方式parr[i][j]来进行访问 for (int i 0; i 3; i) {for (int j 0; j 5; j){printf(%d , parr[i][j]);}printf(\n); }输出结果 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7可以看到我们确实可以用二维数组的方式去访问这个数组。 那么为什么可以这样操作呢 重点在以下过程 int* parr[3] { arr1,arr2,arr3 };我们真的把三个数组放在了这个parr数组里面吗 我们先前讲过数组名的本质是首元素的地址也就是说这里的arr1arr2arr3只是三个地址而已我们只是把三个地址存进了parr里面。 如图 接下来我们解析一下parr[i][j]是如何定位到指定位置的。 对第一个索引值i 通过前面的学习我们知道parr的本质是外层数组的第一个元素那么parr[i]就是*(parr i)此时就得到了下标为i的元素。而parr里存储的是数组指针比如parr[0]得到第一个数组的指针也就是arr1parr[1]得到第一个数组的指针也就是arr2。 所以我们可以通过第一个索引值i来定位数组。 对第二个索引值j 既然parr[i]得到的是内部一维数组的指针那parr[0][j]其实就是arr1[j]parr[1][j]其实就是arr2[j]。这样事情就简单了我们通过第一个索引值拿到了小数组的指针接着再用一个索引值j来定位这个一维数组中的具体哪一个元素就可以得到目标元素了。 以上只是一个模拟的二维数组但是真实的二维数组还要复杂一些接下来我们看看真实的二维数组是如何运作的 看到以下代码 int arr[3][5] { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };for (int i 0; i 3; i) {for (int j 0; j 5; j){printf(%p\n, arr[i][j]);}printf(\n); }输出结果 007AFAB8 007AFABC 007AFAC0 007AFAC4 007AFAC8007AFACC 007AFAD0 007AFAD4 007AFAD8 007AFADC007AFAE0 007AFAE4 007AFAE8 007AFAEC 007AFAF0可以看到这个二维数组的地址是完全连续的不存在每一行之间存在间隔两行之间也是紧密挨着的。 这是你想象的二维数组 但是其在内存中是这样的 那么其是如何运作的呢 对于arrr[3][5]这个数组其内部存储了三个数组而不是三个数组的指针每个数组中存储了五个元素。 在刚刚的模拟实现中我们是用外层parr数组存储了3个指针这里存的就是真真正正的数组。这就是两者的区别。 那么我们这里的arr是什么类型 arr是外层数组的数组名数组名代表了第一个元素的指针这里arr的第一个元素是一个数组 这三个数组的类型是int (*)[5]所以二维数组的数组名arr的指针类型就是int (*)[5]。 接下来我们再对arr[i][j]这样的下标访问进行分析 对第一个索引值i arr作为数组名本身是一个指针此指针的类型为int*[5]类型决定步长于是步长为int [5]类型数组的大小20字节。在面对一个步长为20字节的指针i的偏移量也就变成了20字节。 对第二个索引值j arr内存储的是步长为4字节的数组指针解引用后*arri这个整体就变成了一维数组的指针其类型为int *类型决定步长于是步长为4字节在面对一个步长为4字节的指针j的偏移量就变成了4字节。 所以可以看到此时的i和j是通过指针类型不同进而影响指针的偏移量大小对于i每个单位跳过二十字节也就是一个数组的大小对于j每个单位跳过四字节也就是一个元素的大小。先用i来确定元素在第几个数组再用j来确定元素在这个数组的第几位从而确定元素的位置。 函数指针 么是函数指针变量呢 根据前⾯学习整型指针数组指针的时候我们的类⽐关系我们不难得出结论 函数指针变量应该是⽤来存放函数地址的未来通过地址能够调⽤函数的。 那么函数是否有地址呢 做一个测试 void test() {printf(hehe\n); } int main() {printf(test: %p\n, test);printf(test: %p\n, test);return 0; }输出结果 test: 005913CA test: 005913CA确实打印出来了地址所以函数是有地址的函数名就是函数的地址当然也可以通过 函数名 的⽅式获得函数的地址。 如果我们要将函数的地址存放起来就得创建函数指针变量咯函数指针变量的写法其实和数组指针⾮常类似。 我先为大家展示一个函数指针再做指针的语法解析。 函数void Add(int x, int y)的指针 void (*p) (int, int)(*p) 代表p是一个指针(int , int y) 代表这个指针指向的函数有两个int类型的参数void 代表这个指针指向的函数返回值为void 函数指针有以下注意点 函数的参数名可有可无 void (*p) (int, int); void (*p) (int x, int y);两者效果是一致的 函数名 与 函数名 没有区别 在数组中arr与arr是有区别的但是函数中两者效果一致。 函数指针使用 想要使用函数的指针那就是先解引用指针再调用函数。 void (*p) (int, int) Add;(*p)(2, 3);//完成2 3 的加法void (*p) (int, int) Add;首先定义了一个指向Add函数的指针p。 我们获得指针后要先解引用(*p)然后调用函数(*p)()再传入参数(*p)(2, 3)。 这样我们就完成了函数的调用。 但是Add函数名本质上也是一个函数指针为什么Add(2, 3)可以直接调用函数而不用解引用呢 ANSIC标准规定函数指针中p()是(*p)()的简写。 也就是说在调用函数时可以减少解引用这个步骤。 因此以上代码也可以写成 void (*p) (int, int) Add;p(2, 3);//完成2 3 的加法另外的对于函数指针解引用*是没有意义的所以我们有以下通过指针调用函数的方法 p(2, 3);//省略* (*p)(2, 3);//不省略* (**p)(2, 3);//有多余的* (***p)(2, 3);//有多余的* //...... (**********p)(2, 3);//有多余的*你不论解引用多少次最后都可以正常调用函数。 回调函数 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针地址作为参数传递给另⼀个函数当这个指针被⽤来调⽤其所指向的函数时被调⽤的函数就是回调函数。 下面是一个简单的例子来说明回调函数的使用 // 回调函数的定义 void callback(int num) {printf(回调函数被调用传递的参数为: %d\n, num); }// 接受回调函数作为参数的函数 void performCallback(void (*func)(int)){printf(执行回调函数之前的操作\n);func(10); }int main(){// 主函数中调用接受回调函数的函数performCallback(callback);return 0; }在上面的例子中我们定义了一个名为callback的回调函数它接受一个整数作为参数并在函数体内输出这个参数的值。然后我们定义了一个名为performCallback的函数它接受一个函数指针作为参数。在performCallback函数中我们先输出一些操作然后调用传递进来的函数指针并传递一个整数参数10最后再输出一些操作。在主函数中我们调用performCallback函数并将callback函数作为参数传递进去。 运行这个程序输出如下 执行回调函数之前的操作 回调函数被调用传递的参数为: 10可以看到performCallback函数在执行之前和之后都执行了一些操作并在中间调用了传递进来的回调函数callback并将参数10传递给它。 typedef关键字 typedef关键字用于对变量重命名。 用法如下 typedef unsigned int uint;将unsigned int 重命名为 uint后续可以使用uint代替 unsigned int比如这样 uint x 5;此时的x变量就是unsigned int类型了。 那为什么我要在指针这里讲typedef关键字呢 因为对于指针其有不太一样的语法。 对于一般的指针直接重命名即可 将 int* 的指针重命名为 pint typedef int* pint;普通指针的语法命名与一般的类型没有区别。 对于数组指针 对于数组指针 如果根据一般的语法重命名是 typedef int (*) [5] parr;将 int (*) [5] 这个数组指针重命名为 parr 但是数组指针不允许这样命名必须把新的名称放在*的旁边 typedef int (*parr) [5];这样才算把 int (*) [5] 这个数组指针重命名为 parr。 对于函数指针 和数组指针同理不允许按照一般的语法重命名要把名称放在*旁边 将void (*) (int)类型的指针重命名为pfunc 错误案例 typedef void (*) (int) pfunc;正确示范 typedef void (*pfunc) (int);
http://www.hkea.cn/news/14486715/

相关文章:

  • 可直接进入网站的代码网站导航优化的描述
  • html怎么学百度seo 站长工具
  • 番禺制作网站报价东莞做网站排名优化推广
  • 哪个网站可以做h5页面制作网页app
  • 自助建站代理海外网站的建设
  • 建个公司网站要多少钱网站制作销售术语
  • 商城网站合作协议Wordpress调用百度云
  • 深圳网站定制价格低网站建设哪家公司比较好
  • 太原网站制作哪里便宜联邦快递网站建设的目标
  • 做网站一般都选哪家商城网站开发方案
  • 编程 网站建设如何开公司做网站
  • 怎么用手机做抖音上最火的表白网站包括
  • 个人网站模板h5wordpress 数据库表可视化
  • 推荐做幻灯片搜图网站万网个人网站备案查询
  • 建设食品网站如何定位不会百度吗网页生成
  • 网站建设行规深圳制作网页设计
  • 4s店建设网站的目的医疗门户网站模板
  • 苏州网站建设熊掌号内江做网站哪里便宜
  • 青海小学网站建设如何查看网站图片尺寸
  • 微网站免费注册wordpress搜索优化
  • 做网站公司商丘seo北京公司
  • 网站说明页内容维护jsp是前端还是后端开发的
  • wordpress设计网站广州 网站开发
  • 阿里万网怎么做网站建设彩票网站制作
  • 套别人代码做网站品牌设计作品
  • 建网站软件最新网站备案单位查询系统
  • flash做的网站微信小程序怎么注册申请
  • 个人网站系统上海哪家公司做网站
  • 制作医院网站高端品牌网站建设服务
  • 中文网站站内优化怎么做如何网上申请个人营业执照