《C++Primer》数组 指针 表达式 语句

● 定义数据时,不能使用运行才能确定的大小。

const int arraySize = 3;

int arr[arraySize];

 

● char ch[6] = “daniel”;        //error:Deniel is 7 elements

 

● 不允许数组直接复制和赋值。

int ia = {0,1,2};

int ia2[](ia);          //error:array of ints

 

● 数组下标的正确类型是size_t

 

● string *sp1,sp2;             //sp1 is a pointer to string,ps2 is a string

   string *sp1,*sp2;           //both sp1 and sp2 are pointers to string

 

● 避免使用未初始化的指针。   int *pi = NULL;

 

● C++提供了一种特殊的指针类型void*,它可以保存任何类型对象地址。不允许使用void*指针操纵它所指向的对象。

 

● 引用和指针的比较:

1.引用总是指向某个对象:定义引用没有初始化是错误的。

2.给引用赋值修改的是该引用所关联的对象的值,而不是使引用与另一个对象关联。

PS:

int ival = 1024,ival = 2048;

int *pi = &ival, *pi2 = &ival2;

pi = pi2;

pi所指向的对象的值不变,但是指向了另一个不同的对象。

int &ri = ival, &ri2 = ival2;

ri = ri2;

这个赋值操作修改了ri引用的值,而不是引用本身。赋值后这两个引用还是分别指向原来关联的对象,此时这两个对象的值相等。

 

● 指向指针的指针:   int ival = 1024; int *p1 = &ival; int **p2 = &p1;

 

● 指针访问数据:

int ia[] = {0,2,4,6,8};

int *ip = ia;             //ip opints to ia[0]

int *ip2 = ip + 4;    //ip2 points to ia[4];

ptrdiff_t n = ip2 – ip;

 

int last = *(ia+4);   //last = 8;

last = *ia + 4;         //last = 4;

 

int ia[] = {0,2,4,6,8};

int *p = &ia[2];

int k = p[-2];    //k = ia[0];

 

for(int *pbegin = ia, *pend = ia + arrSz; pbegin != pend; ++pbegin)

 

● C++语言强制要求指向const对象的指针也必须具有const特征,不能使用指向const对象的指针修改基础对象,指向const的指针(自认为指向const的指针,可以不指向const对象,但也不能修改对象的值);

const double *cptr;

 

const指针。 (指针本身的值不能修改)

int errNum = 0;

int *const curErr = &errNum;

 

指向const对象的const指针:

const double pi = 3.1415926;

const double *const ptr = π

不能修改指针本身,也不不能修改指针指向的对象的值。

 

typedef string *pstring;

const pstring cstr;

cstr是指向string类型的const指针。

string *const cstr;

而不是const string *cstr;因为const修饰的是pstring,它是一个指针。

 

● 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

 

char str[16+18+2];

strncpy(str,cp1,17);

strncpy(str,” ”,2);

strncpy(str,cp2,19);

 

● 创建动态数组:

int *pia = new int[10];    //没有初始化

int *pia = new int[10]();    //调用默认构造函数初始化

 

const int *pia = new const int[10]]();

const string *pis = new const string[10];

 

size_t n = getSize();

int *p = new int[n];

 

char arr[0];     //error:  cannot define zero-length array

char *cp = new char[0];    //ok:but cp cannot be dereferenced

 

delete []pia;

 

● string str(“hello world”);

  const char *str2 = str.c_str();          //返回C风格字符串

 

vector<int> ivec(int数组名,数组名+数组大小);

 

● int ia[3][4];

   int (*ip)[4] = ia;     //ip points to an array of 4 ints;

   ip = &ia[2];          //ia[2] is an array of 4 ints;

 

int *ip[4];    //array of points to int;

int (*p)[4];    //points to an array of 4 ints

 

typedef int arr[4];

arr *ip = ia;

 

