118
第第第 C++ 第第

第二章 C++ 概述

  • Upload
    lidia

  • View
    100

  • Download
    5

Embed Size (px)

DESCRIPTION

第二章 C++ 概述. 2.1 C++ 的起源和特点. 2.1.1 C++ 的起源 2.1.2 C++ 的特点: ( 1 ) C++ 保持与 C 兼容,许多 c 程序不经修改就可以被 C++ 所用。 ( 2 )软件的可重用性和可维护性好。 ( 3 )支持面向对象机制,可方便的模拟现实问题的实体。 (4)c++ 编写的程序可读性更好,代码结构更合理。 (5) 程序运行效率更高。. 1. 2.2 C++ 源程序的构成 2.2.1 C++ 程序的一般格式 class student{ - PowerPoint PPT Presentation

Citation preview

Page 1: 第二章  C++ 概述

第二章 C++ 概述

Page 2: 第二章  C++ 概述

2.1.1 C++ 的起源2.1.2 C++ 的特点:( 1 ) C++ 保持与 C 兼容,许多 c 程序不经修改就可以被 C++ 所用。( 2 )软件的可重用性和可维护性好。( 3 )支持面向对象机制,可方便的模拟现实问题的实体。 (4)c++ 编写的程序可读性更好,代码结构更合理。 (5) 程序运行效率更高。

2.1 C++ 的起源和特点

1

Page 3: 第二章  C++ 概述

2.2 C++ 源程序的构成2.2.1 C++ 程序的一般格式class student{ private: int number; char name[10]; int age; float score; public: void printname( ){cout<<name;} void printage( ){cout<<age;} void printheight( ){cout<<score;} };main( )

{ student s1; s1.printname( ); }

4

Page 4: 第二章  C++ 概述

C++ 程序的退化格式说明 C++ 构造的示例程序#include <iostream.h> // 系统头文件int add(int a, int b); // 函数原型的说明int main( ) // 主函数{ int x,y,sum; // 定义三个整型变量 cout<<" 输入二个数 :"<<'\n'; // 界面 : 提示用户输入二个数 cin>>x; // 从键盘输入变量 x 的值 cin>>y; // 从键盘输入变量 y 的值 sum=add(x,y); // 调用函数 add, 将函数返回值赋 sum cout<<" 二数和是 :"<<sum<<'\n'; // 输出 return 0;}int add(int a, int b) // 定义函数 add, 函数 ( 返回 ) 值为整型{ int c; // 定义临时变量 c c=a+b; // 求和 return c; } // 将 c 的值返回 , 通过 add 带回调用处

2

Page 5: 第二章  C++ 概述

2.3 C++ 在非面向对象方面的一些特性2.3.1 注释行/* */ C 的注释 // <CR> C ++ 的注释注意: /*…*/ 方式的注释不能嵌套,/*this is a multiline /*inside of */ here is the end*/ 错误但 // 和 /* */ 方式的注释可以互相嵌套。/*this is a multiline//inside of which here is the end*/

//this is a multiline/*inside of which*/

Page 6: 第二章  C++ 概述

cin 是标准输入流,在程序中代表标准输入设备,即键盘。cin>> 表达式 >> 表达式 int x,y; cin>>x>>y;cout 是标准输出流,在程序中代表标准输出设备,即屏幕。cout<< 表达式 << 表达式 cout<<“the result”<<x<<y;使用 cin 或 cout 进行 I/O 操作时,在程序中必须嵌入头文件

iostream.h// 例 2.2#include <iostream.h>int main( ) { char name[20]; cout<<"Hello, your name:"; cin>>name; cout<<name<<endl; return 0;}

// 例 2.3#include <iostream.h>void main( ) { int x=25;cout<<hex<<x<<‘\n'<<dec<<x<<‘\n‘<<oct<<x<<endl;}

4

2.3.2 新的 I/O 流

Page 7: 第二章  C++ 概述

2.3.3 灵活的局部变量说明int f( ){ int i; int j; i=10; j=25;}

int f( ){ int i; i=10; int j; j=25; for(int k=5;k>=0;k--) ….. …….}以上的写法在 C++ 程序中都是正确的。

Page 8: 第二章  C++ 概述

2.3.4 结构、联合和枚举名可直接作为类型名定义枚举类型名:enum bool {FALSE, TRUE};定义结构类型名:struct student { int sno; char *sneme;};C 语言中定义枚举类型变量: enum bool done;定义结构类型变量: struct student s1, s2;C++ 语言中定义枚举类型变量: bool done;定义结构类型变量: student s1, s2;

Page 9: 第二章  C++ 概述

2.3.5 const 修饰符#define LIMIT 100这里 LIMIT 是一个标志,代表 100

const 类型名 常量名 = 常数;类型名 const 常量名 = 常数;const int LIMIT=100; // const LIMIT=100; int const LIMIT=100;// const LIMIT=100; 这里 LIMIT 是一个常量名,在内存空间放了 100 ,因此有地址,可以用指针指向这空间,但不能修改它。

Page 10: 第二章  C++ 概述

#include <iostream.h>main( ) { int a=1; #define T1 a+a #define T2 T1-T1 cout<<"T2 is "<<T2<<endl; //cout<<“T2 is “<<T1-T1<<endl;//cout<<“T2 is”<<a+a-a+a<<endl; return 0;}

#include <iostream.h>main( ) { int a=1; const T1=a+a; const T2=T1-T1; cout<<"T2 is "<<T2<<endl; return 0;}

8

Page 11: 第二章  C++ 概述

const 可以和指针一起使用,他们的组合可归纳为三种。(1) 可以用一个指向常量的指针变量指向常量: const char *name=“chen”; name[3]=‘a’; // 错误 name=“zhang”;// 正确(2) 指针常量指向变量 char *const name=“chen”; name[3]=‘a’; // 正确 name=“zhang”; // 错误(3) 常指针指向常量 const char *const name =“chen”;

name chen 常量zhang 常量

n

aname chen

zhang常量

a

na

Page 12: 第二章  C++ 概述

说明:( 1) 常量也可以用变量初始化。 const 类型名 常量名 = 变量名; float a=3.4; const float b=a; a=4.5;cout<<b;常量在其有效的范围内不能再赋值。而变量可以多次赋值。( 2 )常量一旦初始化,在其作用域内都不能修改。#include<iostream.h>void f( ){const a=100;cout<<a;}void main( ){float a;a=3.3; cout<<a;f( );}

Page 13: 第二章  C++ 概述

( 3 )常量可以作为函数参数。int f ( const int k) { const int j=k*k; cout<<k; return j; }void main( ){cout<<f(3);}

void t(const int i){

++i; //error}

Page 14: 第二章  C++ 概述

2.3.6 内置函数#include <iostream.h>

int main( ) { for(int i=1;i<=3;i++) cout<<"r="<<i<<" area="<<circle(i)<<endl; return 0;}在函数前加以 inline , 成为内置函数#include <iostream.h>int main( ) 代码嵌入{ for(int i=1;i<=3;i++) cout<<"r="<<i<<" area="<<circle(i)<<endl; return 0;}优点 1 :可以消除函数调用时的系统开销,以提高运行的速度。

float circle(float r) { return 3.1416*r*r; }

inline float circle(float r) { return 3.1416*r*r; }

9

3.1416*r*r

Page 15: 第二章  C++ 概述

// 例 2.7#include <iostream.h>#define doub(x) x*2int main( ) { for(int i=1;i<=3;i++) cout<<doub(i)<<endl; cout<<doub(1+2)<<endl; return 0;}// 例 2.8#include <iostream.h>inline int doub(int x){ return x*2; }int main( ) { for(int i=1;i<=3;i++) cout<<doub(i)<<endl; cout<<doub(1+2)<<endl; return 0;} 优点 2 :可以消除宏定义的不安全性

10

1465

1466

1+2*2

Page 16: 第二章  C++ 概述

注意: ① 内联函数体内一般不能有循环语句和 switch 语句。 ② 内联函数的定义必须出现在第一次被调用之前 .inline float circle(float r) { return 3.1416*r*r; }int main( ) { for(int i=1;i<=3;i++) cout<<"r="<<i<<" area="<<circle(i)<<endl; return 0;} ③ 只有很简单而使用频率很高的函数才被说明为内联函数。

Page 17: 第二章  C++ 概述

2.3.7 函数原型返回类型 函数名(参数表);// 例 2.9#include <iostream.h> void write(char *s); // 函数原型或叫函数申明 void main( ) { write("Hello, world!"); } void write(char *s) 无分号 { cout<<s<<endl; }。。。。。。。。。。。。 #include <iostream.h>

void write(char *s) { cout<<s<<endl; } void main( ) { write("Hello, world!"); }

11

Page 18: 第二章  C++ 概述

说明:( 1 )函数原型的参数表中可不包含参数的名字,而只包含参数的类型,但函数头中必须给出参数的名字。 如: int cal(int ,int); int main( ) { … } int cal(int a,int b) {return a*b;}(2) 如果函数原型中没有任何参数,则 C++假定参数表为空( void)int cal( );等价于 int cal(void);

Page 19: 第二章  C++ 概述

(3) 函数头中没有指出返回类型的函数(包括主函数), C++默认该函数的返回类型为 int 。cal(int a,int b){…} 等价于 int cal(int a,int b){…}main( ){… return 0;}(4) 如果一个函数没有返回值,则必须在函数名前注明返回类型为 void 。void cal( ){cout<<“good”;}void main( ){ }

Page 20: 第二章  C++ 概述

#include <iostream.h>void main(){ int m,n,l,s; int maxj(int a, int b); int minb(int a, int b);

cout<<" 输入 2 个正整数 :"; cin>>m>>n; if (m>0 && n>0) { l=maxj(m,n); s=minb(m,n); cout<<i<<endl; cout<<s<<endl; } else cout<<" 输入了负数 !\n"; return;}

int maxj(int a, int b){ int r,t; if(a<b) {t=a;a=b;b=t;} r=a%b; while(r!=0){

a=b; b=r; r=a%b;

} return b;}//最大公约数int minb(int a, int b){ int r; r=maxj(a,b); if (r!=0) return a*b/r; else

return 0;}//最小公倍数

