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

做网站的开发软件郑州网站推广报价

做网站的开发软件,郑州网站推广报价,解析域名就可以做网站,网站域名后缀区别C语言指针详解(三)目录版 1、字符指针变量1.1、字符指针变量的一般应用1.2、常量字符串1.3、常量字符串与普通字符串的区别1.3.1 常量字符串的不可修改性1.3.2 常量字符串的存储 2、数组指针变量2.1、数组指针变量定义2.2、数组指针变量的初始化 3、二维…

C语言指针详解(三)目录版

    • 1、字符指针变量
      • 1.1、字符指针变量的一般应用
      • 1.2、常量字符串
      • 1.3、常量字符串与普通字符串的区别
        • 1.3.1 常量字符串的不可修改性
        • 1.3.2 常量字符串的存储
    • 2、数组指针变量
      • 2.1、数组指针变量定义
      • 2.2、数组指针变量的初始化
    • 3、二维数组传参本质
    • 4、函数指针变量
      • 4.1、函数指针变量的创建
        • 4.1.1、验证函数地址的存在
        • 4.1.2、函数指针变量表达式
      • 4.2、函数指针变量的使用
      • 4.3、深入理解函数指针
        • 4.3.1、例题一
        • 4.3.2、例题二
        • 4.3.3、例题一解析
        • 4.3.4、例题二解析
        • 4.4、关键字 typedef 介绍
        • 4.4.1、typedef 表达式与实例演示
        • 4.4.2、define 与 typedef 的区别
    • 5、函数指针数组
    • 6、转移表

1、字符指针变量

我们知道若指针所指向的内容是字符,那么指针的类型就是字符指针类型 char* ,这个指针变量就是字符指针变量。

1.1、字符指针变量的一般应用

int main()
{char ch = 'a';char* pc = &ch;*pc = 'w';printf("%c", ch);return 0;
}

在这里插入图片描述

1.2、常量字符串

#include<stdio.h>
int main()
{const char* pt = "hello world.";//请思考这里是把一个字符串放到了 pt 指针当中了吗?printf("%s\n", pt);return 0;
}

如上面代码所示的 char* name = “字符串” 就是常量字符串的表达方式。那么我们思考一下注释中的问题:这里是把一个字符串放到了 pt 指针当中了吗?
答案是:否。毕竟前面是一个指针变量,其存储的应当为地址,故放入的是首字符的地址。因为字符是连续存放的,输出时系统会自动向后遍历,直至遇到 “/0”。
运行效果图:
在这里插入图片描述

1.3、常量字符串与普通字符串的区别

1.3.1 常量字符串的不可修改性

1.1 的代码和运行图中我们可见一般情况下的字符(字符串)是可以通过指针解引用来进行修改的。而常量字符串则不可修改,如下面代码示例演示

int main()
{char* pt = "hello world.";printf("%s\n", pt);*pt = "Hello World";return 0;
}

在这里插入图片描述
原因请见下文 1.3.2

1.3.2 常量字符串的存储

我们知道在存储位置中有栈区,堆区,静态区。其实在此之外还有一部分称为代码段。一般字符(字符串)存储在栈区中,而常量字符串则存储在代码段中。所以即使通过指针解引用也不能更改字符串内容。正因如此,当多个指针变量指向的常量字符串内容一致时,系统不会存储多份相同的常量字符串,而是会只存储一份,各个变量共用这一份常量字符串(即字符串地址相同)。为使各位对此更加清晰,我们通过以下代码和图解来进行进一步解析。

int main()
{char str1[] = "You are handsome !";char str2[] = "YOu are handsome !";char* str3 = "You are so beautiful";char* str4 = "You are so beautiful";if ( str1 == str2)//数组名表示数组首元素地址{printf("str1 and str2 are same\n");}else{printf("str1 and str2 are not same\n");}if (str3 == str4)//验证相同内容的常量字符串是否只有一份,即验证地址是否相同{printf("str3 and str4 are same\n");}else{printf("str3 and str4 are not same\n");}return 0;
}

在这里插入图片描述
在这里插入图片描述

2、数组指针变量

2.1、数组指针变量定义

数组指针,顾名思义它是一种指针。我们已经熟知:
整型指针变量:int * p;存放的是整型变量的地址,指向整型数据的指针。
浮点型指针变量:float * p;存放的是浮点型变量的地址,指向浮点型数据的指针。
由上推知:数组指针变量应当存放的是数组的地址,指向数组的指针。
数组指针变量表达式:int (*p) [20];
在这个表达式中,p会先和*结合,表明 p 是一个指针变量,然后指针指向的是一个大小为20个整型变量的数组。
注意:因为 [ ] 的优先级要高于 * 号,所以必须加上 ()来保证 p 先和 * 结合

2.2、数组指针变量的初始化

