大二寒假读书笔记150203

来源:互联网 发布:手机淘宝怎么提交改价 编辑:程序博客网 时间:2024/04/26 07:59

1、C风格字符串

字符串字面值的类型就是const char类型的数组。C++从C语言继承下来的一种通用结构C风格字符串,而字符串字面值就是该类型的实例。实际上,C风格字符串既不能确切的归结为C语言的类型,也不能归结为C++语言的类型,而是以空字符Null结束的字符数组。

char ca1[] = {'C','+','+'};//no null,not C-style stringchar ca2[] = {'C','+','+','\0'};//explicit nullchar ca3[] = "C++";//自动加nullconst char *cp = "C++";//自动加nullchar *cp1 = ca1;char *cp2 = ca2;
数组的名字即是指向该数组第一个元素的指针。

2、C++语言通过(const)char*类型的指针来操控C风格字符串。一般来说我们使用知怎的算术操作来遍历C风格字符串,每次对指针进行测试并递增1,直到到达结束符null为止。

const char *cp = "some value";while(*cp){    //do something    ++cp;}
真值表明这是除了null外的任意字符,则继续循环直到cp指向结束字符数组的null时,循环结束。

如果cp所指向的字符数组没有null结束符,则此循环将会失败。

3、要使用处理C风格字符串的库函数必须包含相应的C头文件

#include<cstring>
cstring是string.h的C++版本。

strlen(s)  //返回s的长度,不包括字符串结束符nullstrcmp(s1,s2)  //s1大返回正数,s2大返回负数strcat(s1,s2)  //将字符串s2连接到s1后,并返回s1strcpy(s1,s2)  //将s2复制给s1并返回s1strncat(s1,s2,n)  //将s2的前n个字符连接到s1后面,并返回s1strncpy(s1,s2,n)  //将s2的前n个字符复制给s1,并返回s1
C++语言提供普通的关系操作符实现标准可类型string的独享的比较。这些操作符也可用于比较比较C风格字符串的指针,但效果却很不相同:实际上,此时比较的是指针上存放的地址值,而非它们所指向的字符串:

if(cp1 < cp2)//compares addresses not the values pointed to
如果cp1和cp2指向同一数组中的元素(或该数组的溢出位置),上述表达式等效于比较在cp1和cp2种存放的地址;如果这两个指针指向不同的数组,则该表达式实现的比较没有定义。

4、调用者必须保证目标字符串具有足够的大小

传递给标准可函数strcat和strcpy的第一个实参数组必须具有足够大的空间存放新生成的字符串。以下代码虽然演示了一种通常的用法,但是却有潜在的严重错误:

const char *cp1 = "A string example";const char *cp2 = "A different string";char largeStr[16+18+2];strcpy(largeStr,cp1);strcat(largeStr," ");strcat(largeStr,cp2);cout<<largeStr<<endl;
问题在于我们经常会算错largeStr需要的大小。同样的,如果cp1或cp2指向的字符串大小变化,laregStr所需要的大小将会计算错误。

5、使用strn函数处理C风格字符串

如果必须使用,则使用标准库函数strncat和strncpy比较安全

char largeStr[16+18+2];strncpy(largeStr,cp1,17);//cp1中的16个字符加上null结束符strncat(lareStr," ",2);//空字符加上null结束符strncat(largeStr,cp2,19);//cp2的18个字符加上null结束符

在使用strn函数时,必须记得加上null结束符,在定义时也要留出空间来存放它。值得注意的是,在第一次调用strncat时,原来用于结束largeStr的null字符被空字符覆盖了,然后在空格后面写入新的结束符null。

整个过程中,存储largeStr的数组大小始终保持为36(包括null结束符)。

只要可以正确计算出strn中的n值,使用strn版本要比没有n参数的要安全的多。如果要复制或串接的字符串比实际要复制或串接的size大,我们会不经意的把新生成的字符串截短。截短字符串比数组溢出要安全,但这仍是错误的,而使用标准库类型string就不存在这种问题。

6、实际的程序需要在运行时动态的分配数组,虽然数组长度是固定的,但是动态分配的数组却不比在编译时知道其长度,通常是在运行时才确定数组长度。不过与数组变量不同,动态分配的数组将一直存在,直到程序显式释放它为止。下面是原理:

每一个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区(free store)或堆(heap).

动态分配数组时,只需指定类型和数组长度,不必为数组对象明明,new表达式返回指向新分配数组的第一个元素的指针。

int *pia = new int[10];
new表达式需要指定的数组维数可以是任意的复杂表达式。创建数组后,new将返回数组第一个元素的指针。在自由存储区中创建的数组对象是没名字的,程序猿之恩那个通过其地址间接地访问堆中的对象。

动态分配数组是,若元素是是类类型,将使用该类的默认构造函数;是内置类型则无初始化。

string *psa = new string[10];//10 empty stringsint *pia = new int[10];//10 uninitialized ints

第一个数组是string类型,分配了保存对象的内存空间后,将调用string类型的默认构造函数一次初始化数组中的每个元素。第二个int型数组就只分配不初始化。

也可使用跟在数组长的都后面的一对空圆括号对数组元素进行初始化:

int *pia2 = new int[10]();//array of 10 uninitialized
圆括号要求编译器对数组做值初始化,在本例中即把数组元素都设置为0(在mingw5的IDE上不成功,无法正常输出)。

用于动态分配的数组,其元素只能初始化为元素类型的默认值,而不能像数组变量一样,用初始化列表为数组元素提供各不相同的初值。

如果我们在堆中创建的数组存储了内置类型的const对象,则必须为这个数组初始化:

const int *pci_bad = new int[10];//errorconst int *pci_ok = new int[10]();//ok
如果是类类型的const对象则会自动调用它的默认构造函数。

实际意义不大。

7、允许动态分配空数组

size_t n = get_size();int *p = new int[n];for(int *q = p;q != p + n;++q){....}

如果size_t返回的是0仍然是对的,

char arr[0];//书上说是错的,在vc6.0是对的char *cp = new char[0];//ok
用new动态创建长度为0的数组时,new返回有效的非零指针,但不能进行解引用操作。允许:比较运算,用于循环、加(减)0、减去本身,得0值。

8、动态分配的数组最后必须显式释放掉

delete [] pia;
释放掉pia所指向的数组,把相应的内存还给自由存储区。切记不要忘掉[].

9、新旧代码兼容

string s3("hello world");char *str1 = s3;//errorchar *str2 = s3.c_str();//almost ok,but not quite

事实上,上面最后一条语句根本就是错误的。s.c)str()返回的是C风格字符串,返回指向字符数组首地址的指针,该数组存放了与s相同的内容并以null结束。