33

Page 21: 第二章  C++ 概述

2.3.8 带有缺省参数的函数C++ 在说明函数原型时,可以为一个或多个参数指定缺省参数值,以后调用此函数时,若省略其中某一实参, C++自动以缺省值作为相应參数的值。#include<iostream.h>void special(int x=5, float y=5.3);void main( ){special( );// 第一次special(25);// 第二次special(100,79.8);// 第三次}void special(int x,float y){cout<<x*y;}

12

Page 22: 第二章  C++ 概述

#include<iostream.h>void special(int x=5, float y=5.3){cout<<x*y;}

void main( ){special( );special(25);special(100,79.8);}

Page 23: 第二章  C++ 概述

说明 :(1) 所有取缺省值参数都必须出现在不取缺省值参数的右边。 int fun(int i,int j=5, int k); 是错误的 int fun(int i, int k,int j=5); 是正确的 int fun(int i, int k=4,int j=5); 是正确的(2) 调用时,若某个参数省略,则其后的参数皆应省略。int fun(int i=1, int k=4,int j=5){cout<<i*k*j;}fun(2,3);fun(2);

不合法的调用;fun(, 3, 5);fim(, 3);

Page 24: 第二章  C++ 概述

(3) 在相同的作用域内,默认形参值的说明应保持唯一。但如果在不同的作用域内,允许说明不同的默认形参。 add(int x=2,int y=5) ; // 全局默认形参值 void main( ){ add(int x=1,int y=9) ; // 局部默认形参值 add( ) ; // 此处调用时,采用局部默认形参值, x取值 1 , y取值

9}void func( ){add( ) ; // 此处调用时,采用全局默认形参值, x取值 2 , y取值

5} add(int x,int y){cout<<x+y;}

Page 25: 第二章  C++ 概述

2.3.9 函数重载在 C 语言中,函数名必须是唯一的,例如:当要求编写求整数、浮点数和双精度度数的二次方的函数时,必须编写三个函数名不同的函数。int isquare(int i) { return i*i; }float fsquare(float f) { return f*f; }double dsquare(double d) { return d*d; }C++ 中,只要函数的參数的类型不同,或者參数个数不同,或者二兼有之,几个函数可以用相同的函数名 ,称为函数重载 . 使函数方便使用,便于记忆,也使程序设计更加灵活。

13

Page 26: 第二章  C++ 概述

//** 例 2.10 #include <iostream.h>int square(int i) { return i*i; }float square(float f) { return f*f; }double square(double d) { return d*d; }void main( ) { int i=12; float f=3.4; double d=5.67; cout<<i<<'*'<<i<<'='<<square(i)<<endl; cout<<f<<'*'<<f<<'='<<square(f)<<endl; cout<<d<<'*'<<d<<'='<<square(d)<<endl;}

Page 27: 第二章  C++ 概述

//** 例 2.11#include <iostream.h>int mul(int x, int y) { return x*y; }int mul(int x, int y, int z) { return x*y*z; }void main( ) { int a=3,b=4,c=5; cout<<a<<'*'<<b<<'='<<mul(a,b)<<endl; cout<<a<<'*'<<b<<'*'<<c<<'='<<mul(a,b,c)<<endl; }

14

Page 28: 第二章  C++ 概述

说明:(1) 重载函数应在参数个数或参数类型上有所不同,编译才能识别调用哪一个重载版本,即使返回类型不同也不行如: int mul(int x, int y) ; 和 double mul(int x, int y); 是不能重载的。(2) 一般而言,重载函数应对不同的参数情况执行相同的功能。如: abs(int x); 和 abs(float x); 都是求绝对值,一个是整数的绝对值,一个是实数的。(3) 函数的重载与带默认值的函数一起使用时,有可能引起二义性。int mul(int x, int y) { return x*y; }int mul(int x, int y, int z=5) { return x*y*z; }当调用 mul(3,4) 时,编译程序无法确定使用哪个函数。

Page 29: 第二章  C++ 概述

2.3.10 作用域运算符 ::

当全局变量和局部变量同名时,函数中不能使用全局变量。//** 例 2.12#include <iostream.h>int avar=10; // 全局变量void main( ) { int avar=25; // 局部变量 cout<<"avar is "<<avar<<endl; {float avar=4.5; cout<<avar;}

}

