«

[C++Primer学习笔记]第4章 数组和指针

1、现代C++程序中应尽量使用vector和迭代器类型,而避免使用低级的数组和指针。设计良好的程序只有在强调速度时才在类实现的内部使用数组和指针。

2、与vector类型相比,数组的显著缺陷在于:数组的长度是固定的,而且程序员无法知道一个给定数组的长度。数组没有获取其容器大小的size操作,也不提供push_back操作在其中自动添加元素。如果需要更改数组的长度,程序员只能创建一个更大的新数组,然后把原数组的所有元素复制到新数组空间中去。

3、数组的维数必须用值大于等于1的常量表达式定义。
常量表达式包括:

  1. 整型字面值常量。
  2. 枚举常量
  3. 用常量表达式初始化的整型const对象

4、在函数体外定义的内置数组,其元素初始化为0;在函数体内定义的内置数组,其元素无初始化。

5、显示初始化的数组不需要指定数组的维数值,例如:

int ia[] = {0, 1, 2};

6、字符数组既可以用一组由花括号括起来、逗号隔开的字符字面值进行初始化,也可以用一个字符串字面值进行初始化。但,使用字符串字面值会包含一个额外的空字符(null)用于结束字符串。

7、与vector不同,一个数组不能用另外一个数组初始化,也不能将一个数组的值赋给另一个数组。

8、程序员在使用数组时,必须保证其下标值在正确范围之内,即数组在该下标位置对应一个元素。除了程序员自己注意细节,并彻底测试自己的程序之外,没有别的办法可以防止数组越界。

9、指针用于指向对象,它存放了对象的地址。

10、很多运行时错误都源于使用了未初始化的指针。如果可能的话,除非所指向的对象已经存在,否则不要先定义指针,这样可以避免定义一个未初始化的指针。如果必须分开定义指针和其所指向的对象,则将指针初始化为0。因为编译器可检测出0值的指针,程序可判断该指针并未指向一个对象。

11、对指针进行初始化或赋值只能使用一下四种类型的值:

  1. 0值常量表达式
  2. 类型匹配的对象的地址
  3. 另一个对象之后的下一个地址
  4. 同类型的另一个有效地址

12、把int型变量赋给指针是非法的,尽管此int型变量的值可能为0。但允许把数值0或者编译时可获得0值得const量赋给指针。

13、void*指针,它可以保存任何类型对象的地址。但只支持以下几种操作:

  1. 与另一个指针进行比较
  2. 向函数传递void指针或从函数返回void指针
  3. 给另一个void*指针赋值

14、不允许使用void*指针操纵它所指向的对象。

15、指针与引用

  1. 共同点:它们都可以间接访问另一个值
  2. 差异:引用总是指向某个对象,定义引用时没有初始化是错误的。给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化,就始终指向同一个特定的对象。

16、指针的算术操作只有在原指针和计算出来的新指针指向同一个数组的元素,或指向该数组存储空间的下一个单元时才是合法的。

17、两个指针减法操作的结果是标准库类型 ptrdifft 的数据。与 sizet类型一样, ptrdifft 也是一种与机器相关的类型,在 cstddf 头文件中定义。sizet 类型是 unsigned 类型,而 ptrdiff_t 是 signed 整型。

18、指向const对象的指针与const指针

1. const int *A;//const修饰指向的对象,A可变,A指向的对象不可变 
2. int const *A; //const修饰指向的对象,A可变,A指向的对象不可变 
3. int *const A; //const修饰指针A, A不可变,A指向的对象可变 
4. const int *const A;//指针A和A指向的对象都不可变

19、不能使用void指针保存const对象的指针,必须使用const void类型的指针保存const对象的指针。

20、指针与typedef。

typedef string *pstring;
const pstring cstr;
等于
string *const cstr;

21、 C风格字符串既不能确切地归结为C语言的类型,也不能归结为C++语言的类型,而是以空字符null结束的字符数组。

char ca1[]={'C', '+', '+'};    // no null, not C-style string  
char ca2[]={'C', '+', '+', '\0'};     // explicit null  
char ca3[]="C++";           // null terminator addedautomatically  
const char *cp="C++";   // null terminator added automatically  
char *cp1=ca1;      //points to first element of a array, but not C-style string  
char *cp2=ca2;      //points to first element of a null-terminated char array  

C++语言通过(const)char*类型的指针来操作C风格字符串。

22、C风格字符串的标准库函数。C++语言通过(const)char*类型的指针来操作C风格字符串。

strlen(s)                    // 返回s的长度,不包括字符串结束符null  
strcmp(s1, s2)          //当s1<s2时,返回值<0 ,当s1=s2时,返回值=0,当s1>s2时,返回值>0  
strcat(s1, s2)            // 将字符串s2连接到s1后,并返回s1  
strcpy(s1, s2)           // 将s2复制给s1,并返回s1  
strncat(s1, s2, n)     // 将s2的前n个字符连接到s1后面,并返回s1  
strncpy(s1, s2, n)    // 将s2的前n个字符复制给s1,并返回s1  

23、在使用处理C风格字符串的标准库函数时,牢记字符串必须以结束字符null结束。

24、传递给标准库函数strcat和strcpy的第一个实参数组必须具有足够大的空间存放新生成的字符串。

25、如果必须使用C风格字符串,则使用标准库函数strncat 和 strncpy 比 strcat和 strcpy 函数更安全,因为前者可以适当控制复制字符的个数。特别是在复制和串联字符串时,一定要时刻记住算上结束符null。

26、尽可能使用标准库类型 string,除了增强安全性外,效率也提高了,因此应该尽量避免使用C风格字符串。

27、整型类型的变量有三个重要的限制:

  1. 数组长度固定不变
  2. 在编译时必须知道其长度
  3. 数组只在定义它的快语句内存在

28、每一个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区(free store)或堆(heap)。C语言程序使用一堆标准库函数malloc和free在自由存储区中分配存储空间,而C++语言则使用new和delete表达式来实现其功能。例如:

int *pia = new int[10];
delete [] pia;

29、动态分配数组的初始化
1)如果数组元素具有类类型,将使用该类的默认构造函数实现初始化
2)如果数组元素是内置类型,则无初始化,但可以在后面加圆括号,进行初始化,例如

int *pia = new int[10];(把数组元素都设置为0)。

30、如果动态分配内置类型的const对象数组,必须初始化。如果是类类型,必须提供默认构造函数。

31、动态分配时允许分配空数组。

32、可以使用C风格字符串对string对象进行初始化或赋值,却无法使用string对象初始化字符指针。但我们可以通过string类的c_str成员函数来实现:

string str2("hello");
char *str = st2.c_str();

33、cstr 返回的数组并不保证一定是有效的,接下在对st2的操作有可能会改变str2的值,使刚才返回的数组失效。如果程序需要持续访问该数据,则应该复制 cstr 函数返回的数组。

34、C++允许使用数组初始化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);

35、严格地说,C++中没有多维数组,通常所指的多维数组其实就是数组的数组。

36、指针数组和指向数组的指针

1)int*ip[4];      // array of pointers to int
2)int(*ip)[4];   // pointer to array of 4 ints

37、用 typedef 简化指向多维数组的指针

int ia[3][4];
typedef int int_array[4];
int_array  *ip = ia;
输出ia的元素:
for(int_array *p = ia; p!=ia+3; p++)
for(int *q = *p; q!= *p+4; q++)
cout<<*q<<endl;
分享