C++编程--语音特性(1)

一、基本类型

1.内置类型

C++基本内置类型有bool(1个字节)、char(1个字节)、wchar_t(2个字节)、short(2个字节)、int(4个字节)、long(4个字节)、float(4个字节)、double(8个字节)、long double(8个字节)。基本内置类型的存储空间依机器而定。c++标准规定了每个算术类型的最小存储空间。

2.变量名

变量名,即变量的标识符,由字母、数字和下划线组成变量名必顺以字母或下划线开头,并且区分大小写字母:C++的

的标识符都是大小写敏感的。

3.初始化

默认的全局变量有默认值,局部变量则被赋予任意值,为安全起见,无论全局或者局部变量都要初始化。

4.const

const int MaxSize = 100; //定义一个常量
MaxSize = 59;//试图修改MaxSize常量,这一句在编译的时候就要出错

const对象在文件默认为局部变量,也就是说,如果你想在其它文件里使用这个const变量,你必需在定义的时候前面加

//file1.cpp
extern const int MAX_COUNT = 20; //定义和初始化并声明为extern
//file2.cpp
extern const int MAX_COUNT; //使用MAX_COUNT常量从file1.cpp文件中

 :非const变量默认是全局变量(在头文件中)。因此不需要在变量前面添加extern符号

5.引用

引用(reference)就是对象的另一个名字。在实际程序中,引用主要用作函数的形式参数。引用必需用与该引用同类型的对象初始化,如:

int ival = 1024;//ok
int &refval = ival;//ok
int &refVal2; //错误,引用必需初始化。
Int &refVal3 = 10; //错误,初始化必需是一个对象

前面说过,引用其实就是对象的别名,因此在对一个引用操作时,实质是在对引用的那个变量进行操作。

二、变量

typedef

typedef可以用来定义类型的同义词,如:

typedef double WAGES;
WAGES hourly;

枚举

默认情况下,枚举的第一个成员赋值为0,后面的每个枚举成员赋的值比前面的值大1。

enum Week{ Sun,Mon=5,Tue,Wed};

在Week枚举中,Sun默认为0,Mon = 5,Tue=6,Wed=7。

三、数组

1.数组定义和初始化

定义

int a[10];
char ch[10];
double dArray[3];

  任何数组,不论是静态声明的还是动态创建的,其所有元素在内存中都是连续字节存放的,也就是说保存在一大块连续的内存区中。

初始化

int a[4]={8,9,5,3};
int b[]={7,9,2};

  或者

int elem[3];
for(int i=0; i<3; i++)
{
  elem[i]=i+1;
}

  数组不允许直接赋值变量,因此在数组copy时要for循环数组重的每一个元素。如:

int b[]=a;//这里是不允许的

四、指针

初始化

指针进行初始化或赋值只能使用以下四种类型的值:
1)0常量表达式(请用NULL值初始化)
2)类型匹配的对象的地址
3)另一个对象之后的下一地址
4)同类型的另一个有效指针

int *p = 0; //把p指针初始化为0 
int ival=2;
p = &ival;//把p初始化为类型匹配的对象的地址
int* p2 = p; //把p2初始化为同类型的另一个有效指针

注意:避免使用未初始化的指针,很多运行时错误都源于使用了未初始化的指针。

 void*指针

C++提供了一种特殊的指针类型void*,它可以保存任何类型对象的地址,如:

double obj = 3.24;
double *pd = &obj;
void *pv = &obj;
pv = pd;

void*指针只支持几种有限的操作:与另一个指针进行比较;向函数传递void*指针或从函数返回void*指针;给另一个void*指针赋值。不允许使用void*指针操纵它所指向的对象。

指针和引用的比较

 使用引用(reference)和指针都可间接访问另一个值,但它们之间有两个重要区别。
1)引用总是指向某个对象:定义引用时没有初始化是错误的。
2)赋值行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始引用一经初始化,就始终指向同一个特定对象

指针的算术运算

#include <string>
#include <iostream>

using namespace std;

//main函数
void main()
{
	int a[6] = {36, 15, 345, 63, 43, 344};
	int *pStart = a;
	int *pEnd = pStart + 6;//指向该数组末端的下一单元

	//计算元素的个数
	int n = pEnd - pStart;
	//打印数组
	for(int i=0; i<n; i++)
	{
		cout << *pStart++ <<" ";
	}
	cout << endl;
}