15

Page 30: 第二章  C++ 概述

可用作用域运算符 :: //** 例 2.13#include <iostream.h>int avar;void main( ) { int avar; avar=25; // 局部变量 avar ::avar=10; // 全局变量 avar cout<<"local avar = "<<avar<<endl; cout<<"global avar = "<<::avar<<endl;}

Page 31: 第二章  C++ 概述

2.3.11 无名联合C 语言的共用体:union data { int i; char ch; float f;}

共享同一内存地址 , 分配的地址空间的大小是按照最大的来进行分配的 union data a;引用: a.i =3; a.ch =‘k’; a.f =7.9; 等

16

a 4 字节

ich

f

Page 32: 第二章  C++ 概述

无名共用体如下: union { int i; char ch; float f; }  以后在程序中任何地方都可以使用 i,ch,f, 而不需要声明,因为无名共用体已经分配好空间。 #include   <iostream.h> void   main(void)   {  

  union { int i; char ch; float f; };  i  =   12;  

  cout<<i; f=6.5;

cout<<f;   }  

a 4 字节

ich

f

Page 33: 第二章  C++ 概述

2.3.12 强制类型转换隐式类型转换是系统自动实行的转换,主要出现在赋值语句和表达式语句中。int a=3.45;float b=4;double c=a+b;

Page 34: 第二章  C++ 概述

C 语言的强制类型转换 : ( 类型标识符)表达式int i=10;float x=(float)i; int y=(int)(3+6.4)C++ 的强制类型转换:int i=10;float x=float (i);float y=(float) i;两种方法 C++ 都可以。

17

Page 35: 第二章  C++ 概述

• 2.3.13 new 和 delete

• 动态内存分配是相对于静态内存分配而言的。• 静态内存分配是指在编译阶段就分配好存储单元空间,这些空间的大小在程序运行过程中是不可更改的,如变量、数组等; int i;

• 动态内存分配则是指程序员在程序语句中通过调用内存分配函数或使用内存分配运算符取得存储空间,通过动态内存分配得到的空间的大小,编译器是不知道的,完全由动态运行中的程序的当时情况决定。

Page 36: 第二章  C++ 概述

C 语言用函数 malloc( ) 和 free( )动态分配内存和释放动态分配的内存。 C++ 使用运算符 new 和 delete 能更好、更简单地进行内存的分配和释放。 如 C 语言中用: int *p; p=(int *) malloc ( sizeof(int) ); *p=10;

free(p);

p

18

Page 37: 第二章  C++ 概述

而 C++ 语言中 new 运算符用于动态分配一块内存空间。 new 运算符的使用形式如下:指针变量 =new< 数据类型 >[长度 ]char*CBuffer;CBuffer=new char[256];// 分配一个可以容纳 256 个 char 型数据的空间如果分配的空间长度为 1 个单位,则可以省略 new 运算符格式中的中括号和中括号中的整数。float* pNum=new float;与 float* pNum=new float[1];等价。

Page 38: 第二章  C++ 概述

//**2.14#include <iostream.h>void main( ) { int *p; // 定义一个整型指针变量 p p=new int; *p=10; cout<<*p<<endl; delete p; // 释放 p 指的空间 ,撤消指针 p}

Page 39: 第二章  C++ 概述

说明:(1) 使用 new 运算符分配内存空间时,其空间长度可以是变量,也可以是数值表达式。例如: int nSize=5; int* nPInt=new int[nSize+5]; // 分配一个可以容纳 10 个 int 型数据的空间(2) 使用 new 可以为数组动态分配内存空间。 int *pi=new int[10]; int *pi=new int[2][3][4];由 new 分配的内存空间是连续的,可以通过指针的变化访问所分配空间的每一个元素。 int*nPInt=new int[10]; nPInt[5]=100; 或 *(nPInt+5)=100;

19

Page 40: 第二章  C++ 概述

(3)new 可在为简单变量分配内存空间的同时,进行初始化。//** 例 2.15#include <iostream.h>void main( ) { int *p; p=new int(99); //动态分配内存 ,并将 99 作为初始值赋给它 cout<<*p<<endl; delete p;}

Page 41: 第二章  C++ 概述

(4) 由 new 运算符分配的内存空间在使用完毕后,应该使用 delete运算符释放。如果应用程序对有限的内存是只取不还,系统很快就会因为内存枯竭而崩溃。 释放动态分配的数组存储区时,用如下格式: delete 指针 及 delete[ ] 指针 int*pInt=new int; delete pInt; int* pManyInt=new int[10]; delete[ ]pManyInt;

用 new 运算符获得的内存空间,只许使用一次 delete ,不允许多次对同一块空间进行多次释放,否则将会产生严重错误。

Page 42: 第二章  C++ 概述

(5) 使用动态分配内存时,如果没有足够的内存满足分配要求,则分配失败,将返回空指针( NULL )。因此通常要对内存的动态分配是否成功进行检查。 分配内存失败, p=NULL//** 例 2.16#include <iostream.h>void main( ) { int *p; p=new int; if(!p) //if (p==NULL) 若分配内存失败 { cout<<"allocation failure\n"; return ; } *p=20; cout<<*p<<endl; delete p;}

p NULL

20

Page 43: 第二章  C++ 概述

2.3.14 引用引用简单的说就是别名,主要有变量的引用、函数參数的引用、函数返回值的引用。1.引用变量引用变量的声明形式为 < 类型标识符 > &引用名 = 变量名 int someInt ; int& rInt=someInt

21

Page 44: 第二章  C++ 概述

#include<iostream.h>void main( ){ int someInt;

int& rInt=someInt; cout<<&someInt<<“ “<<&rInt<<endl;

someInt=6;cout<<"someInt:"<<someInt<<endl;cout<<"rInt:"<<rInt<<endl;

rInt=7;cout<<"someInt:"<<someInt<<endl;cout<<"rInt:"<<rInt<<endl;

}程序运行结果为0xfff8 0xfff8someInt : 6rInt : 6someInt : 7rInt : 7

6someint

rint

Page 45: 第二章  C++ 概述

(1) 在声明变量的引用时,必须立即对它进行初始化,不能以后再赋值。 int i; int &j; j=i; // 错误 int &j=i;引用的初始值可以为变量,也可以为另一个引用。int i; int &j=i; int &k=j; //i 有两个别名

Page 46: 第二章  C++ 概述

(2) 定义完引用后,每次使用引用,可以直接通过引用名访问变量,而如果用指针,必须通过 * 间接访问变量。 #include <iostream.h>void main( ) { int i=15; // 整型变量 i int *iptr=&i; //iptr 指向 i int &rptr=i; //rptr引用 i cout<<"i is "<<i<<endl; cout<<"*iptr is "<<*iptr<<endl; cout<<"rptr is "<<rptr<<endl; i=29; cout<<" After changing i to 29"<<endl; cout<<"i is "<<i<<endl; cout<<"*iptr is "<<*iptr<<endl; cout<<"rptr is "<<rptr<<endl;}

iptri

rptr

22

Page 47: 第二章  C++ 概述

