第一章 c++的初步知识
1.1 C++对c增强
- 对c功能做了补充
- 增加面向对象的机制
1.2 C++程序分析
- main前面的int的作用是声明函数类型为整型
- cout实际上为输出流对象
- 函数体由大括号{ }括起来的
- #include是预处理命令,它将iostream内容包含到该命令所在的程序文件中
- “<<”是插入运算符,输出的队列也叫输出流
“>>”是提取运算符 - class Student --声明类
{private: --以下为私有变量
int num;
int score;
public: --以下为公有变量
void setdata()
{cin>>num;
cin>>score;}
void display()
{cout<<num<<endl;}
}
Student stud1,stud2; --stud1和stud2都是对象
1.3 c++程序构成和书写形式
- 一个c++程序由单个或多个程序单位构成
- 一个程序单位包括 ①预处理命令②全局声明部分③函数
- 一个函数包括①函数定义②函数体{包括声明部分和执行部分}
- 语句 :①声明语句 ②执行语句
- 一个c++程序总是从main函数开始执行的
1.4 c++编译到运行结果步骤
-
编写程序
-
编译:①内容:把源程序翻译成二进制形式的“目标程序”
②作用:对源程序进行词法检查和语法检查 -
将目标程序连接
-
运行程序
-
分析运行结果
第二章 数据存储、表示和计算
2.1 c++的数据类型
类型名 | 符号 | 数量级 | 字节数 |
---|---|---|---|
整型 | int | -232~232-1 | 4 |
短整型 | short int | -215~215-1 | 2 |
长整型 | long int | -232~232-1 | 4 |
无符号 | unsigned | 双倍整且正数 | 保持 |
字符型 | char | -28~28-1 | 1 |
单精度 | float | 3.410-38~3.41038 | 4 |
双精度 | double | 1.710-308~1.710308 | 8 |
长双精度 | long double | 1.710-308~1.710308 | 8 |
2.2常量
2.2.1 常量分类
- 数值型常量
- 字符型常量
2.2.2 数值常量
-
整型常量的类型
非负值整数可以赋值给unsigned型变量
-十进制整数。整常量后加一个l或者L表示为长整
-八进制整数。常熟开头加一个数字0
-十六进制整数。常熟开头加一0和英文字母x -
浮点数表示方法
①十进制小数形式
-单精度浮点数:后加F或f,4字节
-长双精度数:后加l或L,12字节
-双精度:8字节
②指数形式:3.14159——————>0.314159e10
2.2.3 字符常量
-
普通的字符常量:单引号括起来的一个字符
①只包括一个字符
②区分大小写
③‘ 是定界符 -
转义字符常量 p22
-
字符数据存储形式:存放ASCLL对应的二进制形式
-
字符串常量:双引号括起来的多个字符
2.2.4 符号常量
用一个符号名代表一个常量,称为符号常量,即以标识符出现的常量
#define PRICE 30 //给PRICE符号常量赋值30,该语句后不加分号
使用符号常量的好处:
①含义清楚。在规范程序中不提倡用很多直接常量
②在需要改一个常量的时候做到“一改全改”
2.3 变量
2.3.1 变量的含义
在程序运行期间其值可以改变的量称为变量。变量包括变量名和变量值。
变量名是内存一个存储单元地址
变量值是内存单元中的数值
2.3.2 变量名规则
- 标识符:用来标识变量、符号常量、函数、数组、类型等实体名字的有效字符序列称为标识符,实际上就是一个名字
- 变量的名字需要遵循标识符的命名规则:只能由字母、数字和下划线3种字符组成,且第一个字符必须为字母或下划线。
2.3.3 定义变量
-
定义变量的一般形式 : 数据类型 变量名表列;
eg: int a; -
c语言要求变量的定义应该放在所有的执行语句之前,而c++只要求在第一次使用该变量之前进行定义即可。
-
强制定义的目的:
①使得程序中变量名使用的正确
②变量被指定确定类型后,在编译时就能为其分配相应的存储单元
③变量被指定确定类型后,在编译时可以检查该变量所进行的运算是否合法
2.3.4 对变量赋初值
允许在定义变量时对它赋予一个初值,这称为变量初始化
2.3.5 常变量
-
定义变量时在前面加上关键字const,则变量的值在程序运行期间不能改变
-
为什么要存在常变量?
变量的特征时存在一个以变量名命名的存储单元,在一般情况下,存储单元的内容是可以变化的,对常变量来说,无非在此变量的基础上加上一个限定:存储单元中的值不允许变化,因此常变量又称为只读变量。 -
区分#define指令定义的符号常量和用const定义的常变量。
符号常量知识用一个符号代替一个字符串,在预编译时把所有符号常量替换为所指定的字符串,它没有类型,在内存中并不存在以符号常量命名的存储单元。
2.4 C++ 的运算符
2.5 算术运算符和算术表达式
2.5.1 基本的算术运算符
- 两个整数相除的结果为整数,舍去小数部分,在visual中“向零取整”
- c++在运算时对所有float型数据都按double型数据处理
2.5.2 算术表达式和运算符的优先级与结合性
先乘除后加减,如果优先级相同则从左向右运算
2.5.3 表达式中各类数值型数据间的混合运算
箭头方便只表示数据类型级别的高低,由低到高转换
2.5.4 自增(++)和自减(–)运算符
- ++/–i (在使用i之前先使i加/减1)
- i++/-- (在先使用i,再加/减1)
2.5.5 强制类型转换运算符
一般格式:(类型名)(表达式)
- 在强制类型转换时,得到一个所需类型的中间数据,但原来变量的类型没发生改变。
- 如果要强制类型转换的对象是一个变量,该变量可以不用括号括起来,如果是一个多项表达式则应该用括号括起来。
- 如3+6.5这种转换为隐式类型转换,强制类型转换又叫显式类型转换
2.6 赋值运算符和赋值表达式
2.6.1 赋值运算符
“=” 将一个表达式的值赋给一个变量
2.6.2 赋值过程中的类型转换
- 将浮点型数据赋值给整型时,舍弃小数部分。
- 将整型数据赋给浮点型变量时,数值不变,但以指数形式存储到变量中。
- 将一个double型赋给float变量时,注意数值不能溢出
- 字符型数据赋给整型,将ascll码赋给整型变量
- 将一个int short 或 long型赋给一个char型数据,只能将其低八位原封不懂地送到char型变量。
- 将signed型数据赋给长度相同的unsigned型,将存储单元内容原样照搬
- 不同类型的整型数据间的赋值:按存储单元中的存储形式直接传送,而负数在存储单元中存放的是补码(即原码除符号位取反加一),正数在存储单元中存放的是原码。
2.6.3 复合赋值运算符
在“ = ”前加上别的运算符,可以构成复合运算符。
- 如+= 、-=、%=、*=、<<=、>>=、&=、^=、|=
- 如a+=b ===> a=a+b
2.6.4 赋值表达式
- 求解过程:先求赋值运算符右侧的“表达式”的值,然后赋给赋值运算符左侧的变量
- 表达式和常变量不能被当作左值,变量能被当作左值,右值没限制
2.7 逗号运算符和逗号表达式
一般形式:
(表达式1,表达式2)
求解过程:先求表达式1,再求表达式2,整个逗号表达式的值是表达式2的值
a=(35,a4)为先a=35=15,然后a=154=60,若没有括号则a=15.
第三章程序设计初步
过程化设计:程序必须要给出计算机全部操作的具体过程。
3.1 基于过程的程序设计
3.1.1 算法的概念
一个程序必须包括①对数据的描述,即数据结构②对操作的描述,即算法。
程序 = 算法 + 数据结构
算法是处理问题的一系列步骤,算法必须具体地指出再执行时每一步应当怎样做。
3.1.2 算法的表示
- 自然语言
- 流程图
- 伪代码
- 计算机语言
3.2 c++的程序结构和c++语句
一个程序包括
- 预处理命令。包括#include #define
- 全局声明。全局的数据类型,函数及变量的声明和定义
- 函数。包括函数首部和函数体,在函数体中可以包括声明语句和执行语句
c++语句可以分为以下4种。
-
声明语句
-
执行语句
①控制语句
②函数和流对象调用语句
③表达式语句
任何一个表达式的最后加一个分号都可以称为一个语句,一个语句最后必须出现分号。 -
空语句(;)
-
复合语句(可以用{}把一些语句括起来称为复合语句)
3.3 c++的输入和输出
3.3.1 输入流与输出流的基本操作
- c语言中输入和输出功能时调用scanf和printf函数实现的,而c++中是通过调用cin和cout流对象来实现的。
- 定义流对象时,系统会在内存中开辟一段缓冲区,用来暂存输入输出流的数据。在执行cout语句时,并不是插入一个数据就马上输出一个数据,而是先把插入的数据顺序存放在输出缓冲区中,直到输出缓冲区满或遇到cout语句中的endl,此时将缓冲区中已有数据一起输出,并清空缓冲区。
3.3.2 在标准输入流和输出流中使用控制符
3.4.3 用getchar和putchar函数进行字符的输入和输出
-
putchar函数(字符输出函数:向终端输出一个字符)
putchar(66);的作用是将66作为ascll码转换为字符输出
putchar(’\n’);的作用是输出一个换行符 -
getchar函数(字符输入函数:从终端或系统隐含指定的输入设备输入输入一个字符)
一般形式:getchar()
getchar()函数得到的字符可以赋给一个字符变量或整型变量,也可以不赋给任何变量。
3.4.4 用scanf和printf函数进行输入和输出
一般格式:
scanf(格式控制,输出表列)
printf(格式控制,输出表列)
3.5 编写顺序结构的程序
从上到下的顺序执行各个语句
3.6 关系运算和逻辑运算
-
用关系运算符将两个表达式连接起来的式子,称为关系表达式
一般形式: 表达式 关系运算符 表达式 -
算术表达式的值是一个数值;赋值表达式的值就是赋予变量的值;关系表达式的值是一个逻辑值,即真1假0。
3.6.2 逻辑常量和逻辑变量
- c语言没有提供逻辑型数据,关系真假用10表示;c++使用false和true两个逻辑常量表示。
- 逻辑型变量要用标识符bool定义,它的值只有true和false两种。
- 逻辑变量用bool定义,故称为布尔变量,逻辑常量又叫做布尔常量
3.6.3 逻辑运算和逻辑表达式
-
将两个关系表达式用逻辑运算符连接起来就称为一个逻辑表达式,一般形式为: 表达式 逻辑运算符 表达式
逻辑表达式的值是一个逻辑量真假。 -
整型数据是0则为假,非0则为真
3.7 选择结构和if语句
3.7.1 if语句的形式
- 一般形式:
if(表达式)语句1;
【else语句2】 - 多表达式形式:
if(表达式1)语句1;
else if(表达式2)语句2;
else if (表达式3)语句3;
…
else 语句n;
3.7.2 if语句的嵌套
一般形式如下:
if()
if()语句1;
else 语句2;
else
if()语句3
else 语句4
if与else的配对关系,else总是与它上面最近的,且未配对的if配对
3.7.3 条件运算符和条件表达式
条件运算符(三目运算符) ?:
条件表达式的一般形式: 表达式1 ?表达式2 :表达式3
执行顺序是:先求表达式1,若为真,则求解表达式2,此时表达式2的值就是整个表达式的值;若为假,则求解表达式3,此时表达式3的值就是整个表达式的值。
3.7.4 多分支选择结构与switch语句
一般形式:
switch(表达式)
{case 常量表达式1:语句1;
case 常量表达式2:语句2;
…
case 常量表达式n:语句n
default :语句n+1
}
注:
①switch后面的表达式,可以是数值类型、字符类型的数据
②当switch表达式的值,与某一个case子句中的常量表达式匹配时,执行此case子句中的内嵌语句。
③每个case表达式的值必须不同
④执行完一个case子句后,流程控制转移到下一个case子句继续执行。case常量表达式知识起语句标号作用,并不是在此处进行条件判断,根据switch表达式的值找到对应的casw子句,从此子句开始执行下去,将后面的全部输出! 如果要停止,则在对应语句后面就假break;
3.8 循环结构和循环语句
3.8.1 用while语句构成循环
一般形式:
while(表达式)语句
- 循环体如果包含一个以上的语句,应该用花括号括起来,以复合语句形式出现
- 在循环体中应又使循环趋向于结束的语句
3.8.2 用do-while语句构成循环
一般形式:
do
语句
while(表达式);
特点是:先执行循环体,然后判断循环条件是否成立。
3.8.3 用for语句构成循环
一般格式:
for(表达式1;表达式2;表达式3)语句;
for语句最常用的形式也是最容易理解的格式如下:
for(循环变量赋初值;循环条件;循环变量增值)语句;
说明:①for语句的一般格式中的“表达式1”可以忽略,此时应在for语句之前给循环变量赋初值。注意省略表达式1时,其后的分毫不能忽略。
for(;i<=100;i++)sum=sum+i;
②如果表达式2省略,即不判断循环条件,循环无终止进行下去,也就是认为表达式2始终为真。
for(i=1;;i++)sum=sum+i;
③表达式3也可以省略,但此时程序设计者应另外设法保证循环能正常结束
for(i=1;i<=100;){sum = sum+i;i++;}
④可以忽略表达式和表达式3,只有表达式2,即只给循环条件
for(;i<=100;){sum=sum+i;i++;}
⑤表达式一般是关系表达式或逻辑表达式,但也可以是数值表达式或字符表达式,只有其值非零,就执行循环体。
3.8.4 提前结束循环(break语句和continue语句)
- 用break语句:作用为使流程从循环体内跳出循环体,即提前结束循环
- 用continue:作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。
第四章 利用函数实现指定的功能
4.1 什么是函数
4.1.1 为什么需要函数
在程序进行编译的时候,以程序文件模块为编译单位,即分别对每一个编译单位进行编译,如果发现错误,可以在本程序模块范围内查错并改正,在分别通过编译后,才进行连接,把各模块的目标文件以及系统文件连接在一起形成可执行文件。
程序总是从main函数开始执行的,在应用中main函数总是写的很简单。
4.1.2 函数的分类
- 系统函数,即库函数
- 自定义函数
- 无参函数
- 有参函数
4.2 定义函数的一般形式
4.2.1 定义无参函数的一般形式
一般形式:
类型名 函数名(【void】)
{声明部分
执行语句}
4.2.2 定义有参函数的一般形式
一般形式:
类型名 函数名 (形式参数表列)
{声明部分
执行语句}
如:int max(int x,int y)
4.3 函数参数和函数的值
4.3.1 形式参数和实际参数
- 在定义函数时函数名后面括号中的变量名称为形式参数
- 在主调函数中调用一个函数时,函数名后面括号中的参数称为实际参数
形参和实参的说明:
①在定义函数时指定的形参,在未出现函数调用时,它们并不占内存中的存储单元,因此叫做形式参数或虚拟参数
②只有主函数调用的时候,才会被调用函数中的形参才会分配存储单元,以接收实参传来的数据,在调用结束后,形参所占的内存单元也被释放
③实参和形参的类型应当相同或者赋值兼容(如实参时3.5,形参是整型,则将3送给形参,字符型与整型可以互相通用)
④实参可以是常量变量或表达式,但表达式中的值要确定
⑤实参变量对形参变量的数据传递是“值传递”,即单向传递,只由实参传给形参,而不能由形参传回给实参。
4.3.2 函数的返回值
通过函数的调用使主调函数能得到一个确定对的函数值,这就是函数的返回值
说明:
①return语句将被调用函数中的一个确定值待会主调函数中去。
②输出值取决于函数类型而非变量类型
4.4 函数的调用
4.4.1 函数调用的一般形式
一般形式:
函数名(【实参表列】}
4.4.2 函数调用的方式
- 函数语句(完成一定操作)
printstar(); - 函数表达式(返回一个确定的值以参加表达式运算)
c=2*max(a,b); - 函数参数
m = max(a,sqrt(b));
4.4.3 调用函数的条件
- 被调函数必须是已存在的函数
- 如果是库函数应当用#include引入
- 调用自定义函数时,如果被调用函数在主函数的后面时,必须先声明
4.4.4 函数声明和原型
- 函数声明:就是在函数尚未定义的情况下,事先将该函数的有关信息通知编译系统,以便使编译能正常运行。
如:float add(float x,float y); - 函数原型:
float add(float,float)
它的作用是:根据函数原型在程序编译阶段对调用函数的合法性进行全面检查。 - 函数原型的一般形式:
函数类型 函数名(参数类型1,参数类型2 ……);
函数类型 函数名(参数类型1 参数名1,参数类型2 参数名2……)
说明:
①如果被调用用函数的定义出现在主调函数之前,可以不必声明
②如果函数声明放在函数的外部,在所有函数定义之前,则在各个主调函数中不必对所调用的函数再作声明
4.5 函数的嵌套调用
c++不允许在一个函数中完整地包含另一个函数,但是可以在被调用函数中调用另一个函数。
4.6 函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用函数本身,称为函数的递归调用,包含递归调用的函数称为递归函数。
#include <iostream>
using namespace std;
int digui(int a)
{
int n=0;
if(a>1) n=digui(a-1)+2;
else n=10;
return n;
}
int main()
{
int i,x;
cin>>i;
x = digui(i);
cout<<x<<endl;
}
4.7 内置函数
- 出现原因:调用函数需要一定的事件和空间开销
转去调用函数之前,要记下当时执行指令的地址,还要保护现场,以便在函数调用之后继续执行,在函数调用之后,流程返回到先前几下的地址出,并且根据几下的信息“恢复现场”,然后继续执行。 - 内置函数:嵌入到主调函数的函数,即在编译时将所调用的代码直接嵌入到主调函数中。
- 内置函数用法:可以在声明函数和定义函数时同时写inline,也可以只在函数声明时加inline
编译系统在遇到调用 max(i,j,k) ,就用max函数体的代码代替 max(i,j,k)。 - 使用内置函数可以节省运行时间,但增加了目标程序的长度,因此只将规模很小而使用频繁的函数声明为内置函数。内置函数中不能包括复杂的控制语句,如循环语句和switch语句。
4.8 函数的重载
- 函数的重载:即对一个函数名重新赋予它新的含义,使一个函数名可以多用,所谓重载,其实就是“一物多用”。
- 条件:假如要实现同一类功能,但是细节不同,比如要从三个数中找最大值,但是不同类型的函数,整型、双精度、长整型函数,要实现一个函数满足三种类型,则需要用函数的重载。
- 两次调用max函数的参数个数不同,系统就根据参数的个数找到与之匹配的函数并调用它
4.9 函数模板
- 函数模板:建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代替这个通用函数就称为函数模板,凡是函数体相同的函数都可以用这个模板来代替。
- 一般形式
template< typename T >
通用函数定义
或
template< class T>
通用函数定义
4.10 有默认参数的函数
在函数声明的时候:
int max(int a,int b,int c=0)
4.11 局部变量和全局变量
4.11.1 局部变量
在一个函数内部定义的变量是内部变量,它只在本函数范围内有效;形参也是局部变量
4.11.2 全局变量
函数之外定义的变量是外部变量,称为全局变量,有效范围从定义变量的位置开始到源文件结束。
说明:
- 全局变量的作用是增加了函数间数据联系的渠道。
- 只在必要的时候使用全局变量
- 全局变量在程序的全部执行过程中都占用存储单元
- 函数通用性降低了
- 如果在同一个源文件中,全局变量和局部变量同盟,则在局部变量的作用域内全局变量被屏蔽
4.12 变量的存储类别
4.12.1 动态存储方式和静态存储方式
- 变量有两种属性①作用域②存储期
- 存储期是指变量在内存中的存在周期,可以分为静态存储期和动态存储期
- 静态存储期:指在程序运行期间,系统对变量分配固定的存储空间
动态存储期:在程序运行期间,系统对变量动态分配存储空间 - 存储空间分为三部分:①程序区②静态存储区③动态存储区
- 静态存储区:全局变量,在程序开始执行的时候给全局变量分配存储单元,执行完就释放。
动态存储区:函数形式参数,函数中定义的变量,函数调用时的现场保护和返回地址 - 存储类别分为:①自动的(auto)②静态的(static)③寄存器的(register)④外部的(extern)
4.12.2 自动变量
函数中的局部变量,如果不用关键字static加以声明,编译系统对他们是动态地分配存储空间的
4.12.3 用static声明静态局部变量
当希望函数中的局部变量的值在函数调用结束后不消失,即其占用的存储单元不释放,在下一次该函数调用时,该变量保留上一次函数调用结束时的值,就应该指定为静态局部变量
说明:
- 静态局部变量在静态存储区内分配存储单元
- 对静态局部变量是在编译时赋初值的,即支付处置一次,在程序运行时他已有初值
- 在定义局部变量时不赋初值,静态局部变量就自动赋为0(对数值型)或空字符(对字符型)
- 虽然静态局部变量在函数调用结束后依然存在,但其他函数不能引用
什么情况下需要用局部静态变量?
①需要保修函数上一次调用结束时的值
②初始化后,变量只被引用而不改变其值,则这时用静态局部变量比较方便
4.12.4 用register声明寄存器变量
变量的值一般是存放在内存中的,当程序用到某个变量的时候,由控制器发出指令将内存中该变量的值送到cpu中的运算器。
如果有些变量使用频繁,可以直接放在寄存器中。由于对寄存器的存取速度高于内存的存取速度,因此这样可以提高执行效率。
4.12.5 用extern声明外部变量
全局变量的作用域为从变量的定义开始,到本程序文件的末尾。有时需要用extern来声明全局变量,以拓展全局变量的作用域。
- 在一个文件内声明全局变量
如果外部变量不在文件的开头定义,其有效的作用范围只限于定义的位置起到文件终了的位置止。用extern对该变量作外部变量声明,就可以从声明的位置起,合法地引用该全局变量,这种声明称为提前引用声明。 - 在多文件的程序中声明外部变量
在任一个文件中定义外部变量,在其他文件中用extern对外部变量作外部变量声明
4.12.6 用static声明静态外部变量
有时希望某些外部变量只限于被本文件引用,而不能被其他文件引用,这时可以在定义外部变量时在前面加一个static声明。
4.13内部函数和内部函数
4.13.1 内部函数
如果一个函数只能被本文件中其他函数所调用,它称为内部函数,在定义内部函数时,在函数名和函数类型的前面加static,函数首部的一般格式为
static 类型标识符 函数名(形参表)
4.13.2 外部函数
- 在定义函数时,如果在函数首部的最左端以关键则extern,则表示此函数时外部函数,可供其他文件调用。
- 在需要调用此函数的文件中,用extern声明所用的函数时外部函数。
4.14 头文件
4.14.1 头文件的内容
①对类型的声明
②内置(inline)函数的定义
③函数声明
④宏定义。用#define定义的符号变量和用const声明的常变量
⑤全局变量定义
⑥外部变量声明
⑦还可以根据需要包含其他头文件
4.16.2 关于c++标准库和头文件的形式
各种c++编译系统都提供了许多系统函数和宏定义,而对函数的声明则分别存放在不同的头文件中。如果用户自己编写头文件,可以用.h作后缀。这样从#include指令中即可看出那些头文件是属于c++标准库的,哪些头文件是用户自编或比尔提供的。
第五章 利用数组处理批量数据
5.1 为什么需要用数组
- 数组:具有相同属性的数据,就可以把这批数据看作一个整体,用序号或下标来区分各个数据
- 下标:用来区分各个数据
- 数据元素:数组中的数据
- 数组每一个元素都必须属于同一数据类型。
5.2 定义和引用一维数组
5.2.1 定义一维数组
一般形式:
类型名 数组名【常量表达式】;
例如:int a[10]; //仅为定义时一定要为常量表达式
说明:
①数组名定义规则和变量名,遵循标识符定名规则
②用方括号括起来的变量表达式表示下标值
③常量表达式的值表示元素的个数,即数组长度
int a[10];中包含十个元素分别是a[0]~a[9]
④常量表达式中可以包括变量、常变量和符号常量,但不能包含变量
5.2.2 引用一维数组的元素
只能逐个引用数组元素的值而不能一次引用整个数组中的全部元素的值
表示形式:
数组名[下标]
5.2.3 一维数组的初始化
- 在定义数组时对全部数组元素赋予初值
int a[10] = {0,1,2,3,4,5,6,7,8,9} - 可以只给一部分元素赋值
int a[10]={0,1,2,3,4} - 在对全部数组元素赋初值时,可以不指定数组长度
int a[] = {1,2,3,4,5} //默认数组有五个元素,且分别为12345
5.3 定义和引用二维数组
具有两个下标得数组称为二维数组,有些数据依赖于两个因素才能表示出来。
5.3.1 定义多维数组
一般形式:
类型名 数组名【常量表达式】【常量表达式】[……]
二维数组中元素排列的顺序是:按行存放,即在内存中先顺序存放第一行元素,再存放第二行元素
float a[3 ]【 4 ]为3×4的单精度数组
5.3.2 引用多为数组的元素
一般形式:
数组名 【下标】【下标】【……】
数组元素是左值,可以出现在表达式中,也可以被赋值
5.3.3 二维数组的初始化
- 按行给二维数组全部元素赋初值
int a[3][4】 = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; - 可以将所有数据写在一个花括号内,按数组排列的顺序对全部元素赋初值
int a【3】【4】={1,2,3,4,5,6,7,8,9,10,11,12}; - 可以对部分元素赋初值
int a【3】【4】={{1},{5},{9}}
它的作用只对各行第一列的元素赋初值,其余元素自动置为0. - 如果对全部元素都赋初值,则定义数组时对第1维的长度可以不指定,但对第2维的长度不能省。
int a【】【4】= {1,2,3,4,5,6,7,8,9,10,11,12};
相当于int a【3】【4】
5.4 用数组作函数参数
数组名也可以作实参和形参,传递的是数组的起始地址
- 用数组元素作函数实参
由于实参可以是表达式,而数组元素可以是表达式组成部分,因此数组元素当然可以作为函数的实参,与用变量作实参一样,将数组元素的值传给形参变量 - 用数组名作函数参数
如 max(a,10);
说明:①如果函数实参是数组名,形参也应为数组名②数组名代表数组首元素的地址,形参可以是数组名,也可以是指针变量,它们用来接收形参传来的地址 - 在用变量作为函数参数时,只能将实参变量的值传给形参变量,在调用函数过程中如果改变了形参的值,对实参没有影响;数组名作函数实参时,如果改变了形参数组元素的值将同时改变实参数组元素的值。
5.5 字符数组
字符数组中的一个元素存放一个字符
5.5.1 定义和初始化字符数组
- 如果花括号中提供的初值个数大于字符长度,则按语法错误处理
- 如果花括号中提供的初值个数小于字符长度,则其他元素自动定位空字符(即’\0’)
- 如果个数相等,则定义时可以省略长度。
5.5.2 字符数组的赋值和引用
只能对字符数组的元素赋值,而不能用赋值语句对整个数组赋值。
5.5.3 字符串和字符串结束标志
- c++规定了一个字符串结束标志,字符’\0’。
遇到字符’\0’就表示字符串到此结束,由它前面的字符组成有效字符串。所以,在程序中往往依靠 检测’\0’的位置来判定字符串是否结束,而不是根据数组的长度决定字符串长度。 - 可以用字符串常量来初始化字符数组
这两种等效
5.5.4 字符数组的输入输出
字符数组的输入输出可以有两种方法:
①逐个字符输入输出
②将整个字符串一次输入或输出
cin>>str;
cout<<str;
字符数组名str代表字符数组第一个元素str[0]的地址,执行cout<<str;的过程是从str所指向的数组第一个元素开始逐个输出字符,直到遇到’\0’为止
说明:
- 输出的字符不包括结束符’\0’
- 输出字符串时,cout流中用字符数组名,而不是数组元素名
- 如果数组长度大于字符串实际长度,输出遇’\0’结束
- 如果一个字符数组中包含一个以上’\0’,则遇第一个’\0’时输出就结束
- 用cin从键盘向计算机输入一个字符串时,从键盘输入的字符串应短于已定义的字符数组的长度,否则会出现错误。(例子中的溢出覆盖没有出现,输入什么还是输出什么,只是返回值错误)
5.5.5 使用字符串处理函数对字符串进行操作
用#include<string>把函数库包含到本文件中后可以使用对字符串操作函数
- 字符串连接函数strcat
原型位strcat(char[],const char[]);
函数的作用:将第2个字符数组的字符串连接到前面字符数组的字符串的后面,第2个字符数组被声明为const,以保证该数组中的内容不会在函数调用期间修改。
- 字符串复制函数strcpy
strcpy(char[],const char[])
函数作用:将第2个字符数组中的字符串复制到第1个字符数组中去,将第1个字符数组中的相应字符覆盖。
说明:①在调用strcpy函数时,第1个实参必须时数组名,第2个实参可以时字符数组名,也可以时一个字符串变量②可以用strcpy函数将一个字符串中前若干个字符复制到一个字符数组中去strcpy(str1,str2,2)③只能用此函数来将一个字符串赋给字符数组,不能用赋值语句实现。
- 字符串比较函数strcmp
函数原型为 strcmp(const char【】,const char【】);这两个参数都加上const声明
作用:①如果字符串1等于字符串2,函数值为0
②如果字符串1大于字符串2,函数值为一正整数
③如果字符串1小于字符串2,函数值为一负整数
- 字符串长度函数strlen
strlen(const char【】);
函数作用:字符串中的实际长度,不包括空字符在内
5.6 c++处理字符串的方法——字符串类与字符串常量
c++提供了一中信的数据类型——字符串类型
5.6.1字符串变量的定义和引用
- 定义字符串变量
首先引入库#include<string>
定义 string string1;
定义并初始化 string string2=“china”; - 对字符串变量的赋值
既可以用字符串常量给字符串变量赋值,也可以用一个字符串变量给另一个字符串变量赋值 - 字符串变量的输入输出
cin>>string1;
cout<<string2;
5.6.2 字符串变量的运算
字符数组存放字符串时,字符串的运算要用字符串函数,但是string类对象可以直接用简单的运算符
- 字符串复制直接用赋值号
string1 = string2; - 字符串连接用加号
- 字符串比较直接用关系运算符
5.6.3 字符串数组
说明:①在字符串数组的每一个元素中存放一个字符串,而不是一个字符,这是字符串数组与字符数组的区别。②不要求每个字符串元素有相同的长度③对于同一元素而言,它的长度也可以变化,当向某一个元素重新赋值,长度就可能变化④字符串数组中的每一个元素的值值包含字符串本身的字符而不包括’\0’。
第六章 善于使用指针与应用
6.1 什么是指针
- 内存区每一个字节有一个编号,这就是“地址”。
- 直接赋值给变量的方式为直接存取方式,又称直接访问方式
- 将变量i的地址存放在另一变量中的方式称为间接存取(间接访问)的方式
- i_pointer = &i; //i_pointer是指针变量,&i是变量i的存储单元的起始地址,&是取地址运算符
- 一个变量的地址称为该变量的指针
- 存放变量地址的变量就是指针变量
使用指针的优点:①提高程序效率 ②在调用函数时,如果改变被调用函数中某些变量的值,这些值能为主调函数使用,即可通过函数的调用,得到多个可改变的值③可以实现动态存储分配。
6.2变量与指针
c++中用 “ * ” 来表示指向
例如,当i_pointer = &i;时,*i_pointer也代表变量i,即
①i=3;
②*i_pointer = 3;
两句的作用相同
6.2.1 定义指针变量
- 在Visual c++中,每一个指针变量占4个字节的存储空间。
- int *pointer_1; //定义指针变量,int指所定义的指针变量是指向整型数据的指针变量,也就是pointer_1只能存放整型数据的地址
int i; //定义变量
pointer_1 = &i; //指针变量取变量的地址 - 定义指针变量的一般形式:
基类型 * 指针变量名
指针变量的基类型就是该指针变量指向变量的类型 - pointer_1是指针变量名。*pointer_1等于指向的变量。
注:①在定义指针变量时必须指定基类型。一个变量的指针包括两个方面的含义,一是存储单元编号表示的地址(如编号为2000的字节),一是它指向的存储单元的数据类型,即基类型。指针变量是基本数据类型派生出来的类型,它不能离开基本类型而独立存在。
②指向整型数据的指针类型表示为int * ,读作指向int的指针或简称int 指针
③不能用一个整数给指针变量赋值。如 int *pointer_1=2000
④一个指针变量只能指向同一个类型的变量
⑤说明变量类型时要说 a是指向整型数据的指针变量,b是指向单精度型数据的指针变量,而不能说a是一个指针变量
6.2.2 引用指针变量
- &:取地址运算符
- *:指针运算符(间接访问运算符)
&a为变量a的地址,*p为指针变量p所指向的存储单元
如果已经执行了pointer_1 = &a;,那么:
①&*pointer_1自右而左结合,即&*pointer_1 == &a
②*&a的含义是 *&a == a
6.2.3 用指针作函数参数
函数参数不仅可以是整型、字符型等,还可以是指针类型。它的作用是将一个变量的地址传送给被调用函数的形参。
虚实结合是采用单向的“值传递”方式,只能从实参向形参传数据,形参值的改变无法回传给实参。不能试图通过改变形参指针变量的值而使实参指针变量的值改变。
上述函数被调用时不会改变实参指针变量的值,但可以改变实参指针变量所指向变量的值。
6.3 数组与指针
6.3.1 指向数组元素的指针
- 数组元素的指针就是数组元素的地址
int a[10]; //定义一个整型数组a,它有10个元素
int *p; //定义一个基类型为整型的指针变量p
p=&a[0]; //将元素a[0]的地址赋给指针变量p,使p指向a[0] - 数组名代表数组中第一个元素即p=&a[0];和p=a;等价
- 如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素,即p值得地址加4个字节。
- 如果p的初值为&a[0]
- p+i和a+i就是a[i]的地址,a代表数组首元素的地址,a+i也是地址,它的计算方法同p+i,即它的实际地址为a+i×d。
- *(p+i)或*(a+i)事p+i或a+i所指向的数组元素,即a[i]
- 指向数组元素的指针变量也可以带下标,如p[i]与*(p+i)等价
引用一个数组元素,可以用①下标法a[i]②指针法 *(a+i)或*(p+i)③用指针变量指向数组元素
第三种方法比前两种快,因为用指针变量直接指向元素,不必每次都重新计算地址。
6.3.2 用指针变量作函数形参接收数组地址
- 数组名代表数组首元素的地址。
- 用数组名作函数的参数,传递的是数组首元素的地址。
- c++编译系统将形参数组名一律作为指针变量来处理。
在被调用函数中用sizeof(array)值为4,在主函数中sizeof(a)值为40。 - 实参数组名a代表一个固定的地址,所以不能用数组来计算a
a++; //语法错误,因为a是常量,不能改变 - 形参数组名是指针变量,并不是一个固定的地址值,它的值可以改变。
6.4字符串和指针
- 用字符数组存放一个字符串
char str[] = “I love China!”; - 用字符串变量存放字符串
string str = “I love China!”; - 用字符指针指向一个字符串
char * str = “I love China!”;
对字符串中字符的存取,可以用下标方法,也可以用指针方法
6.5 函数与指针
指针变量也可以指向一个函数,这个函数入口地址就称为函数的指针。
可以用一个指针变量指向max函数,然后通过该指针变量调用此函数。
6.6 返回指针值的函数
一个函数可以待会一个整型值、字符值等,也可以带回指针型的数值,返回指针值的函数简称为指针函数。
6.7 指针数组和指向指针的指针
6.7.1 指针数组
- 定义:如果一个数组,其元素均为指针类型数据,该数组称为指针数组。指针数组中的每一个元素相当于一个指针变量,它的值都是地址。
- 定义式为:
类型名 * 数组名[数组长度];
例如:int *p[4];[]的优先级比*高,表示此数组是指针类型的,每个数组元素都可指向一个整型变量。
int(*p)[4];是指向以为数组的指针变量。
6.7.2 指向指针的指针
全称为指向指针数据的指针,假设name是一个指针数组,其中每一个元素都指向一个数据,再设置一个指针变量p,使其指向name的一个元素,则p为指向指针的指针。
6.8 const指针
可以指定指针变量使一个常量,或者指定指针变量指向的对象是一个常量。
- 指向常量的指针变量
- 定义这种指针变量的一般形式为
const 类型名 * 指针变量名;
经此定义之后,不允许通过指针变量改变它指向的对象的值。
- 例如:
int a==12;
const int *p = &a; //定义了p为指向整型变量a的const指针变量
*p = 15; //不合法
- 假如:
const int a = 12; //这样p就称为指向常变量的指针变量 - 常指针
- 指定指针变量的值是常量,即指针变量的指向不能改变
定义的一般形式为
类型名 * const 指针变量名;
- char *const p1 = “China”; //p1是字符指针变量,其指向不能改变
p1 = “Canada”; //不合法
- 说明:①这种指针变量称为常指针变量,简称常指针
②必须在定义时初始化,指定指向
③指针变量的指向不能改变,但指针变量指向的变量值可以改变 - 指向常量的常指针
- 指针变量指向一个固定的对象,该对象的值不能改变(指不能通过指针变量改变该对象的值)
- 一般形式为
const 基本类型名 * const 指针变量名;
const int * const pt = &a;
6.9 void指针类型
指向空类型或不指向确定的类型(不知道有什么用)
6.10 有关指针的数据类型和指针运算的小结
6.10.1 数据类型
6.10.2 指针运算小结
功能 | 例子和方法 | 说明 |
---|---|---|
指针变量加/减一个整数 | p++,p+i,p-=i | 本质是指针变量原值和他指向的变量所占用的内存党员字节数相加或相减 |
指针变量赋值 | ![]() | 无 |
指针变量空值 | p=NULL | p的值等于NULL是有值的,不指向任何变量;p未赋值不代表p无值,只是它的值是一个无法预料的值,也就是它指向一个未指定的单元 |
两个指针变量可以相减 | p2-p1可以,但p1+p2没有意义 | 如果两个指针变量指向同一个数组元素,则两个指针变量值之差是两个指针之间的元素个数 |
两个指针变量比较 | p1<p2 | 如果两个指针指向同一个数组的元素,就可以进行比较。指向前面的元素的指针变量小于指向后面元素的指针变量 |
对指针变量的赋值 | int *p1;int *p2;p1=p2; | 假如p1,p2分别是整型,字符型,则p1=p2;等是不合法的 ,必须为p1 = (int *)p2; |
6.11 引用
6.11.1 什么是变量的引用
- 引用:对一个数据可以建立一个引用,它的作用是为一个变量起一个别名。
- 如: int a;
int &b = a;
理解为,通过b可以引用a,&是引用声明符,并不代表地址 - 说明:
- 引用不是一中独立的数据类型,对引用只有声明,没有定义
- 声明一个引用时,必须同时使之初始化,即声明它代表哪一个变量
int &b = a;
- 在声明一个引用后,不能再使之作为另一变量的引用
int &b = a;
int &b = a1; //非法
- 不能建立引用数组
int a[5];
int &b[5] = a; //非法,不能建立引用数组
int &b = a[0]; //非法,不能作为数组元素的别名
- 不能建立引用的引用,也没有引用的指针
int &b = a;
int &c = b; //非法
int *p = b; //非法
- 可以取引用的地址。
假如b是a的引用:int *p;
p = &b; //把变量a的地址&a赋给指针变量p
- 引用声明符在左,地址运算符在右 - b是a的引用,实际上在内存中为b开辟了一个指针型的存储单元,在其中放了a的地址。引用实际上就是一种指针,它的指向不能改变。
- c++增加引用的机制,是为了方便用户不必具体处理地址。
6.11.3 引用作为函数参数
引用最大的作用是把它作为函数参数,以扩充函数传递数据的功能
函数参数传递的三种情况:
①将变量名作为实参和形参,这是传给形参的是变量的值,传递是单向的
②传递变量的地址,形参是指针变量,实参是一个变量的地址,调用函数时,形参得到实参变量的地址,因此指向实参变量单元。
③引用作为形参,在虚实结合时建立变量的引用,使形参名作为实参的“引用”,即形参称为实参的引用
说明:前两种方式是传值,第三种方式是传址
第七章 用户自定义数据类型
7.1 结构体类型
7.1.1 为什么需要用结构体类型
- 在一个组合项中包含若干个类型不同(当然也可以相同)的数据项,c和c++允许用户自定义这样一种数据类型,它称为结构体
- 声明一个结构体类型的一般形式为:
struct 结构体类型名
{ 成员表;}
成员表项:类型名 成员名;
每一个成员也称为结构体中的一个域,成员表又称为域表。
7.1.2 结构体类型变量的定义方法及其初始化
- 定义结构体类型变量的方法
- 先声明结构体类型再定义变量
struct Student{int num;char name[20];}
Student student1;
- 声明类型的同时定义变量
struct 结构体名
{
成员表
}变量名表;
提倡使用第一种方法,便于不同的函数甚至不同的文件都能使用所声明的结构体类型。
成员也可以是一个结构体变量:
- 结构体变量的初始化
定义时初始化:
Student student2 = { 1002,“wangming”,“F”,20,98}
7.1.3 引用结构体变量
- 可以将一个结构体变量的值赋给另一个具有相同结构的结构体变量
student1 = student2; //此时s2中各个成员的值分别赋给s1中相应的成员 - 可以引用一个结构体变量中的一个成员的值
引用结构体变量中成员的一般形式为:
结构体变量名.成员名
student1.num = 1001;
7.1.4结构体数组
一个结构体变量中可以存放一组数据
Person leader[3] = {“Li”,0,“zhang”,0,“sun”,0}
//定义person类型的数组,内容为三个候选人的型名和当前的得票数
7.1.5 指向结构体变量的指针
- 一个结构体变量额指针就是该变量所占据的内存段的起始地址。
- 可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址
- 指针变量也可以用来指向结构体数组中的元素
- 通过指向结构体变量的指针引用结构体变量中的成员
Student stu; //定义Student类型的变量stu
student *p = &stu; //定义p为指向Student类型数据的指针变量并指向stu - 用结构体变量和指向结构体变量的指针构成链表
head是一个“头指针”变量,它存放一个地址,该地址指向一个元素,链表中的每一个元素称为“结点”,每个结点包括:①为用户需要的实际数据②下一个结点的地址
7.1.6 结构体类型数据作为函数参数
将一个结构体变量中的数据传递给另一个函数,有下面3种方法:
- 用结构体变量名作参数
用结构体变量作实参,采取值传递的方式,将结构体变量所占的内存单元的内容全部顺序传递给形参(同类型结构体变量)。 - 用指向结构体变量的指针作实参,将结构体变量的地址传给形参
- 用结构体变量的引用作函数形参,它就称为实参的别名
7.1.7 用new和delete运算符进行动态分配和撤销存储空间
c语言种使用malloc和free函数来分配和撤销内存空间,c++提供了较简便而功能较强new和delete运算符。
new例子:
new int; //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址
new int(100); //开辟存放一个整数的空间,并指定该整数的初值为100,返回一个指向该存储空间的地址
new char[10]; //开辟一个存放10个元素的字符数组,返回字符数组首元素的地址
new int[5][4]; //开辟一个存放二维整型数组的空间,返回首元素的地址
float *p = new float(3.1415) //开辟一个存放单精度数的空间,并指定该数的初值为3.1415,返回该空间的地址赋给指针变量p
new一般格式:
new 类型 [初值] //分配数组空间时不能指定初值,如果内存分配失败,new会返回一个NULL
delete一般格式:
delete 指针变量 (对变量)
或
delete [] 指针变量 (对数组)
7.2 枚举类型
- 定义:如果一个变量只能有几种可能的值,可以定义为枚举类型,所谓“枚举”是指将变量的值一一列举出来,变量的值只能在列举出来的值的范围内。
- 声明枚举类型的一般形式:
enum 枚举类型名 {枚举常量表};
enum weekday{sun,mon,tue,wed,thu,fri,sat}; - 声明了枚举类型之后可以用来定义变量
enum weekday workday,week_end; //enum可以省略
workday = mon;week_end = sum;
或者
enum{sun,mon,tue,wed,thu,fri,sat} workday,week_end;
4.说明:
- 枚举元素按常量处理,故称为枚举常量
- 枚举元素作为常量,他们是有值的,其值是一个整数,编译系统按定义时的顺序赋值为0,1,2,3,……
workday = mon;
cout<<workday;//输出值为1
- 枚举值可以用来做判断比较,按整数比较规则进行比较
if(workday == mon)……
- 不能把一个整数直接赋给一个枚举变量,枚举变量只能接收枚举类型数据
workday = tue;//正确
workday = 2;//错误
7.3 用typedef声明新的类型名
- 除了可以用以上方法声明结构体、共用体、枚举等类型外,还可以用typedef声明一个新的类型名来代替已有的类型名。typedef int INTEGER; //指定用标识符INTEGER代替int类型
- 如果在一个程序种,整型变量时专门用来计数的,可以用count来代替int
- 也可以对一个结构体类型声明一个新的名字:
typedef struct
{int month;
int day;
int year;
}DATE; //DATE是新类型名,而不是结构体变量名 - 还可以进一步用typedef声明一个新的类型名
- 声明一个新的类型名的方法是:
①先按定义变量的方法写出定义(int i;)
②将变量名换成类型名(int count;)
③在最前面加typedef(typedef int count;)
④用新类型名去定义变量 - 说明:
①用typedef声明的新类型名又称为typedef类型名,或typedef名字
②用typedef只是对已经存在的类型增加一个类型名
③typedef声明新类型名但不能定义变量
④int a[10],b[10],c[10];比较麻烦,可以用typedef int ARR[10];ARR a,b,c;
⑤用typedef类型名,有利于程序的通用与移植。