C++ Primer第四章数组和指针笔记

  1. 现代c++程序应尽量使用vector和迭代器类型,而避免使用低级的数组和指针.设计良好的程序只有在强调速度时才在类内部使用数组和指针.
  2. 数组和容器的相同点和不同点
    相同点: 都是存储单一数据类型对象的容器
    不同点:
    1)数组的长度是固定的,而且程序员无法知道一个给定数组的长度(没有获得其容量大小的size操作),也不提供push_back操作
    2)如果要更改数组的长度,只能创建一个更大的数组,然后将原数组中的元素copy过去.
  3. 数组初始化实例
int staff_size = 27;
double salaries[staff_size];   // 错误,staff_size不是一个常量

// 在函数体外定义的内置数组,其元素初始化为0
// 在函数体内定义的内置数组,其元素无初始化
const unsigned array_size = 3;
int ia[array_size] = {0,1,2};
int  ca1[] = {0,1,2};
char ca2[] = "C++";     // 维数是4,结束字符串有一个空字符
  1. 指针和迭代器的异同点
    相同点:指针和迭代器一样,提供对所指对象的间接访问
    不同点:指针指向单个对象,而迭代器只能用于访问容器内的元素.
  2. 指针使用实例
string s("hello world");
// sp保存s的地址,*sp中的*操作符表明sp是一个指针变量,&s中的&符号是取地址操作符.
string *sp = &s;
double *dp;        //定义一个指向double对象的指针dp
double* dp1, ps;        //定义一个指向double对象的指针dp1和一个double对象ps
  1. 指针可能的取值
    保存一个对象的地址、指向某个对象后面的另一对象(???没查到什么意思)、0值(表明不指向任何对象)
  2. 指针初始化和赋值操作的约束
    对指针初始化或赋值只能使用以下四种类型的值:
    1)0值常量表达式: 字面值常量0或可获得0值的整型const对象
    2)类型匹配的对象的地址
    3)另一对象之后的下一地址
    4)同类型的另一个有效指针
int ival;
int zero = 0;
const int c_ival = 0;
// 错误, 指针只能初始化为0值常量表达式
int *pi = ival;
// 错,不是const
pi = zero;
// 对
pi = c_ival;
pi = 0;
// 当在代码中使用预处理器变量,编译时会自动被数值0替换
int * pi = NULL;
double dval;
// 对
double *pd = &dval;
// 对
double *pd2 = pd;
// 错, pi和pd为不同类型的指针
int *pi = pd;
// 错,pi只能指向int类型的对象
pi = &dval;
  1. void*指针
// void*指针可以保存任何类型对象的地址,不允许使用void*指针操纵它所指向的对象
double obj = 3.14;
double *pd = &obj;
void *pv = &obj;
  1. 指针解引用操作
string s("hello world");
string *sp = &s;
// 输出hello world
cout<<*sp;
// 修改指针指向对象值
*sp = "goodbye";
string s2 = "some value";
//sp现在指向s2
sp = &s2;
  1. 指针和引用的比较
    1)引用总是指向某个对象,定义引用时没有初始化是错误的
    2)给引用赋值修改的是该引用关联的对象的值,而并不是使引用与另一个对象关联
int ival = 1024, ival2 = 2048;
int *pi = &ival, *pi2 = &ival2;
// pi现在指向ival2
pi = pi2;

int &ri = ival, &ri2 = &ival2;
//ival的值为ival2的值
ri = ri2;
  1. 指向指针的指针
int ival = 1024;
int *pi = &ival;
int **ppi = &pi;
// *ppi表示ppi所指向的对象,也是一个指针,存放的ival的地址,将该指针赋值给pi2,则pi2存放ival的地址
int *pi2 = *ppi;
  1. 使用指针访问数组元素
// 在表达式中使用数组名时,该名字会自动转换为指向数组第一个元素的指针
int ia[] = {0,2,4,6,8};
// 下面两种等价
int *ip = ia;
int *ip = &ia[0];
// 下面两种等价,指向ia[4]
int *ip2 = ip + 4;
int *ip2 = ia + 4;
// 对ia+4解引用,结果为8
int last = *(ia + 4)
  1. 下标和指针
// 当对数组名操作时,实际上使用的是指向数组第一个元素的指针
int ia[] = {0,2,4,6,8};
int i = ia[0];        // 0
int *p = &ia[2];      
int j = p[1];         // 6
int k = p[-2];        // 0
  1. 指向const对象的指针
    如果指针指向const对象,则不允许用指针来改变其所指的const值,为了保证这个特性,c++要求指向const对象的指针页必须是const的.
// cptr指针指向的对象是const的,cptr并不是const,有点有悖直觉.
const double *cptr;
*cptr = 42;        //错,cptr指针指向的对象是const的,不能再赋值了
const double pi = 3.14;
double *ptr = &pi;     // 错,pi不是const
const double *cptr = &pi;
void *pv = &pi;        // 错,前面应该加上const
// 允许非const对象的地址赋给指向const对象的指针
// 尽管dval不是const对象,但是任何企图指针cptr修改其值的行为都会导致编译的错误
double dval = 3.14;
cptr = &dval;
*cptr = 3.1415;       // 错
dval = 3.1415;        // 对,dval不是const,修改其值只要不通过指向const对象的指针cptr修改就好
  1. const指针
int errNumb = 0;
const int errNumb1 = 0;
// const指针的定义
int *const curErr = &errNumb;
// 指针是const,指向的对象也是const
const int *const curErr1 = &errNumb1;

typedef string *pstring;
// cstr为指向string对象的const指针
const pstring cstr;
  1. 动态数组的定义
// string类类型,该处初始化为null
string *psa = new string[10];
// 内置类型,无初始化
int *pia = new int[10];
// 加(),则数组元素全部初始化为0
int *pia = new int[10]();
// new表达式返回的是指向新分配数组的第一个元素的指针,所以以下这种写法错误
int pia = new int[10];
// 不能定义长度为0的数组
char arr[0];
// 能够被创建,但是不能进行解引用操作,因为没有指向任何元素
char *cp = new char[0];
// 释放pia指向的数组的内存空间,[]不能少,它告诉编译器该指针指向的是自由存储区的数组,而非单个对象
delete [] pia;

  1. 使用数组初始化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);
  1. 指针与多维数组
int ia[3][4];
// ip是一个指向含有四个元素的数组的指针,ia默认是指向第一层数组的指针
int (*ip)[4] = ia;
// ip指向第二层数组
ip = &ia[2];
typedef int int_array[4];
// 下面两个等同
int_array *ip = ia;
int (*ip)[4] = ia;
发布了89 篇原创文章 · 获赞 0 · 访问量 1030

猜你喜欢

转载自blog.csdn.net/qq_26496077/article/details/103944802