(3)引用不可重新赋值,不可使其作为另一个变量的别名。int i, k;int &j=i; j=&k; // 错误(4)并不是任何类型的数据都可以引用,下列都是错误的。<1> 不允许对空类型引用 void &a=10; <2> 不能建立引用数组 int a[3]; int &r[3]=a;<3> 不能建立指向引用的指针 , 不能建立引用的引用int a;int &*p=a; int &&r=a;

23

Page 48: 第二章  C++ 概述

(5)当使用取地址运算符时 & ,取的是被引用变量的地址。int num=50;int &ref=num;int *p=&ref;则 p 中保存的是变量 num 的地址。

Page 49: 第二章  C++ 概述

2. 引用作为函数的參数<1> 值传递方式#include <iostream.h>void swap(int m, int n){ int temp; temp=m; m=n; n=temp;}main( ) { int a=5,b=10; cout<<"a="<<a<<" b="<<b<<endl; swap(a,b); cout<<"a="<<a<<" b="<<b<<endl; return 0;}

a=5 b=10a=5 b=10

25

ma

tem

nb

a

b

Page 50: 第二章  C++ 概述

<2> 地址传递调用的方式#include <iostream.h>void swap(int *m, int *n){ int temp; temp=*m; *m=*n; *n=temp;}void main( ) { int a=5,b=10; cout<<"a="<<a<<" b="<<b<<endl; swap(&a,&b); cout<<"a="<<a<<" b="<<b<<endl;}

a=5 b=10a=10 b=5

24

m &aa

temp

n &bb

Page 51: 第二章  C++ 概述

在以数组名作参数时,采取的也是地址传送方式。float fun(float x[4]){float sum=0,aver; for(int i=0;i<4;i++) sum=sum+x[i]; aver=sum/4;}void main( ){float y[4]={3.5, 5.6, 4, 4.7}; float ave=fun(y); return ;}

Page 52: 第二章  C++ 概述

<3>引用传递方式#include <iostream.h>void swap(int &m, int &n){ int temp; temp=m; m=n; n=temp;}main( ) { int a=5,b=10; cout<<"a="<<a<<" b="<<b<<endl; swap(a,b); cout<<"a="<<a<<" b="<<b<<endl; return 0;}

a=5 b=10a=10 b=5

25

ma

temp

nb

Page 53: 第二章  C++ 概述

1 、编写将字符串反序的函数,然后在主函数中调用该函数。2 、编写并验证名为 sphere ( )的函数,使其在给定一个球体的半径 r 之后能返回该球体的体积和表面积。 void sphere(float &a,float &v,float r) a=4*pi*r*r; v=4/3*pi*r*r*r

Page 54: 第二章  C++ 概述

void main(){ char a[255]; cout<<“ 输入字符串 : \n"; gets(a); //cin>>a;? convert(a); cout<<“ 字符串反序为 : \n"; puts(a); return;}

#include <iostream.h>#include<stdio.h>#include <string.h>void convert(char b[]){ int l,i; char c; l=strlen(b); for(i=0; i<=l/2 ;i++){ c=b[i]; b[i]=b[l-i-1]; b[l-i-1]=c;} return ;}

a

b

a[1]a[0]

b[1]b[0]a cb d e f

a[254]

\034

Page 55: 第二章  C++ 概述

#define PI 3.14#include<iostream.h>void sphere(float &a,float &v,float r){a=4*PI*r*r; v=4/3*PI*r*r*r;}void main( ){float rad,area,vol; cin>>r;sphere(area,vol,rad);cout<<area<<endl<<vol<<endl;}

当通过一个函数调用返回多个值时,可以采用引用调用。

Page 56: 第二章  C++ 概述

3 、引用作为返回值   要以引用返回函数值,则函数定义时要按以下格式:类型标识符 & 函数名(形参列表及类型说明)

{ 函数体 }  说明:  ( 1 )以引用返回函数值,定义函数时需要在函数名前加 &  ( 2 )用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。

Page 57: 第二章  C++ 概述

• double temp;double f1(double a){ temp=a*a; return temp;} double &f2(double a){ temp=a*a; return temp;}第一种情况是普通的返回方式,函数 f1 返回全局变量 temp, 是先将 temp 的值赋值给那个无名临时变量(该无名临时变量有return 语句产生),回到主函数后,赋值语句再把临时变量的值赋给所要的,无名临时变量生命期结束。第二种情况是引用返回方式,没有使用那个无名临时变量过渡,而是直接返回 temp本身,赋给所要的。无名临时变量中放的是temp 的地址。不产生拷贝,提高了效率。

void main( )

{double b1=f1(3.4);

double b2=f2(3.4);

}

Page 58: 第二章  C++ 概述

引用作为返回值函数可返回一个引用,其目的是可将函数用在赋值运算符的左边。#include <iostream.h>int a[]={1,3,5,7,9};int &index(int); //声明返回引用的函数void main( ){ index(2)=25; // 将 a[2] 重新赋值为 25for(int i=0;i<5;i++) cout<<a[i]<<endl;}int &index(int i){ return a[i]; }说明:不要返回对该函数内的局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成了“无所指”的引用,程序会进入未知状态。 int &f( ){int a=1;return a;}

26

int &f(int a ){…return a;}

Page 59: 第二章  C++ 概述

引用作为返回值,有以下好处: · 函数返回的是所返回的变量或对象本身,而不需要建立临时的对象。这样减少 了程序运行的开销; · 返回一个引用使得一个函数调用的表达式可以成为一个左值表达式,可以为其 赋值。

Page 60: 第二章  C++ 概述

4. 引用举例#include <iostream.h>int &max(int &num1, int &num2);int &min(int &num1, int &num2);void main( ){ int num1, num2;cin>>num1>>num2; max(num1,num2)=0; cout<<"\n把大的数置成 0 后 , 这两个数是 :"; cout<<'\n'<<num1<<" 和 "<<num2<<'\n'; cout<<"\n 再一次输入二个数 :\n"; cout<<" 输入第一个数 :"; cin>>num1; cout<<" 输入第二个数 :"; cin>>num2;min(num1,num2)=0;cout<<"\n把小的数置成 0 后 , 这两个数是 :”;cout<<'\n'<<num1<<" 和 "<<num2<<'\n’;} 2

7

Page 61: 第二章  C++ 概述

int &max(int &num1, int &num2) //两数中找大数{ return (num1>num2)?num1:num2; }int &min(int &num1, int &num2) //两数中找小数{ return (num1<num2)?num1:num2; }运行结果:45 78把大的数置成 0 后 , 这两个数是 : 45 和 0 再一次输入二个数 :输入第一个数 : 13输入第二个数 : 56把小的数置成 0 后 , 这两个数是 :0 和 56

28

Page 62: 第二章  C++ 概述

1 、指针的概念2 、指针型变量的声明 < 类型标识符 >* 指针变量名 int *p;//p 是用来保存一个指向 int 型变量的地址的指针型变量char*pp[5];// 用来保存 5 个指向 char 型变量的指针的指针型变量数组3 、指针的基本操作 与指针有关的基本运算符有以下两个 (1)& 变量名。“&” 为取地址运算符,用来获取变量的首地址。 int i=5 , *phint; phint=&i: (2)* 指针变量名。“ *” 为指向运算符,用来获取指针变量所指向变量的值。 i=*phint;

