用软件做模板下载网站除了红动中国还有哪些设计网站
2026/5/21 12:18:29 网站建设 项目流程
用软件做模板下载网站,除了红动中国还有哪些设计网站,php的网站模板下载,扫码点餐微信小程序怎么样开通函数指针 如果未提到函数指针#xff0c;则对C 或C函数的讨论将是不完整的。我们将大致介绍一下这个主题#xff0c;将完 整的介绍留给更高级的图书。 与数据项相似#xff0c;函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。通常#xff0c;这些地 址对…函数指针如果未提到函数指针则对C 或C函数的讨论将是不完整的。我们将大致介绍一下这个主题将完整的介绍留给更高级的图书。与数据项相似函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。通常这些地址对用户而言既不重要也没有什么用处但对程序而言却很有用。例如可以编写将另一个函数的地址作为参数的函数。这样第一个函数将能够找到第二个函数并运行它。与直接调用另一个函数相比这种方法很笨拙但它允许在不同的时间传递不同函数的地址这意味着可以在不同的时间使用不同的函数。函数指针的基础知识首先通过一个例子来阐释这一过程。假设要设计一个名为estimate( )的函数估算编写指定行数的代码所需的时间并且希望不同的程序员都将使用该函数。对于所有的用户来说estimate( )中一部分代码都是相同的但该函数允许每个程序员提供自己的算法来估算时间。为实现这种目标采用的机制是将程序员要使用的算法函数的地址传递给estimate( )。为此必须能够完成下面的工作获取函数的地址声明一个函数指针使用函数指针来调用函数。获取函数的地址获取函数的地址很简单只要使用函数名后面不跟参数即可。也就是说如果think( )是一个函数则think 就是该函数的地址。要将函数作为参数进行传递必须传递函数名。一定要区分传递的是函数的地址还是函数的返回值process(think); thougtht(think);process( )调用使得process( )函数能够在其内部调用think( )函数。thought( )调用首先调用think( )函数然后将think( )的返回值传递给thought( )函数。声明函数指针声明指向某种数据类型的指针时必须指定指针指向的类型。同样声明指向函数的指针时也必须指定指针指向的函数类型。这意味着声明应指定函数的返回类型以及函数的特征标参数列表。也就是说声明应像函数原型那样指出有关函数的信息。例如假设Pam leCoder 编写了一个估算时间的函数其原型如下double pam(int);则正确的指针类型声明如下double (*pf)(int);这与pam( )声明类似这是将pam 替换为了*pf。由于pam 是函数因此*pf也是函数。而如果*pf是函数则pf 就是函数指针。提示通常要声明指向特定类型的函数的指针可以首先编写这种函数的原型然后用*pf替换函数名。这样pf 就是这类函数的指针。为提供正确的运算符优先级必须在声明中使用括号将pf 括起。括号的优先级比运算符高因此*pfint意味着pf( )是一个返回指针的函数而*pfint意味着pf 是一个指向函数的指针double (*pf)(int); double *pf(int);正确地声明pf 后便可以将相应函数的地址赋给它double pam(int); double (*pf)(int); pfpam;注意pam( )的特征标和返回类型必须与pf 相同。如果不相同编译器将拒绝这种赋值double ned(double); int ted(int); double *pt(int); pfned; pfted;现在回过头来看一下前面提到的estimate( )函数。假设要将将要编写的代码行数和估算算法如pam( )函数的地址传递给它则其原型将如下void estimate(int lines,double *pf)(int));上述声明指出第二个参数是一个函数指针它指向的函数接受一个int 参数并返回一个double 值。要让estimate( )使用pam( )函数需要将pam( )的地址传递给它estimate(50,pam);显然使用函数指针时比较棘手的是编写原型而传递地址则非常简单。使用指针来调用函数现在进入最后一步即使用指针来调用被指向的函数。线索来自指针声明。前面讲过*pf扮演的角色与函数名相同因此使用*pf时只需将它看作函数名即可double pam(int); double (*pf)(int); pfpam; double xpam(4); double y(*pf)(5);实际上C也允许像使用函数名那样使用pfdouble ypf(5);第一种格式虽然不太好看但它给出了强有力的提示—代码正在使用函数指针。函数指针示例程序清单7.18 演示了如何使用函数指针。它两次调用estimate( )函数一次传递betsy( )函数的地址另一次则传递pam( )函数的地址。在第一种情况下estimate( )使用betsy( )计算所需的小时数在第二种情况下estimate( )使用pam( )进行计算。这种设计有助于今后的程序开发。当Ralph 为估算时间而开发自己的算法时将不需要重新编写estimate( )。相反他只需提供自己的ralph( )函数并确保该函数的特征标和返回类型正确即可。当然重新编写estimate( )也并不是一件非常困难的工作但同样的原则也适用于更复杂的代码。另外函数指针方式使得Ralph 能够修改estimate( )的行为虽然他接触不到estimate( )的源代码。#include iostream double betsy(int); double pam(int); void estimate(int lines, double (*pf)(int)); int main() { using namespace std; int code; cout How many lines of code do you need?; cin code; cout Heres Betsys estimate:\n; estimate(code, betsy); cout Heres Pams estimate:\n; estimate(code, pam); return 0; } double betsy(int lns) { return 0.05 * lns; } double pam(int lns) { return 0.03 * lns 0.0004 * lns * lns; } void estimate(int lines, double(*pf)(int)) { using namespace std; cout lines lines will take; cout (*pf)(lines) hour(s)\n; }深入探讨函数指针函数指针的表示可能非常恐怖。下面通过一个示例演示使用函数指针时面临的一些挑战。首先下面是一些函数的原型它们的特征标和返回类型相同const double *f1(const double ar[],int n); const double *f2(const double[],int); const double *f3(const double *,int);这些函数的特征标看似不同但实际上相同。首先前面说过在函数原型中参数列表const doublear [ ]与const double * ar 的含义完全相同。其次在函数原型中可以省略标识符。因此const double ar [ ]可简化为const double [ ]而const double * ar 可简化为const double *。因此上述所有函数特征标的含义都相同。另一方面函数定义必须提供标识符因此需要使用const double ar [ ]或const double * ar。接下来假设要声明一个指针它可指向这三个函数之一。假定该指针名为pa则只需将目标函数原型中的函数名替换为(*pa)const double *(*p1)(const double * int);可在声明的同时进行初始化const double *(*p1)(const double *,int)f1;使用C11 的自动类型推断功能时代码要简单得多auto p2f2;现在来看下面的语句cout(*p1)(av,3):*(*p1)(av,3)endl; coutp2(av,3):*p2(av,3)endl;根据前面介绍的知识可知(p1) (av, 3)和p2(av, 3)都调用指向的函数这里为f1()和f2()并将av 和3 作为参数。因此显示的是这两个函数的返回值。返回值的类型为const double即double 值的地址因此在每条cout 语句中前半部分显示的都是一个double 值的地址。为查看存储在这些地址处的实际值需要将运算符应用于这些地址如表达式(p1)(av,3)和p2(av,3)所示。鉴于需要使用三个函数如果有一个函数指针数组将很方便。这样将可使用for 循环通过指针依次调用每个函数。如何声明这样的数组呢显然这种声明应类似于单个函数指针的声明但必须在某个地方加上[3]以指出这是一个包含三个函数指针的数组。问题是在什么地方加上[3]答案如下包含初始化const double *(*pa[3])(const double *,int){f1,f2,f3};为何将[3]放在这个地方呢pa 是一个包含三个元素的数组而要声明这样的数组首先需要使用pa[3]。该声明的其他部分指出了数组包含的元素是什么样的。运算符[]的优先级高于*因此*pa[3]表明pa 是一个包含三个指针的数组。上述声明的其他部分指出了每个指针指向的是什么特征标为const double *, int且返回类型为const double *的函数。因此pa 是一个包含三个指针的数组其中每个指针都指向这样的函数即将const double *和int 作为参数并返回一个const double *。这里能否使用auto 呢不能。自动类型推断只能用于单值初始化而不能用于初始化列表。但声明数组pa 后声明同样类型的数组就很简单了auto pbpa;本书前面说过数组名是指向第一个元素的指针因此pa 和pb 都是指向函数指针的指针。如何使用它们来调用函数呢pa[i]和pb[i]都表示数组中的指针因此可将任何一种函数调用表示法用于它们const double *pxpa[0](av,3); const double *py(*pb[1])(av,3);要获得指向的double 值可使用运算符*double x*pa[0](av,3); double y*(*pb[1])(av,3);可做的另一件事是创建指向整个数组的指针。由于数组名pa 是指向函数指针的指针因此指向数组的指针将是这样的指针即它指向指针的指针。这听起来令人恐怖但由于可使用单个值对其进行初始化因此可使用autoauto pcpa;如果您喜欢自己声明该如何办呢显然这种声明应类似于pa 的声明但由于增加了一层间接因此需要在某个地方添加一个*。具体地说如果这个指针名为pd则需要指出它是一个指针而不是数组。这意味着声明的核心部分应为(pd)[3]其中的括号让标识符pd 与先结合*pd[3] (*pd)[3]换句话说pd 是一个指针它指向一个包含三个元素的数组。这些元素是什么呢由pa 的声明的其他部分描述结果如下const double *((*pd)[3])(const double *,int)pa;要调用函数需认识到这样一点既然pd 指向数组那么*pd 就是数组而(pd)[i]是数组中的元素即函数指针。因此较简单的函数调用是(pd)i而(pd)i是返回的指针指向的值。也可以使用第二种使用指针调用函数的语法使用((pd)[i])(av,3)来调用函数而((*pd)[i])(av,3)是指向的double 值。请注意pa它是数组名表示地址和pa 之间的差别。正如您在本书前面看到的在大多数情况下pa 都是数组第一个元素的地址即pa[0]。因此它是单个指针的地址。但pa 是整个数组即三个指针块的地址。从数字上说pa 和pa 的值相同但它们的类型不同。一种差别是pa1 为数组中下一个元素的地址而pa1 为数组pa 后面一个12 字节内存块的地址这里假定地址为4 字节。另一个差别是要得到第一个元素的值只需对pa 解除一次引用但需要对pa 解除两次引用**pa*papa[10]程序清单7.19 使用了这里讨论的知识。出于演示的目的函数f1()等都非常简单。正如注释指出的这个程序演示了auto 的C98 替代品。// 深入探讨函数指针.cpp : 函数指针的深入应用示例 // #include iostream #include algorithm // 函数声明 int add(int a, int b) { return a b; } int subtract(int a, int b) { return a - b; } int multiply(int a, int b) { return a * b; } int divide(int a, int b) { return b ! 0 ? a / b : 0; } // 使用函数指针作为参数 void calculate(int a, int b, int (*operation)(int, int)) { std::cout 结果: operation(a, b) std::endl; } // 函数指针数组 int main() { // 1. 基本函数指针 int (*funcPtr)(int, int) add; std::cout 10 5 funcPtr(10, 5) std::endl; // 2. 函数指针数组 int (*operations[])(int, int) {add, subtract, multiply, divide}; const char* opNames[] {加法, 减法, 乘法, 除法}; for (int i 0; i 4; i) { std::cout opNames[i] (15, 3): ; calculate(15, 3, operations[i]); } // 3. 函数指针作为参数 std::cout \n使用函数指针作为参数: std::endl; calculate(20, 8, add); calculate(20, 8, subtract); // 4. typedef函数指针 typedef int (*MathFunc)(int, int); MathFunc func multiply; std::cout 使用typedef: 7 * 6 func(7, 6) std::endl; // 5. 使用using定义函数指针类型C11 using MathOp int(*)(int, int); MathOp op divide; std::cout 使用using: 100 / 5 op(100, 5) std::endl; return 0; }使用typedef 进行简化除auto 外C还提供了其他简化声明的工具。您可能还记得第5 章说过关键字typedef 让您能够创建类型别名typedef double real;这里采用的方法是将别名当做标识符进行声明并在开头使用关键字typedef。因此可将p_fun 声明为程序清单7.19 使用的函数指针类型的别名typedef const double *(*p_fun)(const double *int); p_fun p1f1;然后使用这个别名来简化代码p_fun pa[3]{f1,f2,f3}; p_fun (*pd)[3]pa;使用typedef 可减少输入量让您编写代码时不容易犯错并让程序更容易理解。总结函数是C的编程模块。要使用函数必须提供定义和原型并调用该函数。函数定义是实现函数功能的代码函数原型描述了函数的接口传递给函数的值的数目和种类以及函数的返回类型。函数调用使得程序将参数传递给函数并执行函数的代码。在默认情况下C函数按值传递参数。这意味着函数定义中的形参是新的变量它们被初始化为函数调用所提供的值。因此C函数通过使用拷贝保护了原始数据的完整性。C将数组名参数视为数组第一个元素的地址。从技术上讲这仍然是按值传递的因为指针是原始地址的拷贝但函数将使用指针来访问原始数组的内容。当且仅当声明函数的形参时下面两个声明才是等价的typeName arr[]; typeName *arr;这两个声明都表明arr 是指向typeName 的指针但在编写函数代码时可以像使用数组名那样使用arr 来访问元素arr[i]。即使在传递指针时也可以将形参声明为const 指针来保护原始数据的完整性。由于传递数据的地址时并不会传输有关数组长度的信息因此通常将数组长度作为独立的参数来传递。另外也可传递两个指针其中一个指向数组开头另一个指向数组末尾的下一个元素以指定一个范围就像STL 使用的算法一样。C提供了3 种表示C-风格字符串的方法字符数组、字符串常量和字符串指针。它们的类型都是char*char 指针因此被作为char*类型参数传递给函数。C使用空值字符\0来结束字符串因此字符串函数检测空值字符来确定字符串的结尾。C还提供了string 类用于表示字符串。函数可以接受string 对象作为参数以及将string 对象作为返回值。string 类的方法size( )可用于判断其存储的字符串的长度。C处理结构的方式与基本类型完全相同这意味着可以按值传递结构并将其用作函数返回类型。然而如果结构非常大则传递结构指针的效率将更高同时函数能够使用原始数据。这些考虑因素也适用于类对象。C函数可以是递归的也就是说函数代码中可以包括对函数本身的调用。C函数名与函数地址的作用相同。通过将函数指针作为参数可以传递要调用的函数的名称。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询