一、复习const,string,vector,函数顺序容器相关知识,回答以下问题。最终结果请以博客形式给出。
1.指针和引用的异同。试举例说明。(概念/使用)
指针是:保存的是一个对象的地址
引用:对象的另一个名字,初始化是指明引用指向哪个对象的唯一名字;
具体参见:http://www.cnblogs.com/kingln/articles/1129114.html book :P51
2.const:const与基本类型,const与指针,const与引用,const+指针+typedef,const+对象,const+对象+指针。
const与基本类型
有些不想被修改的数据就定义为const型,const型在定义后不能被修改,且在定义时必须进行初始化
文件b想使用文件a中的const对象时,必须在文件a中定义该对象为:externconst int bufSize=XX;
const与引用:是指向const对象的应用;
如
const int ival=1024;//const对象
const int &refVal=ival;//refVal是指向const对象的引用
const与指针
指向 const 对象的指针(指针所指的对象是const对象)/
如:const double *cptr; 不能把const对象的地址赋值给一个不是定义为“const对象的指针”
const指针(这个指针本身是const类型的,本身的值不能被修改)/
如:
int errNumb = 0;
int *const curErr=&errNumb;
指向const对象的const指针(指针是const类型,该指针所指向的对象也是const类型,即,1,不能修改该指针的值;2,不能修改指针所指的对象);
如:
const double pi=3.1415;
const double *const pi_str=π
const+指针+typedef
易搞错的一个问题:
typedef string *pstring;
const pstring cstr;
什么意思?错误理解成了const string * cstr(指向string类型const对象的指针,error 原因是把typedef当做文本扩展了)
正确的理解是:const修饰的是pstring类型,这是一个指针,把cstr定义为指向string类型对象的const指针。等价于:string *const cstr。
const+对象
const+对象+指针
3.string:几种初始化对象方式,各种操作(函数)。
string初始化方式:
string s1; //默认构造函数,S1为空串;
string s2(s1); //将s2初始化为s1的一个副本;
string s3("value"); //将s3初始化为一个字符串字面值副本;
string s4(n,'c'); //将s4初始化为字符'c'的n个副本;
string的各种操作函数:
s.empty() 如果s为空串则返回true,否则返回false
s.size() 返回s中字符的个数
s[n] 返回s中位置为n的字符,位置从0开始计数
s1+s2 把s1和s2连成一个新的字符串,返回新生成的字符串
s1=s2 s1内容替换为s2的副本
s1==s2 比较v1和v2的内容,相等则为true,否则为false
!=,<,<=,>和>= 保持这些操作符惯有的意义。
4.vevtor:定义,操作,vector与迭代器。
vector定义理解
vector称为容器,包含很多对象,每个对象都有一个对应的整数索引值,一个容器的所有对象必须是同一种类型的。
它不是一种数据类型,而是一个类模板,用来定义任意多种数据类型。vector类型的每一种都制定了其保存元素的类型,因此vector<int>和vector<string>都是数据类型。
初始化的方式:
vector<T> v1; vector保存类型为T的对象,默认构造函数v1为空
vector<T> v2(v1); v2是v1的一个副本
vector<T> v3(n,i); v3包含n个值为i的元素
vector<T> v4(n); v4含有值初始化的元素的n个副本
vector的相关操作函数
v.empty() 如果v为空则返回true,否则返回false
v.size() 返回v中元素的个数
v.push_back(t) 在v的末尾增加一个值为t的元素
v[n] 返回v中位置为n的元素
v1=v2 v1内容替换为v2中元素的副本
v1==v2 比较v1和v2的内容,相等则为true,否则为false
!=,<,<=,>和>= 保持这些操作符惯有的意义。
vector和迭代器除了使用下标来访问vector对象的元素外,还有另一种使用迭代器来访问元素的方法:迭代器(一种检查容器内元素并遍历元素的数据类型)
容器的iterator类型
vector<int>::iterator iter; //定义了一个名为iter的变量,它的数据类型是由vector<int>定义的iterator类型,*iter解引用操作符来访问迭代器所指向的元素。
迭代器使用自增操作符向前移动迭代器指向容器中下一个元素。++iter
5.操作符:箭头‘->’操作符与点‘.’操作符的关系,操作符优先级。
箭头操作符--> 包含点操作符和解引用操作符
通过一个例子来说明:
解引用的优先级低于点操作符
(*p).foo;
p->foo 这两个是等价的,点操作符用于获取对象的成员,对指针进行解引用获取指针所指向的对象。所以,p是一个指针,*p获取了p所指的对象,(*p).foo,获取该对象的foo成员,如此复杂的关系通过-->便可实现。
操作符的优先级表:《C++ primer》第四版 p147
6.C语言和C++语言动态内存分配各采用什么方式,有何异同?????
7.函数:参数传递(非引用形参,指针形参,const形参,引用形参)各自的使用方式及特点
非引用形参:通过复制对应的实参实现初始化,所以传递入函数中,函数内部的变化不会影响本身的变化;
指针形参:函数的形参时指针,复制实参指针,与其他非引用类型的形参一样,该类型参的任何改变也仅作用于局部副本。如果函数将新指针赋给形参,主调函数使用的实参指针的值没有改变。
const形参:
引用形参:引用形参直接关联到所绑定的对象,而并非这些对象的副本。使用引用形参返回额外信息;是利用const引用避免赋值。
引用类型的一个例子:
void swap(int &v1,int &v2)
{
int tmp=v2;
v2=v1;
v1=tmp;
}
8.内联函数(定义,何时使用?)重载函数(定义,几种方式?如参数个数不同。)
内联函数:定义:内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。编译时,类似宏替换,使用函数体替换调用处的函数名。一般在代码中用inline修饰,但是能否形成内联函数,需要看编译器对该函数定义的具体处理。
使用:内联扩展是用来消除函数调用时的时间开销。它通常用于频繁执行的函数。 一个小内存空间的函数非常受益。
如果没有内联函数,编译器可以决定哪些函数内联 。程序员很少或没有控制哪些职能是内联的,哪些不是。 给这种控制程度,作用是程序员可以选择内联的特定应用 。
引入内联函数的目的是为了解决程序中函数调用的效率问题 重载函数定义:出现在相同作用域的两个函数,如果具有相同的名字而形参表不同,则称为重载函数;觉得比较好好的解释:函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。
几种方式:有个例子来理解:
#include<iostream> using namespace std; void print(int i) { cout<<"print a integer :"<<i<<endl; } void print(string str) { cout<<"print a string :"<<str<<endl; } int main() { print(12); print("hello world!"); return 0; }
9.指向函数的指针(用法以及意义)
bool (*pf)(const string &,const string &);
这个语句将pf声明为指向函数的指针,它所指向的函数带有两个const string&类型的形参和bool类型的返回值。可以用指针变量指向整形变量、字符串、数组、结构体、也可以指向一个函数。一个函数在编译时被分配一个入口地址。这个入口地址就称为函数指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。指向函数的指针变量的一般定义形式为:数据类型 (*指针变量名)(函数参数列表)
这里数据类型就是函数返回值的类型
通过一个例子就知道怎么用了:#include <stdio.h> #include <stdlib.h> int main() { int max(int,int); int (*p)(int,int); int a,b,c; p = max; scanf("%d,%d",&a,&b); c = (*p)(a,b); printf("a=%d,b=%d,max=%d\n",a,b,c); return 0; } int max(int x,int y) { int z; if(x>y) z = x; else z = y; return(z); }
main函数中的" c = max(a,b); " 包括了一次函数的调用。每一个函数都占用一段内存单元。因此,可以用一个指针变量指向一个函数,通过指针变量来访问它指向的函数。第7行:int (*p)( int,int ); 用来定义 p 是一个指向函数的指针变量,该函数有两个整形参数,函数值为整形。注意 *p 两侧的括号不可省略,表示 p 先与 * 结合,是指针变量,然后再与后面的 ( ) 结合,表示此指针变量指向函数,这个函数值 (即函数的返回值) 是整形的。如果写成 int *p ( int,int ) ,由于( )的优先级高于 *,它就成了声明一个函数P( 这个函数的返回值是指向整形变量的指针)。
赋值语句 p = max ; 作用是将函数 max 的入口地址赋给指针变量p。和数组名代表数组首元素地址类似,函数名代表该函数的入口地址。这时 p 就是指向函数 max 的指针变量,此时 p 和 max都指向函数开头,调用 *p 就是调用 max 函数。但是p作为指向函数的指针变量,它只能指向函数入口处而不可能指向函数中间的某一处指令处,因此不能用 *(p + 1)来表示指向下一条指令。
10.IO标准库类型的分类,各自主要针对何种情况,分别编写示例说明。
IO类型在三个独立的头文件中定义:iostream定义读写控制窗口的类型,fstream定义读写已命名文件的类型,sstream所定义的类型用于读写存储在内存中的string对象。表 IO标准库类型和头文件
头文件 类型 iostream istream 从流中读取 ostream 写到流中去 iostream对流进行读写,从istream和ostream派生而来 fstream ifstream 从文件中读取,由istream派生而来 ofstream 写到文件中去,由ostream派生而来 fstream 读写文件, 由iostream派生而来 sstream istringstream从string对象中读取,由istream派生而来 ostringstream写到string对象中去,由ostream派生而来 stringstream 对string对象进行读写, 由iostream派生而来 举例问题以后用到以后补充;
11.顺序容器的几种类型,各自主要针对什么操作。构造函数都有哪几种方式?如何约束容器内元素的类型?各自的迭代器及相应的迭代器运算都是什么?顺序容器常用的操作有?
容器类共享部分公共接口。标准库定义的三种顺序容器类型:vector、list、deque(double-ended queue的缩写,发音为“deck”),它们的差别仅在访问元素的方式,以及添加或删除元素相关操作的代价。顺序容器适配器包括:stack、queue和priority_queue。容器只定义了少量操作,大多数操作由算法库提供。如果两个容器提供了相同的操作,则它们的接口(函数名和参数个数)应该相同。 vector 容器,支持快速随机访问(连续存储) list 链表,支持快速插入/删除 deque 双端队列,支持随机访问(连续存储),两端能快速插入和删除 stack 栈 queue 队列 priority_queue 优先级队列顺序容器的构造和初始化 下面的顺序容器C可以为vector、list和deque类型。 C<T> c; 创建一个空容器;适用于所有容器。 C<T> c2(c); 创建容器c的副本;适用于所有容器。 C<T> c(b, e); 用迭代器[b, e)范围内的元素构造容器;适用于所有容器。 C<T> c(n); 创建有n个值为默认的元素的容器;仅适用于顺序容器。 C<T> c(n, t); 创建有n个值为t的元素的容器;仅适用于顺序容器。 注意:在将一个容器复制到另一个容器时,类型必须匹配,容器类型和元素类型必须相同。 容器元素的类型约束 对于所有容器,容器元素类型必须满足以下约束条件: 1)元素类型必须支持赋值运算; 2)元素类型的对象必须可以复制。迭代器及其范围 下表为迭代器为所有容器类型所提供的运算: *iter 返回类型iter所指向的元素的引用 iter->mem 对iter进行解引用,并取得指定成员 ++iter 给iter加1,使其指向容器中下一个元素 iter++ --iter 给iter减1,使其指向容器中前一个元素 iter-- iter== iter2 当两个迭代器指向同一个容器中的同一元素,或者当它们都指向同一个容器的超出末端的下一个位置时,两个迭代器相等。 iter1!=iter2 vector和deque容器的迭代器提供了额外的运算:迭代器的算术运算和另一些关系运算,如下表所示: iter + n 在迭代器上加(减)整数值,将产生指向容器中前面(后面)第n个元素的迭代器; iter - n 新计算出来的迭代器必须指向容器中的元素或超出容器末端的下一位置。 iter1 += iter2 复合运算:先加(减),再赋值 iter1 -= iter2 iter1 - iter2 只适用于vector和deque >, >=, <, <= 比较迭代器的位置关系;只适用于vector和deque 关系操作符只适用于vector和deque容器,这是因为只有这两种容器为其元素提供快速、随机的访问。它们确保可根据元素位置直接有效地访问指定的容器元素。这两种容器都支持通过元素位置实现的随机访问,因此它们的迭代器可以有效地实现算术和关系运算。 迭代器范围:[first, last)是一个左闭合区间,表示范围从first开始,到last结束,但不包括last。注意:如果first不等于last,则对first反复做自增运算必须能够到达last;否则,即last位于first之前,则将发生未定义行为。 迭代器范围使用左闭合的意义:因为这样可以统一表示空集,就无需特别处理。 另外,使用迭代器时,要特别留意迭代器的可能的失效问题。
二、
C++primer:
学习关联容器的相关知识。主要包括:关联容器的类型,构造函数都有哪几种方式?如何约束容器内元素的类型?常用的操作有?最后自己实现本章的文本查询程序。
C++程序设计原理与实践:
学习第6,7,8,9章。(注:由于内容和之前学习的有所重复,所以用1个小时看完。只需要看和C++primer不同的内容即可。相同的快速过。如能看完最好,起码得看完6,7章。)
向山老师致敬!!