Page 63: 第二章  C++ 概述

指针变量的使用例题。#include<iostream.h>void main(){ int m,n,*p1=&m,*p2=&n,*phint=NULL;

m=n=6;cout<<"*p1="<<*p1<<" , *p2="<<*p2<<endl;cout<<"p1="<<p1<<" , p2="<<p2<<endl;cout<<"m="<<m<<" , n="<<n<<endl;cout<<"phint="<<phint<<endl;

*p1+=3;p2=p1;*p2*=4;phint=p2;cout<<"*p1="<<*p1<<" , *p2="<<*p2<<endl;cout<<"p1="<<p1<<" , p2="<<p2<<endl;cout<<"m="<<m<<" , n="<<n<<endl;cout<<"phint="<<phint<<endl;

} //假设 &m=0x0012FF7C , &n=0x0012FF78

Page 64: 第二章  C++ 概述

程序运行结果为*p1=6 , *p2=6p1=0x0012FF7C , p2=0x0012FF78m=6 , n=6pjint=0x00000000*p1=36 , *p2=36p1=0x0012FF7C , p2=0x0012FF7Cm=36 , n=6pjint=0x0012FF7C

Page 65: 第二章  C++ 概述

4 、指针的运算 对指针也可以进行赋值、算术和关系运算。( 1 )指针的赋值运算对于普通变量的赋值运算,即使变量类型与值的类型不同,赋值运算也是允许的,只不过这种赋值会遵循某些转换规则进行。int n; char Ch='A'; n=Ch;而指针型变量在赋值时,决不允许将与指针型变量类型不同的指针值赋予指针变量。 int* pnValue; char byCh='A'; pnVaIue=&byCb; 是不允许的,因为 &byCh 的类型是 char* ,而 pnValue的类型是 int* 。但 int* pnVa1ue; char byCh='A' ;

pnValue=(int*)&byCh;是可以的

Page 66: 第二章  C++ 概述

( 2 )对于非 void* 型的指针型变量,只能进行加一个整数、减一个整数和两个指针变量相减三种运算。 void*型指针变量不能做任何算术运算。int nValue; int*p1=&nValue; p1=p1+1; //p1++; 假设 p1 的初始地址是 2000 ,则进行

p1=p1+1; 运算后, p1 的地址值是 2002.int *p1, *p2;//p1 p2 值分别为 2000 2006p2-p1=3

Page 67: 第二章  C++ 概述

( 3 )指针间也可以进行关系运算。关系运算符> 、 < 、 = 、 >= 、 <= 、 != 可以用来连接两个指针型变量做关系运算。指针间的关系运算结果就是两个指针所指的地址值的大小的关系运算结果。两个进行关系运算的指针一般要求是同一类型的指针。

Page 68: 第二章  C++ 概述