● 如果两个操作数为正,除法和求模操作的结果也是正数;如果两个操作数为负,除法操作的结果为正数,而求模操作的结果为负数。如果只有一个操作数为负数,这两种操作的结果取决于机器;求模结果的符号也取决于机器,而除法操作的值则是负数或0.

 

● 逻辑与和逻辑或操作符总是先计算其左操作数,然后再计算其右操作数。只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数。我们常称这种求值策略为“短路求值”。

 

● if(i < j <k)  {}              这种只要k大于1就为true。(i < j)返回0或1

   if(i < j && j < k)  {}      这种才能求得正确的结果

 

● 左移操作符(<<)在右边插入0以补充空位。对于右移操作符(>>),如果其操作数是无符号数,则从左边开始插入0,如果操作 数是有符号数,则插入符号位的副本或者0。

 

● cout<<(10 < 40);    //print 1

   cout<<10 < 40   //error

  int ival, jval;

ival = jval = 0;

 

● 为了防止手误,我们用if(42 == i)代替if(i == 42) .因为if(i = 42) 不同于与 if(i == 42)

 

● 因为前置操作需要做的工作更少,只需加1后返回加1后的结果即可。而后置操作符必须先保存操作符原来的值,以便返回未加1之前的值作为操作的结果。因此,养成使用前置操作这个好习惯,就不必担心性能差异的问题。

 

● sizeof操作符的作用是返回一个对象或类型名的长度,返回值的类型为size_t

1.对 char类型或值为char类型的表达式做sizeof操作保证得1。

2.对引用类型做sizeof操作将返回存放此引用类型对象所需的内存空间大小。

3.对指针做sizeof操作将返回存放指针所需的内存大小;注意,如果要获取该指针所指向对象的大小,则必须对指针进行解引用。

4.对数组做sizeof操作等效于将对元素类型做sizeof操作的结果乘以数组元素的个数。int sz = sizeof(ia) / sizeof(*ia);

 

● C++操作符的优先级

image

 

● 求值顺序:

if(ia[index++] < ia[index])    //C++语言不能确保从左到右的计算次序,所以有两种情况  index = 0

if(ia[0] < ia[0])  或 if(ia[0] < ia[1])

 

● int *pi = new int;     //pi points to an uninitialized int

   int *pi = new int();      //pi points to an int value-initialized to 0

 

如果指针指向不是new分配的内存地址,则在该指针上使用delete是不合法的。

一旦删除了指针所指向的对象,立即将指针置为0.

● 显式转换:

static_cast、dynamic_cast、const_cast、reinterpret_cast

dynamic_cast 支持运行时识别指针或引用所指向的对象。

const_cast 将转换掉表达式的const性质。转换掉!

static_cast 编译器隐式执行的任何类型转换都可以由static_cast显式完成。

reinterpret_cast 通常为操作数的位模式提供较低层次的重新解释。

应该避免使用强制类型转换。

 

● 空语句也是一个语句。

   ival = v1 + v2;;              一条表达式语句,一条空语句

 

● 存在一个普遍的误解:以为程序只会执行匹配的case标号相关联的语句。实际上程序从该点开始执行,并跨越case边界继续执行其他语句,直到switch结束或遇到break语句为止。

 

● 对于switch结构,只能在它的最后一个case标号或default标号后面定义变量:

如果在两个case标号之间定义变量,该变量会在块结束之前一直存在,对于定义该变量的标号后面的其他case标号,他们所关联的代码都可以使用这个变量。如果switch从那些后续case标号开始执行,那么这个变量可能还未定义就要使用了。

在这种情况下,如果需要为某个特殊的case定义变量,则可以引入语句块,在该块语句中定义变量,从而保证这个变量在使用前被定义和初始化。

case true:

{

   string fileName;

   ……….

}

 

● 在for语句头定义的任何对象只限制在for循环体里可见。

 

● 标准异常类

image

● assert断言

如果为false,assert输出信息,并且终止程序的执行。如果为true,则不采取任何操作。

 

 

这篇结束~~~

 

BY:AloneMonkey

本文链接:http://www.alonemonkey.com/cplus-review-two.html