高端企业网站源码中国最好的旅游网站

张小明 2026/3/2 19:58:00
高端企业网站源码,中国最好的旅游网站,短网址在线生成免费,wordpress 播放器右键指针和自由存储空间 在第3章的开头#xff0c;提到了计算机程序在存储数据时必须跟踪的3种基木属性。为了方便#xff0c;这里再次列 了这些属性#xff1a; 信息存储在何处#xff1b;存储的值为多少#xff1b;存储的信息是什么类型。 您使用过一种策略来达到上述目的…指针和自由存储空间在第3章的开头提到了计算机程序在存储数据时必须跟踪的3种基木属性。为了方便这里再次列了这些属性信息存储在何处存储的值为多少存储的信息是什么类型。您使用过一种策略来达到上述目的定义一个简单变量。声语句指出了值的类型和符号名还让程序为值分配内存并在内部跟踪该内存单元。下面来看一看另一种策略它在开发C类时非常重要。这种策略以指针为基础指针是一个变量其存储的是值的地址一面不是值本身。在讨论指针之的我们先看一看如何找到常规变量的地址。只需对变量应用地址运算符(),就可以获得它的位置例如如果home是一个变量则home是它的地址。程序清单4.14演示了这个运算符的用法。// 指针和自由存储空间.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。 // #include iostream int main() { using namespace std; int donuts 6; double cups 4.5; cout donuts value donuts; cout and donuts address donuts endl; cout cups value cups; cout and cups address cups endl; return 0; }运行结果donuts value 6and donuts address 000000019E92F6A4 cups value 4.5and cups address 000000019E92F6C8显示地址时该实现的cout使用十六进制表示法因为这是常用于描述内存的表示法有些实现可能使用十进制表示法。在该实现中donuts的存储位置比cups要低。两个地址的差为0x0065fd44一0x0065fd6540即4)。这是有意义的因为donuts的类型为int而这种类型使用4个字节。当然不同系统给定的地址值可能不同。有些系统可能先存储cups再存储donuts这样两个地址值的差将为8个字节因为cups的类型为double。另外在有些系统中可能不会将这两个变量存储在相邻的内存单元中。使用常规变量时值是指定的量面地址为派生量。下面来看看指针策略它是C内存管理编程理念的核心参见旁注“指针与C基本原理”。指针与C基本原理面向对象编程与传统的过程性煸程的区在于强调的是在运行阶段而不是编译阶段一进行决策。运行阶段指的是程序正在运行时编译阶段指的是编译器将程序组合起来时。运行阶段决策就好比度假时选择参观哪些景点取决于天气和当时的心情而编译阶段决策更像不管在什么条件下都坚持预先设定的日程安排。运行阶段决策提供了灵活性可以根据当时的情况进行调整。例如考虑为数组分配内存的情况。传统的方法是声明一个数组。要在C中声明数组必须指定数组的长度。因此数组长度在程序编译时就设定好了这就是编译阶段决策。您可能认为在80的情况下一个包含20个元素的数组足够了但程序有时需要处理200个元素。为了安全起见使用了一个包含2个元素的数组。这样程序在大多数情况下都浪费了内存。OOP通过将这样的决策推迟到运行阶段进行使程序更灵活。在程序运行后可以这次告诉它只需要20个元素而还可以下次告诉它需要205个元素。总之使用OOP时您可能在运行阶段确定数组的长度。为使用这种方法言必须允许在程序运行时创建数组。稍后您看会到C采用的方法是使用关键字new请求正确数量的内存以及使用指针来跟踪新分配的存的位置。在运行阶段做决并非OOP独有的但使用C编写这样的代码比使用C语言简单。处理存储数据的新略刚好相反将地址视为指定的量而将值视为派生量一种特殊类型的变量——指针用于存储值的地址。因此指针名表示的是地址。运算符被称为间接值(indirect velue或解除引用(derefercncing运算符将其应用于指针可以得到该地址处存储的值这和乘法使用的符号相同C根据上下文来确定所指的是乘法还是解除引用。例如假设manly是一个指针则manly表示的是一个地址而manJy表示存储在该地址处的值。*manly与常规int变量等效。程序清单4.15说明了这几点它还演示了如何声明指针。// 指针和自由存储空间415.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。 // #include iostream int main() { using namespace std; int updates 6; int* p_updates; p_updates updates; cout values:updates updates; cout p_updates *p_updates endl; cout Addresses:updates updates; cout ,p_updates p_updates endl; *p_updates *p_updates 1; cout Now updates updates endl; return 0; }运行结果values:updates 6p_updates 6 Addresses:updates 0000001E00CFF654,p_updates 0000001E00CFF654 Now updates 7从中可知int变量updates和指针变量p_updates只不过是同一枚硬币的两面。变量updates表示值并使用运算符来获得地址而变量p-updates表示地址并使用运算符来获得值参见图48。由于p-updates指向updates因此p-updates和updates完全等价。可以像使用int变量那样使用p_updates。正如程序清单4.15表明的甚至可以将值赋给pupdates。这样做将修改指向的值即updates。声明和初始化指针我们来看看如何声明指针。计算机需要指针指卣的值的类型。例如char的地址与double地址看上去没有两样但double和char使用的字节数是不同它们的存储值时使用的内部式也不同。因此指针声明必须指定指针指向的数据的型。例如前一个示例包含这样的声明int *p_updates;这表明p_updates的类型为int。由于运筧符被用于指针因此p_updates变量本身必须是指针。我们说p_updates指向int类型我们还说p_updates的类型是指向int的指针或后int*可以这样说p_updates是指针地址*p_updates是int,而 不是指针(见图4.9。顺便说一句*运算符两边的空格是可选的。传统上C 程序员使用这种格式int *ptr;这强调*ptr 是一个int 类型的值。而很多C程序员使用这种格式int* ptr;这强调的是int是一种类型—指向int 的指针。在哪里添加空格对于编译器来说没有任何区别您甚至可以这样做int* ptr;但要知道的是下面的声明创建一个指针p1和一个int 变量p2int*p1,p2;对每个指针变量名都需要使用一个。注意在C中int *是一种复合类型是指向int 的指针。可以用同样的句法来声明指向其他类型的指针double * tax_ptr; //tax_ptr points to type double char *str; //str points to type char由于己将tax_ptr声明为一个指向double的指针因此编译器知道冰tax一ptr是一个double类型的值。也就是说它知道tax-ptr是一个以浮点格式存储的值这个值在大多数系统上占据8个字节。指针变量不仅仅是指针而且是指向特定类型的指针。tax-ptr的类型是指向double的指针或double类型str是指向char的指针类型或char*),尽管它们都是指针却是不同类型的指针。和数组一样指针都是基于其他类型的。虽然tax-ptr和str指向两种长度不同的数据类型但这两个变量本身的长度通常是相同的。也就是说char的地址与double的地址的长度相同这就好比1016可能是超市的街道地址而1024可以是小村庄的街道地址一样。地址的长度或值既不能指示关于变量的长度或类型的任何信息也不能指示该地址上有什么建筑物。一般来说地址需要2个还是4个字节取决于计算机系统有些系统可能需要更大的地址系统可以针对不同的类型使用不同长度的地址。可以在声明语句中初始化指针。在这种情况下被初始化的是指针而不是它指向的值。也就是说下面的语句将pt而不是*pt的值设置为higgensint higgens5; int *pthiggens;程序清单4.16演示了如何将指针初始化为一个地址。// 如何将指针初始化为一个地址.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。 // #include iostream int main() { using namespace std; int higgens 5; int* pt higgens; cout Value of higgens higgens ; Address of higgens higgens endl; cout Value of *pt *pt ; Value of pt pt endl; return 0; }运行结果Value of higgens 5; Address of higgens 000000B5410FF764 Value of *pt 5; Value of pt 000000B5410FF764从中可知程序将pi而不是*pi初始化为higgens 的地址。在您的系统上显示的地址可能不同显示格式也可能不同。指针的危险指针不是整型虽然计算机通常把地址当作整数来处理。从概念上看指针与整数是截然不同的类型。整数是可以执行加、减、除等运算的数字而指针描述的是位置将两个地址相乘没有任何意义。从可以对整数和指针执行的操作上看它们也是彼此不同的。因此不能简单地将整数赋给指针int *pt; pt0xB8000000;//type mismatch在这里左边是指向int 的指针因此可以把它赋给地址但右边是一个整数。您可能知道0xB8000000是老式计算机系统中视频内存的组合段偏移地址但这条语句并没有告诉程序这个数字就是一个地址。在C99 标准发布之前C 允许这样赋值。但C在类型一致方面的要求更严格编译器将显示一条错误消息通告匹配。要将数字值作为地址来使用应通过强制类型转换将数字转换为适当的地址类型int *pt; pt(int*)0xB8000000;//type mismatch这样赋值语句的两边都是整数的地址因此这样赋值有效。注意pt 是int 值的地址并不意味着pt本身的类型是int。例如在有些平台中int 类型是个2 字节值而地址是个4 字节值。指针还有其他一些有趣的特性这将在合适的时候讨论。下面看看如何使用指针来管理运行阶段的内存空间分配。使用new 来分配内存对指针的工作方式有一定了解后来看看它如何实现在程序运行时分配内存。前面我们都将指针初始化为变量的地址变量是在编译时分配的有名称的内存而指针只是为可以通过名称直接访问的内存提供了一个别名。指针真正的用武之地在于在运行阶段分配未命名的内存以存储值。在这种情况下只能通过指针来访问内存。在C 语言中可以用库函数malloc( )来分配内存在C中仍然可以这样做但C还有更好的方法—new 运算符。下面来试试这种新技术在运行阶段为一个int值分配未命名的内存并使用指针来访问这个值。这里的关键所在是C的new运算符。程序员要告诉new需要为哪种数据类型分配内存new将找到一个长度正确的内存块并返回该内存块的地址。程序员的责任是将该地址赋给一个指针。下面是一个这样的示例int *pnnew int;new int告诉程序需要适合存储int的内存。new运算符根据类型来确定需要多少字节的内存。然后它找到这样的内存并返回其地址。接下来将地址赋给pnpn是被声明为指向int的指针。现在pn是地址而*pn是存储在那里的值。将这种方法与将变量的地址赋给指针进行比较int higgens; int * pthiggens;在这两种情况pn 和pt下都是将一个int 变量的地址赋给了指针。在第二种情况下可以通过名称higgens 来访问该int在第一种情况下则只能通过该指针进行访问。这引出了一个问题pn 指向的内存没有名称如何称呼它呢我们说pn 指向一个数据对象这里的“对象”不是“面向对象编程”中的对象而是一样“东西”。术语“数据对象”比“变量”更通用它指的是为数据项分配的内存块。因此变量也是数据对象但pn 指向的内存不是变量。乍一看处理数据对象的指针方法可能不太好用但它使程序在管理内存方面有更大的控制权。为一个数据对象可以是结构也可以是基本类型获得并指定分配内存的通用格式如下typeName *pointer_namenew typeName;需要在两个地方指定数据类型用来指定需要什么样的内存和用来声明合适的指针。当然如果已经声明了相应类型的指针则可以使用该指针而不用再声明一个新的指针。程序清单4.17 演示了如何将new用于两种不同的类型。#include iostream int main() { using namespace std; int nights 1001; int* pt new int; //allocate space for an int *pt 1001; //store a value there cout nights value ; cout nights :location nights endl; cout int ; cout value *pt :location pt endl; double* pd new double; //allocate space for a double *pd 10000001.0; //store a double there cout double; cout value *pd :location pd endl; cout location of pointer pd: pd endl; cout size of pt sizeof(pt); cout size of pd sizeof pd; cout :size of *pd sizeof(*pd) endl; return 0; }运行结果nights value 1001:location000000E91756FB84 int value 1001:location 000002375D54DC40 doublevalue 1e07:location 000002375D560E70 location of pointer pd:000000E91756FBC8 size of pt 8size of pd 8:size of *pd 8当然内存位置的准确值随系统而异。程序说明该程序使用new 分别为int 类型和double 类型的数据对象分配内存。这是在程序运行时进行的。指针pt 和pd 指向这两个数据对象如果没有它们将无法访问这些内存单元。有了这两个指针就可以像使用变量那样使用pt和pd了。将值赋给pt和pd从而将这些值赋给新的数据对象。同样可以通过打印pt和pd来显示这些值。该程序还指出了必须声明指针所指向的类型的原因之一。地址本身只指出了对象存储地址的开始而没有指出其类型使用的字节数。从这两个值的地址可以知道它们都只是数字并没有提供类型或长度信息。另外指向int的指针的长度与指向double的指针相同。它们都是地址但由于usenew.cpp声明了指针的类型因此程序知道*pd是8个字节的double值pt是4个字节的int值。usenew.cpp打印pd的值时cout知道要读取多少字节以及如何解释它们。对于指针需要指出的另一点是new分配的内存块通常与常规变量声明分配的内存块不同。变量nights和pd的值都存储在被称为栈(stack)的内存区域中而new从被称为堆(heap)或自由存储区(free store)的内存区域分配内存。第9章将更详细地讨论这一点。使用delete 释放内存当需要内存时可以使用new 来请求这只是C内存管理数据包中有魅力的一个方面。另一个方面是delete 运算符它使得在使用完内存后能够将其归还给内存池这是通向最有效地使用内存的关键一步。归还或释放free的内存可供程序的其他部分使用。使用delete 时后面要加上指向内存块的指针这些内存块最初是用new 分配的int * psnew int; //allocate memory with new ... delete ps; //free memory with delete when done这将释放ps 指向的内存但不会删除指针ps 本身。例如可以将ps 重新指向另一个新分配的内存块。一定要配对地使用new 和delete否则将发生内存泄漏memory leak也就是说被分配的内存再也无法使用了。如果内存泄漏严重则程序将由于不断寻找更多内存而终止。不要尝试释放已经释放的内存块C标准指出这样做的结果将是不确定的这意味着什么情况都可能发生。另外不能使用delete 来释放声明变量所获得的内存int *psnew int; //ok delete ps; //ok delete ps; //not ok now int jugs5; //5 int *pijugs; //ok delete pi; //not allowed,memory not allocated by new警告只能用delete 来释放使用new 分配的内存。然而对空指针使用delete 是安全的。注意使用delete 的关键在于将它用于new 分配的内存。这并不意味着要使用用于new 的指针而是用于new 的地址int *psnew int; //allocate memory int *pqps; //set second pointer to same block delete pq; //delete with second pointer一般来说不要创建两个指向同一个内存块的指针因为这将增加错误地删除同一个内存块两次的可能性。但稍后您会看到对于返回指针的函数使用另一个指针确实有道理。使用new 来创建动态数组如果程序只需要一个值则可能会声明一个简单变量因为对于管理一个小型数据对象来说这样做比使用new和指针更简单尽管给人留下的印象不那么深刻。通常对于大型数据如数组、字符串和结构应使用new这正是new的用武之地。例如假设要编写一个程序它是否需要数组取决于运行时用户提供的信息。如果通过声明来创建数组则在程序被编译时将为它分配内存空间。不管程序最终是否使用数组数组都在那里它占用了内存。在编译时给数组分配内存被称为静态联编static binding)意味着数组是在编译时加入到程序中的。但使用new时如果在运行阶段需要数组则创建它如果不需要则不创建。还可以在程序运行时选择数组的长度。这被称为动态联编(dynamic binding意味着数组是在程序运行时创建的。这种数组叫作动态数组(dynamic array)。使用静态联编时必须在编写程序时指定数组的长度使用动态联编时程序将在运行时确定数组的长度。下面来看一下关于动态数组的两个基本问题如何使用C的new运算符创建数组以及如何使用指针访问数组元素。1使用new 创建动态数组在C中创建动态数组很容易只要将数组的元素类型和元素数目告诉new即可。必须在类型名后加上方括号其中包含元素数目。例如要创建一个包含10个int元素的数组可以这样做int *psomenew int[10];//get a block of 10 ints;new 运算符返回第一个元素的地址。在这个例子中该地址被赋给指针psome。当程序使用完new 分配的内存块时应使用delete 释放它们。然而对于使用new 创建的数组应使用另一种格式的delete 来释放delete [] psome; //free a dynamic array方括号告诉程序应释放整个数组而不仅仅是指针指向的元素。请注意delete 和指针之间的方括号。如果使用new 时不带方括号则使用delete 时也不应带方括号。如果使用new 时带方括号则使用delete时也应带方括号。C的早期版本无法识别方括号表示法。然而对于ANSI/ISO 标准来说new 与delete的格式不匹配导致的后果是不确定的这意味着程序员不能依赖于某种特定的行为。下面是一个例子int *ptnew int; short *psnew short[500]; delete []pt;//effect is undefined,dont do it delete ps; //effect is undefined,dont do it总之使用new 和delete 时应遵守以下规则。不要使用delete 来释放不是new 分配的内存。不要使用delete 释放同一个内存块两次。如果使用new [ ]为数组分配内存则应使用delete [ ]来释放。如果使用new [ ]为一个实体分配内存则应使用delete没有方括号来释放。对空指针应用delete 是安全的。现在我们回过头来讨论动态数组。psome是指向一个数组第一个元素的指针。您的责任是跟踪内存块中的元素个数。也就是说由于编译器不能对psome是指向10个整数中的第1个这种情况进行跟踪因此编写程序时必须让程序跟踪元素的数目。实际上程序确实跟踪了分配的内存量以便以后使用delete[]运算符时能够正确地释放这些内存。但这种信息不是公用的例如不能使用sizeof运算符来确定动态分配的数组包含的字节数。为数组分配内存的通用格式如下type_name *pointer_namenew type_name[num_elements];使用new 运算符可以确保内存块足以存储num_elements 个类型为type_name 的元素而pointer_name将指向第1 个元素。下面将会看到可以以使用数组名的方式来使用pointer_name。使用动态数组创建动态数组后如何使用它呢首先从概念上考虑这个问题。下面的语句创建指针psome它指向包含10 个int 值的内存块中的第1 个元素int *psomenew int[10]; //get a block of 10 ints可以将它看作是一根指向该元素的手指。假设int 占4 个字节则将手指沿正确的方向移动4 个字节手指将指向第2 个元素。总共有10 个元素这就是手指的移动范围。因此new 语句提供了识别内存块中每个元素所需的全部信息。现在从实际角度考虑这个问题。如何访问其中的元素呢第一个元素不成问题。由于psome指向数组的第1个元素因此psome是第1个元素的值。这样还有9个元素。如果没有使用过C语言下面这种最简单的方法可能会令您大吃一惊只要把指针当作数组名使用即可。也就是说对于第个元素可以使用psome[0]而不是psome;对于第2个元素可以使用psome[1]依此类推。这样使用指针来访问动态数组就非常简单了虽然还不知道为何这种方法管用。可以这样做的原因是C和C内部都使用指针来处理数组。数组和指针基本等价是C和C的优点之一这在有时候也是个问题但这是另一码事稍后将更详细地介绍这种等同性。首先程序清单4.18演示了如何使用new来创建动态数组以及使用数组表示法来访问元素它还指出了指针和真正的数组名之间的根本差别。#include iostream int main() { using namespace std; double* p3 new double[3]; //space for 3 doubles p3[0] 0.2; p3[1] 0.1; p3[2] 0.8; cout p3[1] is p3[1] .\n; p3 p3 1; //increment the pointer cout Now p3[0] is p3[0] and; cout p3[1] is p3[1] .\n; p3 p3 - 1; //point back beginning delete[] p3; return 0; }运行结果p3[1] is0.1. Now p3[0] is0.1andp3[1] is 0.8.从中可知arraynew.cpp 将指针p3 当作数组名来使用p3[0]为第1 个元素依次类推。下面的代码行指出了数组名和指针之间的根本差别p3p31; //okay for pointers,wrong for array names不能修改数组名的值。但指针是变量因此可以修改它的值。请注意将p3加1的效果。表达式p3[0]现在指的是数组的第2个值。因此将p3加1导致它指向第2个元素而不是第1个。将它减1后指针将指向原来的值这样程序便可以给delete[]提供正确的地址。相邻的int地址通常相差2个字节或4个字节而将p3加1后它将指向下一个元素的地址这表明指针算术有一些特别的地方。情况确实如此。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