指针和const限定符

1)指向const对象的指针

#include <string>
#include <iostream>

using namespace std;

//main函数
void main()
{
    double pi = 3.14;
    const double *cptr = &pi;
    //*cptr = 5;//指针不能改变其对象的值,因此是错误的
}

2)const指针

#include <string>
#include <iostream>

using namespace std;

//main函数
void main()
{
    double val = 1.4;
    double *const cptrVal = &val;
    double val2 = 2.5;

    //cptrVal = &val2;//const指针不能修改
}

五、创建动态数组

在有些情况,编译无法知道数组的大小;比如:读一个文件,这个时候我们开多大的buf来装数据呢?答案是不知道的。
因此我们需要在知道一个文件的大小后,在分配一个数组来装数据,创建动态数组就能解决这种情况。
我们可以像这样去定义,如:
int *pBuf = new int[1024];
创建动态数组,不是没有代价的,你new了一个新的数组,却没有delete掉数组,那么你就有内存泄漏的风险,因此在
不需要的时候要调用delete[] 删除数组,如:
if(pBuf)
{
   delete[] pBuf
   pBuf = NULL;
}

六、多维数组

严格地说,C++中没有多维数组,通常所指的多维数组其实就是数组的数组。
先来看看二维数组的定义和初始化,我们来看一段代码
int a[2][3];//数组的定义
int b[2][3] = {{0,1,2},{4,5,6}}; //数组的初始化
int c[2][3] = {0,1,2,3,4,5};//数组的初始化
上面的代码演示了二维数组的定义和初始化
注意,我们在使用二维数组的时候要按照“先行后列”的方式来访问,而不是先列后行。这是因为我们假设一个内存页为4096字节,并且定义一个数组b[128][1024],其
列数为1024(即每一行的元素恰好占用一页),当你用“先行后列”方式时,外层循环走过每一行,正好走完一页,没
有发生页面调度。当循环进入下一行时操作系统从外存调入下一页,因此,我们可以知道,遍历完后次数最多为128次。但是你用“先列后行”方式来遍历的话,可能在遍历完后页面调度交数变成了1024*128。这将大大降低效率

七、new和delete表达式

注意:
1)对分配的数组进行delete[]删除,不能误用成delete删除,如果用的是delete,那么只会删除数组的第1个元素内存,
后面的内存就丢失了,容易造成内存泄漏。                
2)读写已删除的对象。如果删除指针后,没有把指针置为0,那么就会造成野指针。
3)对同一个内存空间使用两个delete表达式。 当第一次删除时,对象的内存空间返还给自由存储区,当第二次删除时,此时自由存储区可能会被破坏。

八、强制类型转换

在编写程序中,难免会遇到类型转换,在C语言中用()括号来转换,C++继承了这种用法,但是它有一个明显的一个缺陷
,就是不会进行类型检测,不能保证满足转换。在C++里还提供了四种类型转换:static_cast、const_cast、
dynamic_cast以及reinterpret_cast。我们应该避免使用强制类型转换,但如果一定要用的话,推荐使用C++里的那四
种类型转换,因为它们会执行类型检测。

static_cast

可以使用static_cast显式地执行C++语言直接支持的转换。当需要将一个较大的算术赋值给较小的类型时,如:
double d = 7.8;
int  n = static_cast<int>(d);

const_cast

const_cast最为直接,是将转换掉表达式的const性质。似乎从理论上讲,一个变量是const,那么就应该一直是const。
然而实际上,有时候你会发现有这种情况,比如我们在使用第三方的库时候,示例:
extern void fun(char* str); //第三方的函数
void f(const char *str)
{
    fun(const_cast<char*>(str));
}

dynamic_cast和reinterpret_cast

dynamic为继承层次结构内的类型转换提供运行时检测
reinterpret_cast通常为操作数的位模式提供较低层次的重新解释。reinterpret_cast本质上依赖于机器。为了安全地使
用reinterpret_cast,要求程序员完全理解所涉及的数据类型,以及编译器实现强制类型转换的细节 

reinterpret_cast用于指针和引用转换,不可以对对象本身。

 

 

 

 

 

 

posted on 2013-08-25 18:27  奎哥  阅读(356)  评论(0编辑  收藏  举报