c语言编程要点(编辑修改稿)内容摘要:

a= b+(((c/d)/function— call())* 5) 这样,就能确保表达式被正确求值,而且编译程序不会为了优化代码而重新安排运算符的优先级了。 1. 13 ++var 和 var++有什么区别 ? “++” 运算符被称为自增运算符。 如果 “++” 运算符出现在变量的前面 (++var),那么在表达式使用变量之前,变量的值将增加 1。 如果 “++” 运算符出现在变量之后 (var++),那么先对表达式求值,然后变量的值才增加 1。 对自减运算符 ()来说,情况完全相同。 如果运算符出现在变量的前面,则相应的运算被称为前缀运算;反之,则称为后缀运算。 例如,请看一个使用后缀自增运算符的例子: int x, y。 x=1。 y=(x++* 5); 上例使用了后缀自增运算符,在求得表达式的值之后, x 的值才增加 1,因此, y 的值为 1乘以 5,等于 5。 在求得表达式的值之后, x 自增为 2。 现在看一个使用前缀自增运算符的例子: int x, y。 x=1。 y=(++x*5)。 这个例子和前一个相同,只不过使用了前缀自增运算符,而不是后缀自增运算符,因此,x 的值先增加 1,变为 2,然后才求得表达式的值。 这样, y 的值为 2 乘以 5,等于 10。 1. 14 取模运算符 (modulus operator)“% ”的作用是什么 ? 取模运算符 “ % ” 的作用是求两个数相除的余数。 例如,请看下面这段代码: x=15/7。 如果 x 是一个整数, x 的值将为 2。 然而,如果用取模运算符代替除法运算符 /,得到的结果就不同了: X=15% 7。 这个表达式的结果为 15除以 7 的余数,等于 1。 这就是说, 15除以 7 得 2 余 1。 取模运算符通常用来判断一个数是否被另一个数整除。 例如,如果你要打印字母表中序号为 3的倍数的字母,你可以使用下面这段代码: int x。 for(x= 1。 x=26。 x++) if((x%3)== 0) 11 printf(%c。 x+64)。 上例将输出字符串 cfilorux,即字母表中序号为 3的倍数的所有字母。 第 2章 变量和数据存储 C 语言的强大功能之 一是可以灵活地定义数据的存储方式。 C 语言从两个方面控制变量的性质:作用域 (scope)和生存期 (lifetime)。 作用域是指可以存取变量的代码范围,生存期是指可以存取变量的时间范围。 作用域有三种: 1. extern(外部的 ) 这是在函数外部定义的变量的缺省存储方式。 extern 变量的作用域是整个程序。 2. static(静态的 ) 在函数外部说明为 static 的变量的作用域为从定义点到该文件尾部;在函数内部说明为 static 的变量的作用域为从定义点到该局部程序块尾部。 3. auto(自动的 ) 这是在函数内部说明的变量的缺省存储方式。 auto 变量的作用域为从定义点到该局部程序块尾部。 变量的生存期也有三种,但它们不象作用域那样有预定义的关键字名称。 第一种是 extern和 static 变量的生存期,它从 main()函数被调用之前开始,到程序退出时为止。 第二种是函数参数和 auto 变量的生存期,它从函数调用时开始,到函数返回时为止。 第三种是动态分配的数据的生存期,它从程序调用 malloc()或 calloc()为数据分配存储空间时开始,到程序调用 free()或程序退出时为 止。 . 变量存储在内存 (memory)中的什么地方 ? 变量可以存储在内存中的不同地方,这依赖于它们的生存期。 在函数外部定义的变量 (全局变量或静态外部变量 )和在函数内部定义的 static 变量,其生存期就是程序运行的全过程,这些变量被存储在数据段 (datasegment)中。 数据段是在内存中为这些变量留出的一段大小固定的空间,它分为两部分,一部分用来存放初始化变量,另一部分用来存放未初始化变量。 在函数内部定义的 auto变量 (没有用关键字 static定义的变量 )的生存期从程序开始执行其所在的程序块 代码时开始,到程序离开该程序块时为止。 作为函数参数的变量只在调用该函数期间存在。 这些变量被存储在栈 (stack)中。 栈是内存中的一段空间,开始很小,以后逐渐自动增大,直到达到某个预定义的界限。 在象 DOS这样的没有虚拟内存 (virtual memory)的系统中,这个界限由系统决定,并且通常非常大,因此程序员不必担心用尽栈空间。 关于虚拟内存 的讨论,请参见 2. 3。 第三种 (也是最后一种 )内存空间实际上并不存储变量,但是可以用来存储变量所指向的数据。 如果把调用 malloc()函数的结果赋给一个指 针变量,那么这个指针变量将包含一块动态分配的内存的地址,这块内存位于一段名为 “ 堆 (heap)” 的内存空间中。 堆开始时也很小,但当程序员调用 malloc()或 calloc()等内存分配函数时它就会增大。 堆可以和数据段或栈共用一个内存段(memorysegment),也可以有它自己的内存段,这完全取决于编译选项和操作系统。 与栈相似,堆也有一个增长界限,并且决定这个界限的规则与栈相同。 请参见: 1. 1 什么是局部程序块 (10calblock)? 2. 2 变量必须初始化吗 ? 12 2. 3 什么是页抖动 (pagethrashing)? 7. 20 什么是栈 (stack)? 7. 21 什么是堆 (heap)7 . . 变量必须初始化吗 ? 不。 使用变量之前应该给变量一个值,一个好的编译程序将帮助你发现那些还没有被给定一个值就被使用的变量。 不过,变量不一定需要初始化。 在函数外部定义的变量或者在函数内部用 static 关键字定义的变量 (被定义在数据段中的那些变量,见 2. 1)在没有明确地被程序初始化之前都已被系统初始化为 0 了。 在函数内部或程序块内部定义的不带 static 关键字的变量都是自动变量,如果你没有明确地初始化这些变量,它们就会具有未定义值。 如果你没有初始化一个自动变量,在使用它之前你就必须保证先给它赋值。 调用 malloc()函数从堆中分配到的空间也包含未定义的数据,因此在使用它之前必须先进行初始化,但调用 calloc()函数分配到的空间在分配时就已经被初始化为 0 了。 请参见: 1. 1 什么是局部程序块 (10calblock)? 7. 20 什么是栈 (stack)? 7. 21 什么是堆 (heap)? . 什么是页抖动 (pagethrashing)? 有些操作系统 (如 UNIX 和增强模式下的 Windows)使用虚拟内存,这是一种使机器的作业地址空间大于实际内存的技术,它是通过用磁盘空间模拟 RAM(random— access memory)来实现的。 在 80386 和更高级的 Intel CPU 芯片中,在现有的大多数其它微处理器 (如 Motorola 68030, sparc 和 Power PC)中,都有一个被称为内存管理单元 (Memory Management Unit,缩写为MMU)的器件。 MMU 把内存看作是由一系列 “ 页 (page)” 组成的来处理。 一页内存是指一个具有一定大小的连续的内存块,通常为 4096 或 8192 字节。 操作系统为每个正在运行的程序建立并维护一张被称为进程内存映射 (Process Memory Map,缩与为 PMM)的表,表中记录了程序可以存取的所有内存页以及它们的实际位置。 每当程序存取一块内存时,它会把相应的地址 (虚拟地址, virtualaddress)传送给 MMU,MMU 会在 PMM 中查找这块内存的实际位置 (物理地址, physical address),物理地址可以是由操作系统指定的在内存中或磁盘上的 任何位置。 如果程序要存取的位置在磁盘上,就必须把包含该地址的页从磁盘上读到内存中,并且必须更新 PMM以反映这个变化 (这被称为 pagefault,即页错 )。 希望你继续读下去,因为下面就要介绍其中的难点了。 存取磁盘比存取 RAM 要慢得多,所以操作系统会试图在 RAM 中保持尽量多的虚拟内存。 如果你在运行一个非常大的程序 (或者同时运行几个小程序 ),那么可能没有足够的 RAM 来承担程序要使用的全部内存,因此必须把一些页从RAM 中移到磁盘上 (这被为 pagingout,即页出 )。 操作系统会试图去判断 哪些页可能暂时不会被使用 (通常基于过去使用内存的情况 ),如果它判断错了,或者程序正在很多地方存取很多内存,那么为了读入已调出的页,就会产生大量页错动作。 因为 RAM 已被全部使用,所以为了调入要存取的一页,必须调出另一页,而这将导致更多的页错动作,因为此时不同的一页已被移到磁盘上。 在短时间内出现大量页错动作的情形被称为页抖动,它将大大降低系统的执行效率。 频繁存取内存中大量散布的位置的程序更容易在系统中造成页抖动。 如果同时运行许多小程序,而实际上已经不再使用这些程序,也很容易造成页抖动。 为了减少页抖动, 你应该减少同时运行的程序的数目。 对于大的程序,你应该改变它的工作方式,以尽量使操作系统能准确地判 13 断出哪些页不再需要。 为此,你可以使用高速缓冲存储技术,或者改变用于大型数据结构的查找算法,或者使用效率更高的 malloc()函数。 当然,你也可以考虑增加系统的 RAM,以减少页出动作。 请参见: 7. 17 怎样说明一个大于 640KB 的数组 ? 7. 21 什么是堆 (heap)? 18. 14 怎样才能使 DOS 程序获得超过 64KB 的可用内存 ? 21. 31 Windows 是怎样组织 内存的 ? . 什么是 const 指针 ? 如果希望一个变量在被初始化后其值不会被修改,程序员就会通过 const,修饰符和编译程序达成默契。 编译程序会努力去保证这种默契 —— 它将禁止程序中出现对说明为 const 的变量进行修改的代码。 const 指针的准确提法应该是指向 const 数据的指针,即它所指向的数据不能被修改。 只要在指针说明的开头加入 const 修饰符,就可说明一个 cosnt 指针。 尽管 const 指针所指向的数据不能被修改,但 cosnt 指针本身是可以修改的。 下面给出了 const 指针的一些合法和非法的 用法例子: const char *str=hello。 char c=*str。 /*legal*/ str++。 /*legal*/ *str=39。 a39。 /* illegal */ str[1]= 39。 b39。 /*illegal*/ 前两条语句是合法的,因为它们没有修改 str 所指向的数据;后两条语句是非法的,因为它们要修改 str 所指向的数据。 在说明函数参数时,常常要使用 const 指针。 例如,一个计算字符串长度的函数不必改变字符串内容,它可以写成这样: my_strlen(const char *str) { int count=0。 while ( * str++) { count ++。 } return count。 } 注意,如果有必要,一个非 const 指针可以被隐式地转换为 const 指针,但一个 const 指针不能被转换成非 const 指针。 这就是说,在调用 my_strlen()时, 它的参数既可以是一个 const指针,也可以是一个非 const 指针。 请参见: 2. 7 一个变量可以同时被说明为 const 和 volatile 吗 ? 14 2. 8 什么时候应该使用 const 修饰符 ? 2. 14 什么时候不应该使用类型强制转换 (type cast)? 2. 18 用 const 说明常量有什么好处 ? . 什么时候应该使用 register 修饰符 ?它真的有用吗 ? register 修饰符暗示编译程序相应的变量将被频繁使用,如果可能的话,应将其保存在CPU 的寄存 器中,以加快其存取速度。 但是,使用 register 修饰符有几点限制。 首先, register 变量必须是能被 CPU 寄存器所接受的类型。 这通常意味着 register 变量必须是一个单个的值,并且其长度应小于或等于整型的长度。 但是,有些机器的寄存器也能存放浮点数。 其次,因为 register 变量可能不存放在内存中,所以不能用取址运算符 “amp。 ” 来获取register 变量的地址。 如果你试图这样做,。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。