建设网站要不要钱百度贴吧企业订单管理系统软件

GB28181自动化测试:提升测试效率的完整解决方案 【免费下载链接】GB28181自动化测试工具 GB28181自动化测试工具是一款专为GB28181协议设计的测试解决方案,帮助用户快速、高效地完成协议自动化测试。工具经过严格测试,确保稳定可用&#xff0…

张小明 2026/1/11 17:39:34 网站建设

模板建站按年收费贵阳网站定制建设开发 首商网

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个基于浏览器的JDK1.8云端体验平台,用户无需安装即可直接编写和运行Java代码。平台应预装JDK1.8环境,提供代码编辑器、终端和简单的项目管理功能。支持…

张小明 2026/1/11 17:39:32 网站建设

东莞网站建设硅胶重庆网站建设夹夹虫公司

王总,在上月的国际电机技术峰会上,我与全球前五大无刷马达制造企业的技术高管进行了深入交流。一个明确的行业趋势已经形成:头部企业已将六西格玛方法论深度融入研发与制造体系,其量产产品的平均效率从三年前的90.2%提升至当前的9…

张小明 2026/1/10 19:18:03 网站建设

在哪个网站做外贸生意好网站建设方案书个人

信号和信号组可以有一个额外的Bit,表示该信号或信号组是否被更新。这个参数对应用层是不可见的。注意:1、对于ComTxModeNumberOfRepetitions大于等于1的DIRECT报文,UpdateBit是不允许的。发送端如果发送信号使能了UpdateBit, 在调…

张小明 2026/1/11 17:39:29 网站建设

石家庄的网站的公司网站建设公司的流程

✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室🍊个人信条:格物致知,完整Matlab代码获取及仿真…

张小明 2026/1/10 19:38:25 网站建设

如何建开发手机网站seo网站推广计划

数字营销:策略、技术与内容的全面解析 一、数字营销新流程与情感监测 数字营销实际上是一种全新的营销流程。潜在客户与营销活动之间存在众多接触点,“培育式”营销模式聚焦于从首次接触到客户产生真正兴趣的这段时间,可能长达数年。为使该模式有效运作,持续监测客户情感…

张小明 2026/1/11 16:56:43 网站建设