目录
1.1 数据的输入与输出
1.2 指针
1.3 new和delete
1.4 引用
1.5 const常量
1.6 类型转换
1.7 函数
1.8 函数重载
1.9 内联函数
1.10 typedef
1.11 命名空间
1.12 std命名空间
1.13 预处理器
1.14 变量初始化
1.15 局部变量声明
1.1.1 cin和析取运算符>>
C++常用cin输入数据。
cin>>x>>y;
程序执行到cin时,等待键盘输入,>>后面只能出现变量名。
1.1.2 cout和插入运算符
cout<
C++一般用cout输出数据。
依次将x,y的值输出到显示器,end1相当于换行"\n",将光标移动到下一行开头处。
指针用于存放一个对象在内存中的地址,通过指针能够间接操作这个对象,指针的典型应是建立链接的数据结构,如树tree和链表list,并管理在程序运行中动态分配的对象。或者用域函数参数,以便传递数组或者大型类的对象。
对于类型T,T*是T的指针,即一个类型为T*的变量能够保存类型T的对象的地址。
int i=10;
int *p;
p = &i;
可以理解为指针代表了两个变量,一个是指针变量本身,另一个是它所指向的变量。对于int *p;
可以理解为它定义了两个变量p和*p,p是一个地址变量,只能存放整形变量在内存中的地址。
*p是一个整形变量,真能存放一个整数。
指针有两个属性,地址和长度,地址大小固定,与类型无关。长度则与指针的类型相关,这个类型指示编译器怎样解释它所指定内存区域的内容,以及该内存内容应该跨越多少个内存单元。鉴于此,C++提供了、无类型指针void*,任何类型的指针都是大小相同的地址,而void*指针仅表示与之相关的值是个地址。因此能够接收任何数据类型(除函数指针外)的指针。
例如:
void* pv;
如果想访问*p所指向内存的内容,则需要进行强制类型转换。
count<<*(double*)pv;
void*最重要的作用是作为函数的参数,以便向函数传递一个类型可变的对象,另一种用途就是从函数返回一个五类型对象。
指针经常与堆(heap)空间分配有关,所谓的堆就是一块内存区域,它允许程序在运行时以指针的方式从其中申请一定数量的存储单元(其他存储空间的分配是在编译时完成的),用域程序数据的处理,堆内存也称为动态内存。在使用堆内存时,可以使用malloc()从堆中分配指定大小的存储区域,用完之后需要用free()将之归还系统,如果不归还容易造成内存泄漏,也就是自己不用了,其他程序也无法使用,因此malloc()和free()是成对出现的。
例如:
上述两个函数在如下头文件中定义,
#include
main()
{
int *p;
//从堆分配一个int对象需要的内存,并将之转换为int类型。
p = (int*)malloc(sizeof(int));
*p = 23;
free(p);//释放堆内存
}
但malloc()的使用比较麻烦,除了要计算需求内存的大小,还必须对获得的内存区域进行类型转换才能使用。
因此C++提供了new和delete两个运算符进行堆内存的分配与释放。
new 的用法:
new用于从堆内存中分配指定大小的内存区域,并返回获得内存区域的首地址。
用法1:p=new type;
用法2:p=new type(x)
用法3:p=new type[n]
其中p是指针变量,type是数据类型。用法1只分配内存,用法2将分配到的内存初始化为x,用法3分配具有n个元素的数组,new能够根据type自动计算分配内存的大小,不需要sizeof()进行计算。如果分配成功将会得到的内存首地址存放在指针变量p中,如果分配不成功 ,则返回空指针(0)。
delete 的用法:
p = new int[10];
用法1:delete p;
用法2:delete[]p;
其中p是用new分配的堆空间的指针变量。用法1是用于释放动态分配的单个指针变量。用法2用于释放动态分配的数组存储区域。
其中 delete p 和 delete[]p的区别是,前者只释放了第一个数组元素,即p[0],而没有释放其他数组元素p[1]~p[9]会造成内存泄漏;后者则
将p所指向的数组区域全部归还系统。
使用new和delete的好处:
new能够自动计算要分配内存的大小,不需要用sizeof计算所要分配内存的字节数,减小出错率;
new不需要进行类型转换,能够自动返回正确指针类型;
new可以对分配的内存进行初始化;
new和delete可以被重载。
引用是某个对象(即变量)的别名,即某个对象的替代名称。是C++引用的新概念,引用由符号&引导定义,形式入下:
类型 &引用名 = 变量名;
例如:
int i = 9;
int &ir = i;
int *p = &ir;
p实际指向的是i,因为ir的别名是i,所以&ir将获得i的内存地址。
其中ir为i的别名,相当于i还有一个名字叫ir,对ir的操作就是对i的操作。
使用引用时应该注意:引用符&在类型和引用名之间的位置是灵活的;在变量声明时出现的&才是引用运算符(包括函数声明和函数返回类型声明),其他地方出现&都是地址操作符;引用必须定义在初始化,不能在定义完成后再给它赋值,为引用提供的初值,可以是一个变量,可以是另一个引用名,同一个变量可以定义多个引用。
使用引用时应当注意,不能建立引用的引用,不能建立引用数组,不能建立数组的引用,可以建立指针的引用,但不能创建指向引用的指针。
变量实质上是在程序运行过程中其值可以改变的内存单元的名字,常量就是在程序执行过程中其值固定不变的内存单元的名字。const用于修饰定义的常量。
const 常量类型 常量名=常量值
例如:
const i = 10;
const int i = 10;
上述两者等价C++把没有定义指定类型的常量定义默认为int类型。
const char c = "A"; //字符常量
const char s[] = "C++ CONST" //数组常量
注意:常量必须定义时初始化,且常量一旦定义就不能修改。
const int n;//错误,常量n未进行初始化。
const int n = 10;
i = 10;//错误,修改常量
i++;//错误,修改常量
在C++中,表达式可以出现在常量定义语句中。
int j,k = 9;
const il = 10+k+6;
在C++中,可以采用#define定义常量,但它是采用宏代换的方式进行常量处理,不具有类型检查机制,存在不安全性。
1.5.1 const与指针
const与指针结合有如下三种情况
type *const p // p【const】---*p【 】
type const *p
const type *p // p【 】---*p【const】
const type const *p // p【const】---*p【const】
type代表C++中的任意数据类型,p是指针变量。
1.5.2 const与引用
在定义引用时可以用const进行限制,使其成为不允许被修改的常量引用。
int i =9;
int &rr = i;
const int &ir = i;
rr = 8;
ir =7;//错误,ir是const的引用,不允许通过它修改对应的常量i。
类型转换是将一种数据类型转换为另一种数据类型,在同一个算术表达式中,若出现了两种以上的不同类型的数据类型,就会先进行数据类型转换,再计算表达式的值。
C++中类型转换常用在算数表达式计算、函数的参数传递、函数返回值及赋值语句中。
C++有两种类型转换方式,隐式类型转换,显示类型转换。
函数原型就是常说的函数声明,只有一条语句,由函数返回类型、函数名和形式参数表三部分构成,参数表中包含的所有参数类型和参数名,参数之间用逗号隔开;形式如下:
rtype f_name(typle p1,typl2 p2,....);
rtype是函数返回类型,f_name是函数名,type1是参数1的类型,p1、p2是形式参数。其中函数原型中的形式参数名是可以省略的。
如果函数原型中没有指出函数的返回类型,C++将默认函数的返回类型是int类型;如果一个函数中没有返回类型,则必须指明它的返回类型void。在函数体中不需要return语句。
函数重载就是允许在同一个程序中定义多个同名的函数,这些函数可以有不同的返回类型,参数类型,参数个数,以及不同的函数功能。
在函数声明或定义时,将inline关键字加在返回类型前面的函数就是内联函数,每次调用函数inline时都会插入它的代码,故会使代码增加,占用存储空间。
注意:内联函数的声明和定义必须要在函数调用之前完成;一般只有几行的程序(最好1~5行)经常被调用的简单函数才用作内联函数。
以下函数不能作为内联函数:递归函数、函数体内含有循环,switch,goto语句之类的复杂结构函数,或具有较多程序代码的大函数。
typedef 可以给已有类型定义一个容易阅读的描述性名称,提高程序代码的可读性。但要注意,typedef并没有建立新的数据类型,只是为已有的类型引入一个助记符。
typedef type newname;
其中type是已存在的数据类型,newname是为type指定的新类型名,新类型名newname并未取代原来的类型type,即type和newname在程序中都是可用的。
typedef float house_price;
house_price x,y;
float a,b;
命名空间的引入是为了防止大型软件中函数和变量名产生重名冲突。因此命名空间有以下特点:在一个命名空间里,可以定义许多不同的对象,并将这些对象的有效范围局限在命名空间内。但在不同的命名空间中,可以定义同名的对象,只要两个同名对象不在同一命名空间中,就不会引起冲突。
命名空间的定义:关键字为 namespace;
语法如下:
namespace namespace_name{
members;
}
【例如】
namespace ABC{
int count;
typedef float house_price;
struct student{
char *name;
int age;
};
double add(int a,int b){
return (double)a+b;
inline int min(int a,int b);
}
int ABC::min(int a,int, b){
return a>b? a:b;
};
}
这个命名空间有5个成员,count,house_price,student,add(),min()。有变量,结构,类型以及函数的声明或定义。
函数的定义有两种方法:
1.在命名空间中定义,如函数的add(),也可以在命名空间以外进行定义,如min()。当在命名空间以外进行定义时,要用"命名空间::"作为函数的前缀,表示该函数是属于某个命名空间的成员,它的有效范围仅在此命名空间内。
命名空间的应用:
【例如】
void main()
{
ABC::count = 1;
int count =9;//main函数中的count,与ABC中的count无关。
ABC::student s; //用ABC中的student定义s。
s.age = 9;
int x = ABC::min(4,5); //调用ABC中的min()计算两个数的最小值。
}
另外,标准C++提供了using命令,它可以将命名空间中的成员引入当前程序,简化了命名空间的使用。使用方式有如下两种:
1.引用空间名中的单个成员
using namespace_name::identifier
【例如】
void main()
{
using ABC::count;
count = 2;
//int count= 9;
count += 2;
}
第三行是错误的,因为main中已经有从ABC命名空间引入的count了,如果不使用using的话,第二和四行会写成:
ABC::count = 2;
ABC::count += 2;
2.引用命名空间的全部成员
using namespace_name
【例如】
using namespace ABC;
void main(){
int count = 9
student s;
count 5;
s.age = min(4,6)
}
在main函数中直接使用命名空间中所有成员。
标准C++将新格式头文件的内容全部放在了std命名空间中,如果程序要引用标准C++新格式头文件的函数,就要在程序中使用下面的语句std命名空间中的名称引用到全局命名空间中。
using namespace std;
【例如】
#include
string s1 = "ddd",s2; //string是字符串,定义域
s2 = si; //字符串赋值不需要strcpy。
#include
int s=sin(30); //sin函数在cmath库中;
#include
int i
scanf("%d",&i);
printf("i=%d\n",i)
#include
cin>>i;
cout<
如果只是用到std命名空间的个别标识符,可以在要使用的标识符前面加上前缀srd::,不用“using namespace std”,将std的全部名称引用到程序中来。
【例如】
std::cout <<"not use using std"<
C++预处理器提供了一些预处理命令,这些命令在正式编译之前执行,所有的预处理命令都以“#”开头,独占一行,语句结束时不需要分号。
1.#define 和 undef
#define 常用于定义一个标识符常量或者带参数的宏。
【例如】
#define pi 3.1415926
#define MAX(a,b) ((a)>(b)?(a):(b))
在对程序进行预编译时,C++会将#define定义的标识符常量的值替代常量标识符,用宏代替宏名。
#undef
用于删除由#define定义的宏,使之不再起作用。
#undef MAX
此命令之后MAX不再有意义。
2.条件编译
条件编译指示编译器只对满足条件的语句或者语句块进行编译,使同一程序再不同的编译条件下能够得到不同的目标代码。常用的条件编译有以下两种形式:
a)
#ifdef 标识符
语句组1
[#else
语句组2]//[]内是可选项。
#endif
b)
#ifndef 标识符
语句组1
[#else
语句组2]//[]内是可选项。
#endif
变量初始化的基本原则:
如果定义变量时提供了初始值表达式,系统就用这个表达式的值作为变量的初值;
如果定义变量时没有为它提供初值,则全局数据区中的变量将被系统自动初始化为0,栈和堆中的变量不被初始化。
int n; //初始化为0。
在C语言中,局部变量应当在函数可执行语句之前;
在C++中,变量可以在任何语句中定义。例如:
【例1-1】C++允许在for循环中定义变量
#include
void main(){
int n=1;
for(int i = 1; i <= 10; i++)
{
int n = 1;
n = n*i;
k = i;
}
cout<
变量在包含它最近的{}内有效,成为块作用域。
故n在main()函数内有效,i和k只在for循环中有效。