《C程序设计语言(第2版·新版)》第4章 函数与程序结构

函数功能:隐藏操作细节,结构更加清晰,降低修改难度;

4.1 函数基本知识

返回值类型 函数名(参数声明表)

{

声明和语句

}

  函数在源文件中出现的次序可以任意;

  返回值类型省略则默认int;return可不带表达式,执行到最后右花括号也会返回:都是没有返回值的,合法,但未成功返回的“值”肯定是无用的;

  程序可看做变量定义与函数定义的集合;函数通过参数、返回值和外部变量通信;

4.2 返回非整型的函数

  函数与调用它的主函数在同一源文件中,并且类型不一致时,编译就会发现该错误;

  隐式声明:如果未声明过的一个名字出现在某表达式中,并且其后紧跟左圆括号,那么上下文会认为这是一个函数名,其返回值会被假定为int,其参数不做任何假设;

  return (表达式);表达式的值返回时会被转换为函数类型,这可能会丢失信息有些编译器会警告,故可显示类型转换;

4.3 外部变量

  C程序可看做一系列外部对象(包括变量和函数)构成;

  外部变量定义在函数外;函数不允许定义在其它函数中,故每一个函数也是“外部的”;

  ??(It)外部变量与函数默认具有“外部链接”性质:即使来自于单独编译的不同函数,通过同一个名字引用的都是同一个对象,据此函数可以借助外部变量通信,尤其函数需要共享大量信息时,同时也会使函数之间产生大量的数据联系,影响程序结构;

  后面会介绍怎样定义只使用在一个源文件中的外部变量和函数;后面再讨论怎么把程序分割成多个源文件;

  外部变量生存期:永久存在,两次函数调用之间保持不变;

  函数共享的“”,可定义为外部变量,同时定义一个指针保存下一个空闲栈位置;

4.4 作用域规则

  函数与外部变量可分开编译;一个程序可放在几个文件中;已编译过的函数可从库中加载;

  作用域:程序中可以使用该名字的部分;局部变量(包括函数参数)作用域在函数内;外部变量或函数作用域从声明处开始,到其所在(待编译的)文件末尾结束,函数调用它们时无需声明直接用;

  extern:如果要在外部变量定义之前使用它,或者定义与使用不在同一个源文件中,则声明中须强制使用extern;

  ??外部变量声明与定义的区分:

  放在所有函数外部的int sp;double val[MAX];定义外部变量sp及val,分配内存单元,同时作为该源文件其余部分的声明;

  extern int sp;extern double val[MAX]为源文件其余部分声明了外部变量sp及val(数组长度可在其他地方确定),但是并未建立变量或者分配存储单元;

  一个源程序的所有源文件中,一个外部变量只能在某个文件中定义一次;其他文件必须先进行extern声明后才能访问它;(??也可在定义所在源文件进行extern声明);外部变量初始化只能出现在其定义中;一个变量如果要先使用后定义,使用前也须extern声明一下;

4.5 头文件

  实际程序中,考虑到其各部分可能分别来自单独编译的库,所以常常将源程序分割成多个源文件;

考虑定义和声明的共享问题:(It)尽可能在一个头文件中专门集中各个源文件共享/公共部分(宏替换、函数原型等,简洁易修改),然后在各个需要的源文件中通过include "~.h"包含进去;较大规模程序可能需要多个头文件;

4.6 静态变量

  外部变量或函数的声明前加上static:该对象作用域限定为被编译源文件剩余部分,对其他文件不可见(同名也不会冲突);

  内部变量声明前加static:与自动变量一样只能在该函数内使用;不同之处在于不管该函数是否被调用,它一直存在一直占据存储空间,而非像自动变量那样随着函数的调用和退出而存在和消失;(It)该函数下次调用时可以使用上次调用留下的静态变量值,有时很有用(p57);

4.7寄存器变量

  在较高频使用的自动变量或函数形参的声明前可加register,编译器可以将它放入寄存器中从而加快速度,编译器也可以忽略此选项;

  实际底层硬件情况的限制:每个函数只有少量某些类型的变量可保存于寄存器;过量寄存器声明是无害的,编译器会忽略过量或不支持的寄存器变量声明;

  无论寄存器变量是否真的放在寄存器中,其地址总是不能访问的;