2.3.15void 型指针void 指针是一个特殊指针,可以说是任意指针,因为任何类型的指针值都可以赋给 void 类型的指针 void main( ) { void *vp; int i=5; float f=7.8; char c='A'; int *ip; float *fp; char *cp; ip=&i; vp=&i; cp=&c; vp=&c; fp=&f; vp=&f; vp=ip; vp=fp; vp=cp; ip=vp; cp=vp; fp=vp; // 错误 }

Page 69: 第二章  C++ 概述

void   指针是空类型指针 , 它不指向任何类型 , 只是一个地址 .当进行自增运算或取指针指向的值时就会出错,空指针也不能用 --->运算符号。要想使用指向操作必须进行显示类型转换。 void main( ){ float b=3.4;  

  void  * p=&b;     p++ ; //error;

(float*)p++;  //error  *p=20.5   //error;       *(float *)p=20.5;  int   a=1;     int *ps=&a;     p=ps ; ps=p; //error     ps=(int*)p;

}

Page 70: 第二章  C++ 概述

通过指针引用数组元素 由于指针同数组的特殊关系,数组与指针几乎可以互换使用。下面利用一个具体例子来说明通过指针引用数组元素的方法。 用指针的方法编写求一个数组中所有元素之和的程序。

Page 71: 第二章  C++ 概述

#include<iostream.h>void main( )

{ int Array[10]={6,7,8,9,5,4,3,2,10,1};int sum=0 , *p=Array;for(i=0;i<10;i++)

sum=sum+(*p++); //sum=sum+*p; p++;

cout<<" 数组各元素和 :sum1="<<sum<<endl;}

Page 72: 第二章  C++ 概述

指针和函数指针变量可以作函数的参数,指针也可作函数的返回值,还有一种指针可以用来指向函数

Page 73: 第二章  C++ 概述

指向函数的指针 1.指向函数指针变量的定义与使用 同数据一样,程序也保存在内存中,函数在内存中的起始地址称为入口地址,在调用函数时,只需知道被调函数的入口地址,即函数的指针就可以调用函数。函数名就是一个指针,它指向函数的入口,我们可以定义一个指针变量,并赋予它函数名值,这样的指针变量成为指向函数的指针变量。 声明一个函数指针变量的形式如下 : < 类型标识符 >(* 函数指针变量名 )( 参数表 ) 注意,定义中的两对圆括号都不要遗漏,数据类型是函数指针变量所指函数的返回值的数据类型。

Page 74: 第二章  C++ 概述

例如,若定义函数 void FunctionA(int m,int n); 则对应于函数 FunctionA 的指针型变量可以按如下方法声明 : void(*pFPointer)(int,int); 要用已经定义的函数指针变量来调用函数,需要分两步进行。 第一步:将函数名赋给已定义的函数指针变量。采用的格式为 函数指针变量名 = 函数名

Page 75: 第二章  C++ 概述

例如,可以将 FunctionA 的入口地址值赋予 pFPointer 这个函数指针变量 :

pFpointer=FunctionA; 第二步:使用函数指针变量调用它所指的函数。采用的格式为 (* 函数指针变量名 )( 实参表 ) 或 函数指针变量名 ( 实参表 ) 事实上,由于 pFPointer 和 FunctionA指 向同一 函 数 入口, 除 了 可 以 使 用 函 数 名

FunctionA 调用函数外,当然可以使用函数指针 pFPointer 调用函数。例如:

FunctionA(3,4) 等价于 (*pFPointer)(3,4); 或 pFPointer(3,4);

Page 76: 第二章  C++ 概述

#include<iostream.h>void FunctionA(int m,int n){cout<<m*n;}void main( ){void(*p)(int,int);p=FunctionA;(*p)(3,4);//p(3,4)}

Page 77: 第二章  C++ 概述

2.函数指针变量作为函数的参数 函数指针变量的一个主要用途是在函数调用时把函数指针变量作为参数,也就是说传递的不是数值,而是函数的入口地址,目的是实现对若干个不同函数的灵活调用。具体编程时要注意的是:主调函数的实参应设置成将被调用的函数名,被调函数的相应形参应设置成接受同类型函数入口地址的函数指针变量。

Page 78: 第二章  C++ 概述

#include<iostream.h>

int add(int x,int y)

{ return x+y;}

int sub(int x,int y)

{ return x-y;}

int funct(int(*fun)(int,int),int x,int y)

{ int result;

result=(*fun)(x,y);

//等价于 result=fun(x,y);

return result;

}

void main( )

{ int a=5,b=10;

cin>>a>>b;

cout<<"a+b="<<

funct(add,a,b)<<endl;

cout<<"a-b="<<

funct(sub,a,b)<<endl;

}

Page 79: 第二章  C++ 概述

指针作为函数的返回类型 如前所述,函数的数据类型是指函数返回值的类型,它可以是整型、字符型、浮点型或

void( 无返回值 ) ,也可以是指针类型,即函数的返回值是地址。返回值是地址的函数称为指针函数,其定义的一般形式如下: < 类型标识符 >* 函数名 (形参表 ) { 函数体 }

Page 80: 第二章  C++ 概述

例如: int*ip;

int*fFun1(int x)

{

...

return ip;

}

其中 fFun1 是函数名,前面的“ *” 表示 fFun1是一个指针函数 ( 注意与函数指针的区别 ) ,它的返回值是一个 int 类型的地址。与此相匹配的是,在函数体内 return 语句中的 ip 也必须是指向 int 型的指针变量。

Page 81: 第二章  C++ 概述

C++ 函数的返回类型,可以是除数组和函数外的任何类型包括指针【例 】 指针作为函数的返回值的例子 先问用户要输入多少个实数,然后分配一存储空间保存输入的这些实数,并把指向这空间的指针返回给用户。 #include <iostream.h> float *input(int& n); void main( ){ int num; float *P; P = input(num); if(P) { for(int i=0; i<num; i++) cout<<P[i]<<" "; delete P; } }

float *input(int& n) { int num; cout<<“要输入多少个实数 :”; cin >> num; if(num<=0) return NULL; float *buf=new float[num]; if(buf==NULL) return; n = num; for(int i=0; i<num; i++) cin>>buf[i]; return buf; }

55

Page 82: 第二章  C++ 概述

1 、写一个函数,找出从键盘输入的字符串中大写字母字符(即’ A’-‘Z’ 这 26 个字母)的个数(如字符串” China Computer Wrold” 中大写字母字符的个数为 3 个)。 函数的原型: int CalcCapital (char *str); 函数参数: str 为所要处理的字符串; 函数返回值: 所给字符串中数字字符的个数

Page 83: 第二章  C++ 概述

int CalcCapital (char *str){ if (str == NULL) return 0; //判断字符指针是否为空  int num = 0; //记录大写字母字符个数的变量,初值为 0  for(int i=0; str[i] != ‘\0’; i++) if (str[i] <= 'A' && str[i] >= 'Z') num++; //若是大写字母,则总数加 1  return num; // 返回大写字母字符数}#include<iostream.h>void main( ){char s[20]; cin.getline(s,20);cout<< CalcCapital(s);}

Page 84: 第二章  C++ 概述

2.下列各项中不符合函数重载必须满足的条件的是 ( )     A. 必须有不同的参数个数   B.对应的参数类型必须不相同   C. A 和 B 必须同时满足   D . A 和 B 只要满足一个即可3.下列带缺省值参数的函数说明中,正确的说明是 ( )      A . int Fun(int x,int y=2,int z=3);   B . int Fun(int x=1,int y,int z=3);   C. int Fun(int x,int y=2,int z);   D . int Fun(int x=1,int y=3,int z);

Page 85: 第二章  C++ 概述

4 为了提高程序的运行速度,可将不太复杂的功能用函数实现,此函数应选择 。 A.内联函数 B. 重载函数 C.递归函数 D. 函数模板 5 . 函数原型语句正确的是 。 A. int Function(void a); B.void Function (int); C. int Function(a); D.void int(double a); 6. C++ 中函数返回值的类型是由 决定的。 A. return 语句中表达式的类型 B.该函数定义时的类型 C. 调用函数时的调用语句 D. 系统根据结果 7. 以下函数的返回结果是 。 int function(char * x) { char *p = x; while (*p++); return (p-x-1); } A. 求字符串的长度 B. 将字符串 x连接到字符串 p后面 C. 将字符串 x复制到字符串 p 中 D. 将字符串 x反向存放

Page 86: 第二章  C++ 概述

8. 函数调用 func((exp1,exp2),(exp3,exp4,exp5)) 中所含实参的个数为 个。 A. 1 B. 2 C. 4 D. 5

9. 以下正确的函数原型语句是 。 A. double fun(int x , int y) B. double fun(int x ; int y) C. double fun(int , int); D. double fun(int x , y);

10. 面向对象方法的多态性是指 。 A. 一个类可以派生出多个特殊类 B. 一个对象在不同的运行环境中可以有不同的变体 C. 针对一消息,不同的对象可以以适合自身的方式加以响应。 D. 一个对象可以是由多个其他对象组合而成的

Page 87: 第二章  C++ 概述

11. 所谓数据封装就是将一组数据和与这组数据有关操作组装在一起,形成一个实体,这实体也就是 ( )  A.  类 B.  对象 C.  函数体 D.  数据块

12. 在 ( ) 情况下适宜采用 inline  定义内联函数。 A.  函数体含有循环语句 B.  函数体含有递归语句 C.  函数代码少、频繁调用 D.  函数代码多、不常调用

13  在 C++  中,数据封装要解决的问题是 ( )  。 A.  数据规范化排列 B.  数据高速转换 C. 避免数据丢失 D.  保证数据完整性

14. 所谓多态性是指 (      )A. 不同的对象调用不同名称的函数

B. 不同的对象调用相同名称的函数C. 一个对象调用不同名称的函数

  D. 一个对象调用不同名称的对象

Page 88: 第二章  C++ 概述

写出运行结果 # include <iostream.h>const int N = 5;void fun( );void main( ) {

for (int i=1; i<N; i++)fun( );

}void fun( ){

static int a;int b=2;cout <<(a += 3 , a+b)<<" ";

}

Page 89: 第二章  C++ 概述

5 8 11 14

Page 90: 第二章  C++ 概述

2.5 基本运算符和表达式2.5.1 关系运算符2.5.2 算术运算符2.5.3 逻辑运算符2.5.4 位运算符2.5.5 条件运算符2.5.6 逗号表达式2.5.7sizeof 运算符2.6 赋值及运算顺序2.7 类型转换

30

Page 91: 第二章  C++ 概述

2.8 语句2.8.1 表达式语句、空语句和块语句2.8.2 选择语句 1. if 语句 2. switch 语句2.8.3 循环 1. while 语句 2. do while 语句 3. for 语句2.8.4 转移 1. break 与 continue 语句 2. goto 语句2.8.5 return 语句

31

Page 92: 第二章  C++ 概述

2.9 函数2.9.1 函数的基础知识 函数先声明再调用后定义的例子 #include <iostream.h> void main( ) { int a,b,c; int sum(int, int); //先申明 sum() 函数 a=25; b=36; c=sum(a,b); // 调用 sum() 函数 cout << c << endl; } int sum(int x, int y) // 定义 sum() 函数 { int temp; temp=x+y; return temp; }

32

Page 93: 第二章  C++ 概述

//习题 函数 (7.1)#include <stdio.h>void main(){ int m,n,l,s; int maxj(int a, int b); int minb(int a, int b); printf(" 输入个正整数 :"); scanf("%d,%d",&m,&n); if (m>0 && n>0) { l=maxj(m,n); s=minb(m,n); printf("%d 和 %d 的最大公约数为 %d\n",m,n,l); printf("%d 和 %d 的最小公倍数为 %d\n",m,n,s); } else printf(" 输入了负数 !\n"); return;}

int maxj(int a, int b){ int r,t; if(a<b) {t=a;a=b;b=t;} r=a%b; while(r!=0){

a=b; b=r; r=a%b;

} return b;}

int minb(int a, int b){ int r; r=maxj(a,b); if (r!=0) return a*b/r; else

return 0;}

sln 78m 56

t

rb 78a 56

rb 78a 56

33

Page 94: 第二章  C++ 概述

//习题 函数 (7.5)#include <iostream.h>#include <stdio.h>#include <string.h>void main(){ char a[255]; void convert(char b[]); printf("请输入一个字符串 : \n"); gets(a); convert(a); printf("该字符串反序为 : \n"); puts(a); return;}

void convert(char b[]){ int l,i; char c; l=strlen(b); for(i=0; i<=l/2 ;i++){ c=b[i]; b[i]=b[l-i-1]; b[l-i-1]=c;} return ;} c

a

b

a[1]a[0]

b[1]b[0]a cb d e f

a[254]

\0

34

Page 95: 第二章  C++ 概述

m#include <stdio.h>#include <math.h>void main(){ float a,b,c,d,x[2]; void root0(float a, float b, float c, float d,float x[]); void root1(float a, float b, float c,float x[]); void root2(float a, float b, float c, float d, float x[]); printf("请输入一元二次方程的三个系数 a,b,c:\n"); scanf("%f,%f,%f",&a,&b,&c); if(a<=1e-6) printf(" 不是一元二次方程 !\n"); else { printf(" 方程 (%4.1f)x*x+(%4.1f)x+(%4.1f)=0\n",a,b,c); d=b*b-4*a*c; if (d<0){ root0(a,b,c,d,x); printf("由于 b*b-4*a*c<0 因此有二个虚根 :\n"); printf("x1 = %f + %f i\n",x[0],x[1]); printf("x2 = %f - %f i\n", x[0],x[1]); } else if(d==0){ root1(a,b,c,x); printf("由于 b*b-4*a*c=0 因此有一个重根 :\n"); printf("x1 = %f \n",x[0]); printf("x2 = %f \n",x[1]); }

x[1]x[0]

35

Page 96: 第二章  C++ 概述

void root2(float a, float b, float c, float d,float x[]){ float r, i; r=-b/(2*a); i=sqrt(d)/(2*a); x[0]=r-i; x[1]=r+i;}

void root1(float a, float b, float c,float x[]){ x[0]=x[1]==-b/(2*a);}

void root0(float a, float b, float c, float d,float x[]){ x[0]=-b/(2*a); x[1]=sqrt(-d)/(2*a);}

else{ root2(a,b,c,d,x); printf("由于 b*b-4*a*c>0 因此有二个实根 :\n"); printf("x1 = %f \n",x1); printf("x2 = %f \n",x2); } } return;}

