参考书 《C++程序设计教程》 钱能 主编 清华大学出版社

Slides:



Advertisements
Similar presentations
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Advertisements

Tool Command Language --11级ACM班 金天行.
第三章 鏈結串列 Linked List.
6.4 字符串与指针 1. 用字符数组存放一个字符串.
C语言实验 第一课 标题:学号+姓名.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
單向鏈結串列 Singly Linked Lists.
4.3函数 4.3.1函数的概念及定义 1、函数的概念: 可以被其它程序调用具有 特定功能的一段相对独立的 程序(模块),称函数。
走向C++之路 WindyWinter WindyWinter感谢诸位前来捧场。
内容提要 对象的生命周期 构造函数 析构函数 拷贝构造函数. 常宝宝 北京大学计算机科学与技术系
C++程序设计 第二讲 清华大学软件学院.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
第三章 C++中的C 面向对象程序设计(C++).
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
走进编程 程序的顺序结构(二).
辅导课程六.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第二章 C++对C 在非面向对象方面的改进 更简洁,更安全.
第1章 C++概述  知识点 面向对象程序设计的基本概念 C++的起源和特点 C++源程序的构成 C++在非面向对象方面的一些特性
第一章 C++基础.
第二章 Java语言基础.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
第七章 操作符重载 胡昊 南京大学计算机系软件所.
第三章 链表 单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
1.3 C语言的语句和关键字 一、C语言的语句 与其它高级语言一样,C语言也是利用函数体中的可执行 语句,向计算机系统发出操作命令。按照语句功能或构成的不 同,可将C语言的语句分为五类。 goto, return.
C语言程序设计 主讲教师:陆幼利.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
$9 泛型基础.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
第11章 從C到C++語言 11-1 C++語言的基礎 11-2 C++語言的資料型態與運算子 11-3 C++語言的輸出與輸入
第五章 函 数 要点:掌握函数的定义,函数的原形,函数的返回值,函数的调用,函数的形式参数和实际参数之间的关系;掌握函数重载的使用方法,关键字inline的含义与使用,掌握变量的作用域与生存期,了解函数的作用域。
第三章 数据抽象.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第4章 Excel电子表格制作软件 4.4 函数(一).
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第九节 赋值运算符和赋值表达式.
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第二章 高级函数特性.
挑戰C++程式語言 ──第9章 函數.
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院.
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
本节内容 结构体.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
鸡兔同笼(续) ——选择结构.
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
顺序结构程序设计 ——关于“字符串”和数值.
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
编译原理实践 6.程序设计语言PL/0.
本节内容 this指针 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
§2 自由代数 定义19.7:设X是集合,G是一个T-代数,为X到G的函数,若对每个T-代数A和X到A的函数,都存在唯一的G到A的同态映射,使得=,则称G(更严格的说是(G,))是生成集X上的自由T-代数。X中的元素称为生成元。 A变, 变 变, 也变 对给定的 和A,是唯一的.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

常宝宝 北京大学计算机科学与技术系 chbb@pku.edu.cn

参考书 《C++程序设计教程》 钱能 主编 清华大学出版社 Thinking in C++, Volume 1 Bruce Eckel 机械工业出版社 Data Structures and Program Design Robert L. Kruse & Alexander J. Ryba 高等教育出版社

关于C++ C++是一种程序设计语言 C++和C的关系: C是C++的子集 C++非常流行 C++是面向对象的程序设计语言

内容提要 C++中新增的注释方法 标准输入流和标准输出流 关于引用 引用和函数 函数重载 函数参数的默认值 内联函数 动态内存分配和回收

C++中新增的注释方法 C语言中,注释内容始于/*,止于*/,注释可以跨行,在C++中仍可使用。 在C++中,也可以用//来表示注释。 //this is the first C++ program #include <iostream.h> int main() { cout<<"Hello, World!"<<endl; }

标准输入流和标准输出流 C语言中,常使用函数printf(...) 和函数scanf(...)进行数据的输入和输出。 C++中常使用流对象进行输入和输出: (1)标准输入流对象cin (2)标准输出流对象cout cin和cout分别相当于C语言中的stdin、stdout,对应于键盘、控制台窗口,均可以被重定向。 要在程序中使用cin和cout,程序头部要包含头文件iostream.h 在控制台窗口显示信息,使用标准输出流cout的插入运算符<<。

标准输入流和标准输出流 //standard output stream #include <iostream.h> void main() { int a; …… cout << "This is the first C++ Program\n" ; cout << a << "\n"; //显示变量a的内容 }