既然数组指针变量存放的是数组的地址,那么我们就要将数组的地址给指针变量。数组地址:&数组名

int arr[10] = {0};//定义数组并初始化
int (*p) [10] = &arr;//将数组的地址赋值给指针变量 

在这里插入图片描述

3、二维数组传参本质

在数组章节中曾提及二维数组传参的如下写法:

#include <stdio.h>void print_arr(int arr[4][5], int a, int b)
{int i = 0;for (i = 0; i < a; i++){int j = 0;for (j = 0; j < b; j++){printf("%d", arr[i][j]);}printf("\n");}
}int main()
{int arr[4][5] = { {1,2,3,4,5},{2.3,4,5,6},{3,4,5,6,7},{4,5,6,7,8}};print_arr(arr, 4, 5);return 0;
}

在上述代码中,实参为二维数组,形参也为二维数组。那么下面来介绍另一种传参方式,使用数组指针进行传参。
二维数组在之前数组章节曾讲过,其可以看成每个元素是一维数组的数组,即二维数组的每个元素是一个一维数组,二维数组首元素就是第一行,是一个一维数组。
在这里插入图片描述
二维数组的数组名就是第一行的地址,是一个一维数组的地址,第一行一维数组类型为int [5],故其地址类型为int (*) [5];。如此也就证明二维数组传参实际上是传递了第一行一维数组的地址。由此可知,函数形参部分也可以写成指针形式。如下所示:

#include <stdio.h>void print_arr(int (*p) [5], int a, int b)//数组形参设置为数组指针
{int i = 0;for (i = 0; i < a; i++){int j = 0;for (j = 0; j < b; j++){printf("%d", *( * ( p + i ) + j ) );//深入理解系统对数组arr[ i ]的编译。// arr[ i ] = *(arr + i)}printf("\n");}
}int main()
{int arr[4][5] = { {1,2,3,4,5},{2.3,4,5,6},{3,4,5,6,7},{4,5,6,7,8} };print_arr(arr, 4, 5);return 0;
}

4、函数指针变量

4.1、函数指针变量的创建

根据上文内容,我们可以推断出函数指针变量是存储函数地址的变量,同时我们可以通过函数的地址来调用函数。

4.1.1、验证函数地址的存在

下面我们来验证函数地址的存在:

#include<stdio.h>void test()
{printf("hehe\n");
}int main()
{printf("test = %p\n", test);//函数名printf("&test = %p\n", &test);//取函数地址return 0;
}

在这里插入图片描述
由此说明函数存在地址,函数名与 &函数名 都可以得到函数的地址。

4.1.2、函数指针变量表达式

表达式如下:

int*pf)(int x , int y);
//或 int (*pf)(int , int)

在这里插入图片描述
去掉变量名即为其变量类型:

int*)(int x , int

4.2、函数指针变量的使用

在使用函数指针变量调用函数时,(*pf)()与 pf()两种方法都是可行的,因为二者表示的意思都一致,都是对应函数的地址。
代码演示:

#include<stdio.h>int div(int a , int b)
{return a / b;
}int main()
{int (*pf) (int, int) = div;printf("%d\n", (*pf)(4 , 2) );//调用方式一printf("%d\n", pf(4, 2));//调用方式二return 0;
}

在这里插入图片描述

4.3、深入理解函数指针

4.3.1、例题一
(*( void (*)() ) 0)();//请思考此行代码的意义

请思考上面代码的意义,解析见 4.3.3

4.3.2、例题二
void (*signal(int, void(*)(int)))(int);//请思考此行代码的意义

请思考上面代码得意义,解析见 4.3.4

4.3.3、例题一解析

在这里插入图片描述
入手关键点在 0 处,其前方应当为0的类型,( void (*) () ) 0 典型的强制类型转换,将0从整型 int 强制转换为函数指针类型 void ( * ) () ,从而 0 就成为一个函数指针变量,整体就是通过函数指针调用函数。

4.3.4、例题二解析

在这里插入图片描述
入手关键点在中间的函数名及其参数部分 signal(int, void(*)(int)) 我们可见在这一小部分中已经包含了signal函数的函数名和该函数内的两个参数的类型,但无参数名,根据C语言标准可知这应当是一个函数声明。故剩余部分为函数的返回类型,为 void (*) (int)函数指针类型。因为解引用操作符 * 后要跟名称,所以signal(int, void(*)(int))放在了 * 之后。综上,整体为一个函数声明

4.4、关键字 typedef 介绍
4.4.1、typedef 表达式与实例演示

typedef是用来类型的重命名的,可以简化复杂的类型,如 4.3.4 例题二中的函数指针类型。其重定义表达式如下:

typedef name1 name2;

name1 表示需要重定义类型名
name2 表示 name1 重定义后的类型名

具体演示如下:

#include<stdio.h>int div(int a , int b)
{return a / b;
}int main()
{typedef int(*son)(int, int);// * 后要跟名称,所以新的类型名要放在 * 后son pf = div;printf("%d\n", (*pf)(18 , 2) );printf("%d\n", pf(10, 2));return 0;
}

在这里插入图片描述

4.4.2、define 与 typedef 的区别

1、 本质区别:
#define 是预处理指令,用于文本替换。在编译之前,预处理器会直接将 #define 定义的宏替换成指定的文本。
typedef 是类型定义命令,用于为已存在的数据类型创建一个新的名字。
2.、作用范围:
#define 定义的宏没有作用域限制,一旦定义,就会一直有效,除非被 #undef 取消定义。
typedef 定义的类型有作用域限制,它遵循C语言的变量作用域规则。
3、 类型检查:
#define 不进行类型检查。它仅仅是在预处理阶段进行文本替换,所以不会检查替换后的类型是否正确。
typedef 会进行类型检查。当你使用 typedef 定义的新类型时,编译器会检查类型是否匹配。
4、 使用方式:
#define 可以用于定义常量、宏函数等,不仅仅限于类型。
typedef 仅用于定义类型的别名。
5、 内存分配:
#define 不会分配内存,因为它只是在预处理阶段进行文本替换。
typedef 本身也不分配内存,但它定义的类型在创建变量时会分配内存。

5、函数指针数组

我们知道数组是一个存储相同类型数据的存储空间。故函数指针数组就是一块连续的存储函数指针的空间。
表达式如下:

type (* name[number]();

name 会先和 [ ] 结合,表明 name 是数组,数组的内容是 type (*) () 类型的函数指针。(因为 * 后面要跟名称,所以 * 后面跟上数组名)

6、转移表

转移表是函数指针数组实例化的体现。
下面以简易计算器的改造为例:

//改造前的计算器
#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;
}

上述代码的条件分支中我们可以看到有许多重复的部分
在这里插入图片描述
这样就出现两个问题:

1、将这样重复的代码实现成函数。 2、这个函数又能完成不同的任务

如此我们有两种思路:

1、设计回调函数

2、引入函数指针数组来设计转移表。

在此我们以思路二进行改造(思路一请见《C语言指针详解(四)》)。首先我们要思考,设计转移表的话函数指针数组中的元素应当如何设置。我们一共自定义了 4 个函数,所以我们就把这四个函数的地址放入数组。具体演示如下:

#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 (*parr[5])(int , int) = { 0 , add , sub , mul , div };//转移表//之所以首元素为 0  是为了便于选择,使1-4都对应具体函数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 = (parr[input])(x, y);printf("ret = %d\n", ret);}else if (input == 0){printf("退出计算器\n");}else{printf("输入错误");}} while (input);return 0;
}