因为c_str()返回的指针指向const char*类型的数组,所以初始化失败。下面的才正确:

const char *str = s3.c_str();

10、C++允许使用数组初始化vector对象。使用数组初始化vector对象,必须指出用于初始化式的第一个元素及数组最后一个元素的下一位置的地址:

const size_t arr_size = 6;int int_arr[arr_size] = {0,1,2,3,4,5};vector<int> ivec(int_arr,int_arr+arr_size);//each onevector<int> ivec(int_arr+1,int_arr +4);//int_arr[1]、int_arr[2]、int_arr[3]

11、严格的说,C++中没有多维数组,通常所指的多维数组其实就是数组中的元素类型是数组。

与普通数组一样,使用多维数组名时,实际上将其自动转换为指向该数组第一个元素的指针。因为多维数组其实就是数组的数组,所以有多维数组转换而成的指针类型应是指向第一个内层数组的指针。

int ia[3][4];int (*ip)[4] = ia;ip = &ia[2];
定义指向数组的之痕与如何定义数组本身类似:首先声明元素类型,后接(数组)变量名字和维数。窍门在于(数组)变量的名字其实是指针,因此需在标识符前加上*。如果从内向外阅读ip的声明,可理解为:*ip是int[4]类型——即ip是一个指向含有4元素数组的指针(还是晕。。)

0 0
原创粉丝点击