标准输入流和标准输出流 从键盘读入数据,使用标准输入流的提取运算符>>。 输入数据的类型和提取运算符>>右边变量的类型一致。 cin和cout可以正确处理所有的基本数据类型(整型、实型、字符型、字符串),对于自定义的复杂类型,需要对运算符进行重载 …… int age; …… cout << "Please input your age: "; cin >> age; ……

标准输入流和标准输出流 显示多个数据以及输入多个数据,可以写在同一行中。 …… int a; float b; char c; cin >> a >> b >> c; cout << "a=" << a << "\n"<< "b=" << b << "\n" << "c=" << c << "\n";

标准输入流和标准输出流 在使用标准输出流时,可以使用算子改变输出格式和以及进行输出控制。 表示换行的算子为endl,如: cout << endl; //显示换行。 改变显示数制的算子: dec 十进制显示 hex 十六进制显示 oct 八进制显示 设置显示宽度的算子是setw(n),如: cout << setw(8) <<a << endl; 关于其它更多的算子,参见《C++程序设计教程》p22-27 使用算子,要包含头文件iomanip.h …… int a = 10; cout << hex << a << endl;

引用 在C++中,可以为一个变量建立引用,这相当于为该变量建立了一个别名。 引用本质是常量指针。 声明引用必须初始化,引用一旦初始化,就和一个目标(变量和对象)联系起来了。声明引用的格式如下: 类型 &引用名=变量名; …… int a; int&b = a;//为变量a建立了一个引用b

引用 引用和引用目标之间的联系一旦建立,就再也不分开: 对该引用的任何赋值,都是对引用联系的目标赋值。 对引用做求地址运算,都是对引用联系的目标求地址。 引用不是变量,通常编译器不会为引用分配存储空间。 …… int a, *pb, *pa; int&b = a;//为变量a建立了一个引用b a = 1; cout << b << endl; // 1 b = 10; cout << a << endl; // 10 pb = &b; pa = &a; // pa == pb

引用 引用的类型和其联系的目标的类型应该相同。 struct _student { char id[20]; char name[20]; int score; }; typedef struct _student STUDENT; …… STUDENT s; int& a = s; //错误

引用 引用的初始值可以不是左值(l-value),这时实际上相当于建立一个临时目标并用该初值初始化该目标,然后建立该临时目标的引用,例如: const int& i = 1; 相当于 const int temp = 1; const int& i = temp; 不能为数组建立引用,数组名本身不是一个数据类型,例如: int a[10]; int& ra[10] = a; //错误 可以为指针建立引用,例如: int *a; int b; int* & p = a; p = &b; //现在a的内容是什么?