全文至此结束!!!
写作不易,不知各位老板能否给个一键三连或是一个免费的赞呢()(),这将是对我最大的肯定与支持!!!谢谢!!!()()

http://www.rdtb.cn/news/18963.html

相关文章:

  • 网站关键字及说明优化疫情防控 这些措施你应该知道
  • 做网站的 需要续费维护费吗武威网站seo
  • 婚恋交友网站建设方案关键词智能优化排名
  • 网站做的题不小心关闭了新闻发稿平台
  • 记事本怎样做网站百度小说app
  • php动态网站怎么做泰安做网站公司
  • 山东德州网站建设哪家最好网络营销推广方式都有哪些
  • 兄弟网站制作快速优化seo软件
  • 收费的网站如何免费网络推广外包流程
  • 河源公司做网站营销推广是什么
  • 礼品网站如何做搜索引擎优化服务公司哪家好
  • 上海建设网站的公司网站建设网站
  • html静态网站怎么放在网站上推广网站的方法有哪些
  • 昆明做网站vrseo的培训班
  • 人社局劳务网站建设汇报厦门关键词优化网站
  • win 2012 iis 默认网站泉州关键词优化排名
  • 房产获客软件百度网站推广排名优化
  • 一个女的让我和她做优惠网站杭州seo排名
  • 网站建设 推广什么意思如何快速推广app
  • 石油化工建设网站百度优化是什么
  • 国外做鞋子的网站吗营销活动推广策划
  • dw 做网站模板微信软文范例大全100
  • 网站建设 自动生成seo诊断报告怎么写
  • 湛江网站建设技术托管产品推销方案
  • 网站说服力营销型网站策划苏州seo安严博客
  • 网站图片设置方法企业seo如何优化
  • 山东今日热搜长春网站优化流程
  • 上海做网站公司推荐公司网站首页设计
  • 企业网站建设深圳西安今日头条新闻消息
  • 建站神器免费的客户资源怎么找