36

Page 97: 第二章  C++ 概述

2.9.2 参数传递及函数返回值 (1) 值传 一般变量 (2) 传地址 结构 , 数组 (3) 传引用 一般变量 , 结构 , 数组 缺省参数2.9.3 使用 C++ 系统函数

37

Page 98: 第二章  C++ 概述

2.10 数组定义 类型 数组名 [大小 ]; int a[4;]; int b[3][4]; int c[2][3][4];使用时数组元素 数组名 [ 表达式 ] a[0]=10; i=3; a[i]=5; b[0][3]=20; 初始值 定义时 int a[]={2,4,6,8,10}; int b[][3]={{2,4,6},{8,10,12}};

38

Page 99: 第二章  C++ 概述

2.11 指针定义 类型 * 指针变量名 ;2.11.1 使用指针 取地址运算符 & 取内容运算符 * 位移取值 [ ] #include <iostream.h> void main( ) { int a[10]={2,4,6,8,10}; for(int *p=a;p<a+10;p++) cout << p[+0] <<endl; }这里 p[+0] 位移 +0 ,等价于 *p p=a; p[+2] 即 *(p+2) p[-i] 即 *(p-i)

39

Page 100: 第二章  C++ 概述

2.11.2 指针运算1. 赋值 int x,*px,*q; px=&x; q=px; 表示 q 和 px 同指一个地方 (q跟着 px 指 )2. 比较 px= =q q!=px 判断 q 和 px 是否同指一个地方 p < q 判断 p 和 q 指在数组元素的前后3. 移动指针 p=p+3; ++ -- 运算 y=*px++; //y=*(px++); y=*++px; //y=*(++px); y=++*px; //y=++(*px); y=(*px)++;

40

Page 101: 第二章  C++ 概述

2.11.3 指针和数组1. 指向一维数组的指针 int a[4], *p; p=a; 或 p=&a[0]; 即 p 指向 a[0]; 2. 指针数组 许多个指针变量在一起都可用来指向整数 int *pa[2]; char *pc[5][7]; 例 #include <iostream.h> void main( ) { int a[2][3]={{2,4,6},{8,10,12}}; int *pa[2]; // 有二个指针 pa[0] 和 pa[1] pa[0]=a[0]; pa[1]=a[1]; for (int i=0; i<2; i++) for(int j=0; j<3; j++,pa[i]++) cout << "a["<<i<<"]["<<j<<"]=” <<*pa[i]<<endl; }

41

Page 102: 第二章  C++ 概述

3. 指向整个数组的指针 ( 行指针 ) 如: int (*a)[5]; int b[2][5]={0,1,2,3,4,5,6,7,8,9} a=b; a b 0 1 2 3 4 5 6 7 8 9 #include <iostream.h> void main( ) { int (*a)[5]; int b[2][5]={0,1,2,3,4,5,6,7,8,9}; a=b; for(int i=0;i<5;i++) cout << i <<":"<< *(*a+i)<<endl; a++; for(int i=0;i<5;i++) cout << i <<":"<< *(*a+i)<<endl; }

42

Page 103: 第二章  C++ 概述

一维数组的地址 int a[4];

a+0 是第 0 列的地址 a+i 是第 i 列的地址 *( a+0) 是第 0 列的数据 *(a+i) 是第 i 列的数据

地址 a 数据 *a &a[0] a[0]

一维数组的指针 int a[4], *p; p=a;

可以 p++

指针 p 数据 *p a[0]

43

Page 104: 第二章  C++ 概述

二维数组的地址 *a a[0] int a[3][4]; *(a+i)+j 是第 i 行第 j 列地址

*(*(a+i)+j)

a+0 是第 0 行的地址 ………. a+i 是第 i 行的地址 *( a+0) 是第 0 行第 0 列的地址…… ..*(a+0)+j 是第 0 行第 j 列的地址 *(a+i) 是第 i 行第 0 列的地址 …… ... *(a+i)+j 是第 i 行第 j 列的地址 *(*(a+0)+0) 是第 0 行第 0列的数据 ..(*(a+0)+j) 是第 0 行第 j列的数据 *(*(a+i)+0) 是第 i 行第 0列的数据… .*(*(a+i)+j) 是第 i 行第 j列的数据