函数参数传递 c语言中,所有函数调用均为传值调用(call by value),即在为函数传递参数时,要为函数建立参数的副本。 在传递较大的对象时,浪费时间空间;函数不能改变实参的值。 void swap( int a, int b ) { int temp; temp = a; a = b; b = temp; } int main() { int x=5, y=6; swap(x,y);// x=? Y=? ……

函数参数传递 在C语言中,可以采用指针来弥补传值调用的不足。 但采用指针的缺点是书写麻烦,可读性差。 void swap( int* a, int* b ) { int temp; temp = *a; *a = *b; *b = temp; } int main() { int x=5, y=6; swap(&x,&y);// x=? y=? ……

函数参数传递 C++增加了引用调用(call by reference)。即在定义参数时,把参数定义为引用。例如: void swap(int& a, int& b ) { … } 按照引用调用,函数不会为实参建立副本,而是把实参的地址传递给函数。(和指针传递道理相同,但写法不同) 由于引用调用不为实参建立副本,在传递较大的对象时,有效地节省了时间空间开销。由于函数得到了实参的地址,函数体对形参内容的改变会影响到实参。 在采用引用调用的函数中,对形参的无需用间接引用运算符*。,

函数参数传递 int temp;//a 和 b 相当于实参的别名 temp = a; a = b; b = temp; } void swap( int& a, int& b ) { int temp;//a 和 b 相当于实参的别名 temp = a; a = b; b = temp; } int main() { int x=5, y=6; swap(x,y);// x=? y=? ……

函数参数传递 由于引用调用会影响实参的内容,如果不希望函数体改变实参的值,可以采用const修饰符限制函数体改变实参的值。 void swap( const int& a, const int& b ) { int temp; //这个函数编译时会报错 temp = a; //因为函数体要修改实参的值 a = b; b = temp; } int main() { int x=5, y=6; swap(x,y);// x=? y=? ……

函数参数传递 在C++中,任何函数都只能有一个返回值,如果希望返回多个结果,可以采用引用调用的办法解决。(当然也可以用指针的办法) int divide(int dividend, int divisor,int& quotient,int& remainder) {//求整数相除所得的商和余数 if ( divisor==0 ) return 0; quotient = dividend / divisor; remainder = dividend % divisor; return 1; } int main() { int x = 10, y = 3, q, r, s; s = diviede( x, y, q, r );// x、y、q、r、s的值是什么?

返回引用的函数 通常函数在返回值时,实际上为返回值建立了一个副本。调用者得到的是返回值的副本,这引起时空消耗。例如: return x;//函数在返回时,建立了一个x的副本 在C++中,可以规定函数返回引用,从而不为返回值建立副本。若希望函数返回引用,可将函数的返回类型声明为引用。 int& g(int& x) { x++; return x; } int main() { int z = 6, y; y = g(z); //y和z的值是什么?

返回引用的函数 返回引用不为返回值建立副本,所以不能返回不在作用域范围内的变量或对象的引用。 int& g(int& x) { //这个函数是错误的 int a; //a是一个局部变量,作用域范围仅限于本函数 a = x; //函数执行结束后,a所占据的空间被回收,所以 a++; //变量a不再存在,故对它的引用也没有意义 return a; } int main() { int z = 6, y; y = g(z);

返回引用的函数 在函数返回引用时,函数调用可以作为左值(l-value),左值是可以出现在赋值号(=)左边的表达式。 int& g(int& x) { x++; return x; } int main() {//这个程序在C++中可以正确编译 int z = 6; g(z) = 5; //z的值是什么?

函数名重载 在C语言中,每个函数都必须有惟一的名字。如果两个函数功能相同,仅仅参数类型不同,也不能例外。 int abs( int a) {//计算整数的绝对值 if ( a >= 0 ) return a; return -a; } float fabs( float a) {//计算实数的绝对值,要采用不同的函数名 int main() { int b = -5; float c = -5.3; b = abs(b);//区别对待 c = fabs(c);//麻烦 c = abs(c); //c=? }

函数名重载 C++中允许两个函数使用相同的名字。一个名字,有了多重意义,是为重载。 同一个函数名对应多个版本,C++ 编译器自动选择正确的版本,根据 实参的类型和个数判别 int abs( int a) {//计算整数的绝对值 if ( a >= 0 ) return a; return -a; } float abs( float a) {//计算实数的绝对值,函数名相同,C++允许 int main() { int b = -5; float c = -5.3; b = abs(b); c = abs(c);// c=? }

函数名重载 int f( int );//这样的函数重载不允许 函数返回类型不能作为重载的判别依据,因为函数调用可以忽略返回值,例如: float f( int ); …… int a ; f(a); //错误, C++不能判别哪个函数将被调用

函数参数的默认值 在C++中,如果需要多次用同样的参数值去调用函数,可将此参数值指定为函数参数的默认值,从而不必每次调用时都给出这个参数值。调用时如果没有给定参数值,则使用默认值。 void delay(int loops) { //通过循环而达到等待一段时间 for ( int i = 0; i < loops; i++ ); //的目的,等待时间的长短通过 } //设定循环次数确定 int main() { …… delay(1000);…… }

函数参数的默认值 在对函数进行声明时,C++允许给函数参数设定默认值,如: 在调用时,如果没有提供参数,则使用默认值,如: void delay( int loops = 1000 ); 在调用时,如果没有提供参数,则使用默认值,如: delay();// 即delay(1000 ); 默认参数一般应在函数声明中给出,若没有函数声明,也可以在函数定义中给出。如: void delay(int loops) { //此时,函数定义中不能再有默认值 for ( int i = 0; i < loops; i++ ); } 如果函数中有多个默认参数,必须按照从右向左的顺序定义,如: void func(int a, int b=2, int c=3, int d=4 ); void func(int a=1, int b, int c=3, int d=4 ); //错误 func(10 );// func(10, 2, 3, 4 ) func(10,20 ); // func(10, 20, 3, 4 ) func(10,20,30 ); // func(10, 20, 30, 4 )

函数参数的默认值 函数默认值有时会和函数重载发生冲突,此时编译会出错,应该注意避免。 void func(int, int = 10 ); void func(int a) { ... } void func(int a, int b) { int main() { func( 5 ); //有歧义,可以解释为func(5),也可以解释 } //为func(5,10)

内联函数 函数调用是有代价的,对于程序中的任何一个函数调用,编译程序都要为其生成调用代码和进行参数传递。 有时候一个函数功能非常简单,代码短小,函数体本身的执行代价(时间和空间)还不及执行调用代码和进行参数传递的代价。此时,写成一个函数反而效率不高,不如直接把函数体写在需要调用函数的地方。 使用函数的优点是代码结构清晰。

内联函数 C语言的办法是使用宏定义。例如: 一个程序要反复判断一个字符是否是数字(‘0’-‘9’)。 #include <iostream.h> #define ISNUMBER(x) ( (x >='0' && x <='9') ?1:0 ) void main() { char c; while( ( c=cin.get() )!='\n' ) { if ( ISNUMBER( c ) ) cout << "Number" << endl; else cout << "Other" << endl; }

内联函数 但宏定义不进行类型检查。 float f; ISNUMBER(f); //编译器不会报错 宏也会产生令人厌恶的副作用,而程序员很容易忽视这一点。 #define MAX(a,b) (((a)>=(b)) ? (a):(b)) int x = 1, y = 0, r; r = MAX(x,y); //返回1 r = MAX(++x,y);// 返回3,而不是2 // r = (((++x)>=(y)) ? (++x):(y)) //宏替换是机械替换,不是首先计算参数的值,再进行替换

内联函数 C++使用内联函数,而不使用宏,但同宏一样,对于内联函数,编译器不产生函数调用代码,而是用函数体替代函数调用。 把一个函数指定为内联函数使用保留字inline。例如: inline int isnumber(char c) {//该函数是内联函数 return (c >='0' && c <='9') ?1:0; } 内联函数在替代时和宏的处理不同,要进行类型检查,对于参数要首先进行计算才进行替换。 inline int max(a,b){ return (a>=b) ? a:b; } …… int x = 1, y = 0,r; r = max(x,y); //返回1 r = max(++x,y);// 返回2 // temp = ++x; r = (temp>=y) ? temp:y;

内联函数 可以在函数声明中把函数指定为内联函数,也可以在函数定义时,把函数指定成内联函数。 内联函数应在函数调用以前进行声 明和定义,若在调用后进行定义, 将不会作为内联函数处理。 inline int isnumber(char); void main() { ... if ( isnumber(a)) { } int isnumber(char c) { void main() { //不作为内联函数 ... //对待 if ( isnumber(a)) { ... } inline int isnumber(char c) {

内联函数 并非所有函数都可以指定为内联函数,只有简单的函数才可以指定为内联函数,如果一个函数中含有循环语句,即使指定为内联函数,编译程序也不会作为内联函数对待。 不能把一个递归函数指定成内联函数。 函数实际上是一个地址,因而可以把函数赋给一个函数指针,若某函数被赋给一个函数指针,则该函数也不能指定成内联函数。即使指定,也无效。例如: inline int isnumber(char c); … int (*f)(char c); f = isnumber;

堆区内存的动态分配和回收 在C语言中要动态分配堆区(heap)内存使用malloc(...)函数,回收已经分配的堆区内存使用free(...)函数。(使用包含文件alloc.h) #include <alloc.h> …… int* p = (int*)malloc(sizeof(int)); … free(p); 这两个函数不能用于对象的内存分配,因为为对象分配内存,要调用构造函数,回收内存要调用析构函数。 C++中使用new 和delete,使用new表达式动态分配内存,使用delete表达式回收已经分配的内存。 int* p = new int; … delete p;

堆区内存的动态分配和回收 new表达式自动计算要分配类型的大小,不使用sizeof运算符,省事且可以避免错误。 如果内存分配失败,和malloc(…)一样,new表达式返回 NULL,因此可以通过检查返回值的方式得知内存分配成功与否。 int* p = new int; if ( p == NULL ) { cout << “内存分配失败! “ << endl; exit(1); } new 和 delete 必须搭配使用。用new表达式分配的内存必须用delete表达式回收。

堆区内存的动态分配和回收 new表达式在分配内存的同时,可以对内存进行初始化。例如: int *p; p=new int(100); //动态分配一个整数并初始化 cout << *p << endl; //*p的内容是什么? new表达式也可以同时为多个同类型对象分配内存,此时不能指定初值。例如: int *p; p=new int[10]; //分配一个含有10个整数的整形数组 如果使用new表达式同时为多个对象分配了内存,回收内存时,使用delete表达式中应有[]。例如: int *p; p=new int[10]; //分配一个含有10个整数的整形数组 …… delete[] p;

堆区内存的动态分配和回收 什么是内存泄漏? 程序中动态分配了内存,却没有回收,造成这部分存储空间不能再被利用,称为内存泄漏(memory leak)。 如果程序需要长期运行,内存泄漏问题会耗尽所有内存,从而使程序崩溃。 好的习惯:在所分配的内存不再使用后,及时回收内存。

上机练习内容 进一步熟悉Visual C++ 6.0的使用,学习调试功能。(单步运行程序,设置断点,监视变量内容)。 在机器上练习本节介绍的内容。