4.8 程序块结构

  C语言不能在函数中定义函数,但可以在函数的程序块结构中定义变量;变量声明(包括初始化)可以紧跟在任何标识复合语句开始的左花括号之后,在与之匹配的右花括号之前一直存在,并且它与该程序块以外的同名变量无任何关系;

4.9初始化

  不显式初始化:则外部变量和静态变量都将被初始化为0;自动变量和寄存器变量初值未定义(即无用信息);

  显式初始化:外部变量和静态变量=常量表达式,且只在程序开始前初始化一次;自动变量和寄存器变量每次进入函数或程序块时都将被初始化,且无需是常量表达式:可以包含之前已定义的值及函数调用;

  数组的初始化:

int day[]={31,28,31,30,31,30,31,30,31,30,31};

  忽略数组长度时,花括号中初始化表达式的个数将被编译器作为长度;数组长度多于个数,对外部变量、静态变量、自动变量,剩余未初始化的元素都将赋0;长度小于个数则出错;一个初始化表达式不能一次赋给多个元素;不能跳过前面元素直接初始化后面元素;

  字符数组初始化:

char pattern[]="ould";等价于char pattern[]={‘o‘,‘u‘,‘l‘,‘d‘,‘\0‘};数组长度是5;

4.10 递归

  函数可以直接或间接调用自身;

  快排函数:void qsort(int v[], int left, int right) //p74

  标准库中的qsort函数可以对任何类型的对象进行排序;

  递归并不节省存储开销(必须在某个地方维护一个存储处理值的栈),执行速度并不快;但其代码紧凑易于编写和理解;对于树等递归定义的数据结构使用起来非常方便;

4.11 C预处理器

  预处理器是编译过程中单独执行的第一个步骤;

文件包含:

#include "文件名" 或 #include <文件名>

  源文件中任何形如上述的行都将被替换为文件名指定的内容;对""则在源文件所在位置查找该文件,对未找到或<>则按相应规则(与具体实现有关)查找;

  #include指令常用来包含#define、extern声明、函数原型,在较大程序中这有利于避免错误;若某个被包含文件内容变化,显然所有依赖于它的源文件都必须重新编译;

宏替换:

宏定义:#define 名字 替换文本

  名字命名同变量,替换文本可以是任意字符串;替换文本需分行,则在待续行尾加\;作用域从定义点到源文件末尾;宏定义可以使用前面出现的宏定义;替换只对记号(即不在字符串内也不是某名字的一部分)有用;

  带参数的宏定义,例如:

#define max(A, B) ((A)>(B) ? (A) : (B))

  使用需谨慎:适当用圆括号以保证计算顺序正确;考虑表达式的例如自增自减等副作用;

  宏的价值:函数(如getchar)被定义为宏,可避免调用函数所需运行时的开销;

#undef 名字 可取消宏定义;

  ??名字中的形参不能用带引号字符串替换,若需要,则在替换文本中给参数前加上#;

  预处理运算符##:若替换文本中形参与它相邻,则形参被实参替换的同时##及其前后空白符会被删除,替换后的结果会重新扫描;此法可连接实际参数,例如:

#define paste(front, back) front ## back

则宏调用paste(name, 1)将建立记号name1;

条件包含:

#if-#elif-#else-#endif

  其中判断表达式必须是常量整型表达式(且不包含sizeof、(type)、enum量),可以是defined(名字)表达式(可用来避免重复包含某一名字或文件,多文件都使用这一方式,将不必考虑各个头文件之间的依赖关系);

#ifdef与#ifndef:专门测试某个名字是否已定义,例如:

#ifndef HDR

#define HDR

//放hdr.h的内容

#endif

它等价于

#if !define(HDR)

#define HDR

//放hdr.h的内容

#endif

时间: 2024-11-25 14:53:36

《C程序设计语言(第2版·新版)》第4章 函数与程序结构的相关文章

JavaScript高级程序设计(第三版)第七章 函数表达式

一种是函数声明:另一种是函数表达式. 函数声明提升: say Hi(); function say Hi(){ alert("Hi!"); }      //这个例子不会抛出错误,因为在代码执行之前会先读取函数声明. 匿名函数:var functionName=function(arg0,arg1,arg2){函数体}; sayHi();   //错误:函数还不存在 var sayHi=function(){ alert("Hi!"); }; //不要这样做    