行地址 a+0

列地址 *(a+0)

行地址 a+i

44

Page 105: 第二章  C++ 概述

二维数组的指针 *a a[0] int a[3][4]; (p+i*4+j) 是第 i 行第 j 列地址 (1) int *p;( 小指针 ) p=*a;∨ p=a; ㄨ p=a[0]; ∨ *(p+i*4+j) p=&a[0][0]; ∨ 元素地址 : p=*a+j; p+j p++; 元素数据 : *p *(p+j) p[j]

*( a+0) 是第 0 行第 0 列的地址…… ..*(a+0)+j 是第 0 行第 j 列的地址 *(a+i) 是第 i 行第 0 列的地址 …… ... *(a+i)+j 是第 i 行第 j 列的地址 *(*(a+0)+0) 是第 0 行第 0列的数据 ..(*(a+0)+j) 是第 0 行第 j列的数据 *(*(a+i)+0) 是第 i 行第 0列的数据… .*(*(a+i)+j) 是第 i 行第 j列的数据 p 当一维数组名用但可 p=p+i p++ 走 (i) 一行 元素地址 : *p+j 数据 : *(*p+j) (*p)[j]

列地址 *(a+0)

45

Page 106: 第二章  C++ 概述

struct student { int num; float score; struct student *next};struct student *p;

nextnum score

结点

#include <stdlib.h>

申请空间函数: malloc( 字节数 )测试字节运算符: sizeof( 类型 )p=(struct student * )malloc(sizeof(struct student)) ;

释放空间函数: free( 指针); free( p );

nextnum score

结点p

46

Page 107: 第二章  C++ 概述

p1=p2=(struct student * )malloc(LEN) ;

scanf(“%d,%f”,&p1->num,&p1->score) ;

nextnum score

结点p1 p2

20101 89.5

head NULL

n= 0 1

head=p1 ;

headnextnum score

p1

p1=(struct student * )malloc(LEN) ;

20103 90

2

(n=2) p2->next=p1;p2=p1 ;

p2

scanf(“%d,%f”,&p1->num,&p1->score);

nextnum score

p1

0

NULL

p1->num==0

47

Page 108: 第二章  C++ 概述

p p01 03 07 08 11 NU

LLhead

p1

p2

p1p2

01 03 07 08 11 NULL

head

p0

05

p1

p

01 03 08 11head NULL

p1p

2

48

Page 109: 第二章  C++ 概述

2.11.4 引用 引用可为变量起别名,它主要用作函数参数以及函数的返回类型。有参数引用和返回值引用。 1. 引用说明 int num=50; int& ref=num; 表示放整数 50 的内存空间 可叫 num ,又可叫 ref 引用实质上是为另一个变量建立别名。 2. 引用参数 (传引用 )

49

Page 110: 第二章  C++ 概述

3. 返回引用的函数当一个函数的返回值需重新赋值的时候,我们也可对返回值进行引用,这时函数可出现在赋值号的左边。这种函数称为返回引用的函数。 形式 类型 & 函数名 ( 参数 )#include <iostream.h> int a[]={2,4,6,8,10,12}; int& index(int i); void main( ) { index(3)=16; //index(3) 即返回值 a[i],i=3,a[3] 改为 16 cout<<index(3)<<endl; cout <<a[3]<<endl; } int& index(int i) { return a[i]; }注意 : 返回值是函数内的局部变量时不能引用 5

0

Page 111: 第二章  C++ 概述

例#include <iostream.h>int e(int i){ return i+1; }

int &f(){ int i=1; return ++i;}

int g(int &i){ i=i+1; return i;}

main(){ int r1=e(3); int &r2=e(4); int r3=f(); int &r4=f(); int a=0,b=0,c=0,d; d=g(4); a+=g(g(c)); b+=g(e(3)); return 1;}

51

Page 112: 第二章  C++ 概述

2.11.5 void 类型指针 void 指针是一个特殊指针,它可以指向任一类型的 C++ 对象。 void main() { void *vp; int i=5; floatf=7.8; char c='A'; int *ip; float *fp; char *cp; ip=&i; vp=&i; cp=&c; vp=&c; fp=&f; vp=&f; vp=ip; vp=fp; vp=cp; ip=vp; cp=vp; fp=vp; // 错误 }

52

Page 113: 第二章  C++ 概述

2.12 类型定义 typedef 类型名 标识符2.13 指针和动态内存分配 C++ 的基本操作符 new 和 delete 分配内存 : 指针变量名 =new 类型 [大小 ]; int *ip; ip=new int[5]; 释放内存 delete ip;

53

Page 114: 第二章  C++ 概述

2.14 指针和函数 指针变量可以作函数的参数,指针也可作函数的返回值,还有一种指针可以用来指向函数2.14.1 指针作为函数的参数 函数中的形参,可以是指针变量。这时实参可以是地址或指针来调用它 【例 】 指针作为参数的例子 #include <iostream.h> void main( ) { int a[15]; void input(int *s, int n); input(a,15); for(int i=0; i<15; i++) cout<<a[i]<<endl; }

void input(int *s, int n){ cout<<“请输入” <<n<<“ 个整数 :”<<endl; for(int i=0; i<n; i++) cin>>s[i]; // 或 cin>>*s++;}

54

Page 115: 第二章  C++ 概述

2.14.2 返回指针的函数 C++ 函数的返回类型,可以是除数组和函数外的任何类型包括指针【例 】 指针作为函数的返回值的例子 先问用户要输入多少个实数,然后分配一存储空间保存输入的这些实数,并把指向这空间的指针返回给用户。 #include <iostream.h> float *input(int& n); void main( ) { int num; float *data; data = input(num); if(data) { for(int i=0; i<num; i++) cout<<data[i]<<" "; delete data; } }

float *input(int& n) { int num; cout<<“要输入多少个实数 :”; cin << num; if(num<=0) return 0; float *buf=new float[num]; if(buf==0) return; n = num; for(int i=0; i<num; i++) cin>>buf[i]; return buf; }

55

Page 116: 第二章  C++ 概述

2.14.3 指向函数的指针变量 C++ 中函数也有地址,也可以用指针指向它。 这种指针的定义方法 : int (*funp)(int a, int b); 表示 funp 是指针,可以用来指向带有两个 int 类型参数的函数,这个函数的返回值是 int 函数 int fun(int a, int b) { ..........… } funp=fun; funp 指向函数 fun 可以用这种指针调用函数 result=(*funp)(5,10); 或 result=fnup(5,10);

56

Page 117: 第二章  C++ 概述

在 C++ 中,字符串被定义为以 '\0' 结束的字符数组。 char str[7]={'s','t','r','i','n','g','\0'}; char str[7]="string"; char *ps="string"; 或分成 char *ps; ps="string"; 但数组不能分成 char str[7]; str="string"; // 错误 串可以作为一个整体输入输出 : #include <iostream.h> void main( ) { char str[]="请输入一个字符串 :"; char entstr[25]; cout << str; cin >> entstr; cout << "\n您输入的字符串是 :" << entstr; } 5

7

Page 118: 第二章  C++ 概述

习题2.12.32.72.82.9

58