C语言函数与程序结构

title : C语言函数与程序结构 tags : C语言作用域规则 , 外部变量 ,静态变量 ,寄存器变量,宏定义 grammar_cjkRuby: true --- 外部变量 变量声明用于说明变量的属性(类型),而变量定义还会引起存储器分配 int sp; double s[MAX]; 声明地方:函数外 如果上面的变量定义在所有函数之外,即为外部变量,并为这两个外部变量sp.s[MAX],分配储存单元以及数组的长度,在其源文件中的所有函数都可以使用这两个外部变量. extern int sp

《Python学习手册 第五版》 -第16章 函数基础

前面的章节讲解的是一些基础数据类型.基本语句使用和一些文档查看的内容,这些都是一些基础,其实还谈不上入门,只有了解了函数,才算入门 函数是编程里面使用最多的也是最基本的程序结构, 本章重点内容 1.函数 1)什么是函数? 2)为什么使用函数? 2.编写函数 1)函数的基本格式 2)定义和调用函数 3)函数的多态.局部变量 接下来针对本章重点,展开详细的说明 1.函数 1)什么是函数? 这里没有严格的定义,用通俗易懂的方式来说: 函数就是将一些语句集合在一起的组件,从而让他们能够不止一次的在程序中

C程序设计语言(第二版)--- 习题选

1. 解: 2. 解: 3. (分析的好有条理啊!) 4.

JavaScript高级程序设计(第3版)第六章读书笔记

第六章 面向对象的程序设计 1. 数据属性 [[Configurable]]:表示能否通过delete删除属性从而重新定义属性.默认值为true. [[Enumerable]]:表示能否通过for-in循环返回属性.默认值为true. [[Writable]]:表示能否修改属性的值,默认为true. [[Value]]:包含这个属性的数据值.默认为undefined. 要修改属性默认的特性,必须使用ECMAScript5的Object.defineProperty( )方法.接收三个参数:属性所

JavaScript高级程序设计(第3版) 第三章 (基本概念)

3.1 语法 1.不以数字开头的数字,字母,下划线,美元符号 2.注释:html <!-- --> css/**/ js单行// 多行/**/ 3.ES5 引入了严格模式(strict mode).即为js定义的一种不同的解析与执行模型. 可以在整个脚本头部或者函数的上方,包含"use strict"来启用严格模式(ie10以上支持严格模式) 3.2 关键字和保留字 3.3 变量 1.ECMAScript的变量是松散型的.即每个变量仅仅是一个用于保存值的占位符而已. 不存在

JavaScript高级程序设计(第3版)第五章读书笔记

第五章 引用类型 创建Object实例的方式有两种,第一种是使用new操作符后跟Object构造函数,例如: var person = new Object( ); person.name = “Nicholas”; person.age=29; 第二种是使用对象字面量表示法.如: var person = { name : “Nicholas”, age : 29 }; 在最后一个属性后面添加逗号,会在IE7及更早版本和Opera中导致错误. 两种访问对象属性的方法,一是方括号语法,例如per

JavaScript高级程序设计(第三版) (5章 引用类型)

引用类型 在ECMAScript 中,引用类型是一种数据结构,用于将数据和功能组织在一起.这种数据类型不具备传统的面向对象语言所支持的类和接口等基本结构.引用类型有时候也被称为对象定义,因为他们描述的是一类对象所具有的属性和方法. 5.1    Object类型 5.2    Array类型 特点: 每一项可以保存任何类型的数据: 大小可以动态调整 length大小可变(最大值4294967295) 两种创建方式: 一:通过构造函数创建 //不指定大小 var colors1 = new Arr

《avascript 高级程序设计(第三版)》 ---第一章 Javascript简介

这一章主要是介绍了 Javascript的一些历史: 1.Javascript主要由三个部分组成:ECMAScript,DOM,BOM. ECMAScript:现在主流浏览器已经全部支持. DOM:把整个HTML页面映射为一个多层节点结构.通过DOM提供的API,开发人员可以轻松自如的删除,添加,替换或修改节点. BOM:控制浏览器窗口大小,移动,AJAX对象等. 总结:Javascript是一种专门为网页交互而设计的脚本语言.