您的位置:首页 > 编程语言 > C语言/C++

C++程序设计语言(特别版):第三章 标准库概念

2010-10-10 21:42 351 查看

第三章 标准库概念

3.1 引言
没有任何一个重要程序是只用赤裸裸的程序设计语言写出的,首先总是要开发出一组支撑库,这也就形成了进一步工作的基础。
3.2 Hello, world!
来自main()的非0值表示出错。
fyhui:如果返回的是非0值,对程序运行或编译有什么影响?有待验证。

#include <iostream> //VC6.0中,这几行代码能编译通过吗?不加其他头文件
int main()
{
std::cout<<”Hello, world!/n”;
}
3.3 标准库名字空间
#include <string>
using namespace std;
string str = “fyhui”;
#include是类似宏定义代码替换,把头文件代码复制一份。而namespace也是声明,它是代码复制吗?不同文件间如何使用的?与#include有何异同?
3.4 输出
默认情况下,送到cout的输出值都将被转换为字符的系列。
字符常量被输出为一个字符,而不是一个数值。
一个输出表达式的结果本身还可以用于进一步的输出。ècout::operator<<返回自引用?

int a = 10;
char c = ‘c’;
cout<<”a = ”<<a<<” c = ”<<c<<endl;

3.5 字符串
string str = “fyhui”; int n = sizeof(string)=16; int m = sizeof(str)=16;
string具体有哪些成员函数和成员变量?是以‘/0’结尾吗?

fyhui问1:i++、++i、i += 1、i = i + 1效率排序,他们具体使用到几个寄存器和加法器?
++i 等价于 i = ( i, i + 1); èè返回+1值,返回的是自身对象,最后自身已经+1了
i++ 等价于 i = (t = i, i += i, t); èè返回原值,返回的是另一个对象,最后自身+1了

网上流行string类的几个基本函数的实现。
class string //怎么没有无参数的构造函数,是因为有默认参数值的通用构造函数吗?
{
string(const char *str=NULL); //通用构造函数
string(const string &another); //拷贝构造函数
~string(); //析构函数
string & operator= (const string &other); //赋值函数
private:
char *m_data;
};

string::string(const char *str)
{
if(str == NULL) //构造空字符串
{
m_data = new char[1]; //若能加NULL判断更好
m_data[0] = 0; //*m_data = ‘/0’;
}
else
{
m_data = new char[strlen(str) + 1]; //若能加NULL判断更好
strcpy(m_data, str);
}
}
string::string(const string &another)
{
assert(another.m_data != NULL); //没有此句—林锐
m_data = new char[strlen(another.m_data) + 1]; //若能加NULL判断更好
strcpy(m_data, another.m_data);
}
string:~string()
{ //仅一行delete [] m_data;—林锐
if(m_data != NULL)
{
delete [] m_data; //由于m_data是内部数据类型,可以直接delete m_data
m_data = NULL;
}
}
string & string::operator=(const string &other)
{
if(this == &other) //自赋值
{
return *this;
}
delete [] m_data; //释放以前资源
assert(other.m_data != NULL); //没有这一行—林锐
m_data = new char[strlen(other.m_data) + 1]; //若能加NULL判断更好
strcpy(m_data, other.m_data);

return *this;
}
3.5.1 C风格的字符串
一个C风格的字符串是以0字符结束的字符数组。很容易将一个C风格的字符串放进string里;要调用以C风格的字符串为参数的函数,就必须以C风格字符串的形式提取string的值,函数c_str()正是。printf(“name: %s/n”, name.c_str());
3.6 输入
cin是标准输入流。
int a;
double d;
cin>>a>>d; //输入32.12 63会产出错误吗?
cout<<a<<” ”<<d<<endl;
输入对应的数据类型有什么限制,中间用什么分开数据,空格符、回车换行符?
输入32.12 63àà输出32 .12;
输入w 3àà输出-858993460 -1.07374e+008

按照默认方式,一个空白符,例如空格符(还有其他符号是空格符?),将结束一次输入。
可以用getline()读取一整行的输入。一行,无论多少个字符,只要没有回车+换行?
3.7 容器
一个以保存一批对象为主要用途的类通常被称为一个容器。
3.7.1 向量——vector
struct Entry
{
string name;
int number;
};

内部数据具有固定的内存,分配太大浪费,分配太小又溢出。vector是动态变长数组。
vector<Entry>book(1000); //1000个元素的向量
vector<Entry>book[1000]; //1000个空向量的数组
3.7.2 范围检查
标准库的vector并不提供对区间范围的检查。——不是动态数组吗?只要保证访问size()以下的就不可能超出范围啊。
3.7.3 表——list’
双向链表。如果对电话薄的插入和删除操作很频繁,请使用list,如果使用list,将倾向于不采用通过下标方式访问。——是不能下标访问吧。
list<Entry>phone_book;
3.7.4 映射——map
支持插入、删除和基于值的检索。类似于对偶的list,存储方式是数组还是链表。
map<string, int>phone_book;
3.7.5 标准容器
vector、list、map比较:对向量的下标操作开销较小且易于操作,而在向量的两个元素间插入元素代价高昂;list性质恰好相反;map类似于(关键码,值)对偶的表,除此之外还针对基于关键码去查询值做了特殊的优化。
标准库容器的总结
vector<T> 变长向量
list<T> 双向链表
queue<T> 队列
stack<T> 堆栈
deque<T> 双向队列
priority_queue<T> 按值排序的队列
set<T> 集合
multiset<T> 集合,值可能重复
map<key, value> 关联数组
multimap<key, value> 关联数组,关键字可以重复
3.8 算法
3.8.1 迭代器的使用
template<class C, class T>int count(const C &v, T val) //val值在v出现的次数
{
typename C::const_iternator i = find(v.begin(). v.end(), val);
int n = 0;
while(i != v.end())
{
++n;
i = find(i+1, v.end(), val);
}
return n;
}
但是我们并不需要去定义count模板,为了达到完全的通用性,标准库的count以一个系列作为参数,而不是容器作为参数。采用系列的写法,将使我们能把count用于内部数组,还可以对容器中的一部分做统计。
void g(char cs[], int sz)
{
int i1 = count(&cs[0], &cs[sz], ‘z’); //数组中的’z’
int i2 = count(&cs[0], &cs[sz/2], ‘z’); //数组前一半中的’z’
}
3.8.2 迭代器类型
各种容器还应该实现对应的迭代器?
3.8.3 迭代器I/O
ostream_iterator<string> oo(cout); // ostream_iterator关键字何意?
istream_iterator<string> ii(cin); // istream_iterator关键字何意?

int main()
{
*oo = “Hellow”; //意思是cout<<”Hellow”;

string s = *ii; //意思是string s; cin>>s;
}

3.8.4 遍历和谓词
用于控制算法的函数被称为谓词,谓词将被针对每个元素调用并返回布尔值,算法根据这种返回值去执行自己预定的动作。
bool gt_42(const pair<const string, int>& r)
{
return r.seconde > 42;
}

void f(map<string, int>& m)
{
typedef map<string, int>::const_iterator M1;
M1 i = find_if(m.begin(), m.end(), gt_42);
}
3.8.5 使用成员函数的算法
有许多算法都是将某个函数应用于一个系列里的各个元素。
void draw(Shape *p)
{
p->draw();
}
void f(list<Shape *>& sh)
{
for_each(sh.begin(), sh.end(), mem_fun(&Shape::draw));
}
3.8.6 标准库算法
标准库算法的选择
for_each() 对每个元素调用函数
find() 找出参数的第一个出现
find_if() 找出第一个满足谓词的元素
count() 统计元素出现的次数
cout_if() 统计与谓词匹配的元素
replace() 用新值取代元素
replace_if() 用新值取代满足谓词的元素
copy() 复制元素
unique_copy() 复制元素、不重复
sort() 对元素排序
equal_range() 找出所有具有等价值的元素
merge() 归并排序的序列
这些算法以及其他许多算法都可以用于容器、string和内部数组的元素。
3.9 数学
3.9.1 复数
3.9.2 向量算术
3.9.3 基本数值支持
3.10 标准库功能
标准库所提供的功能可以分类如下:
[1]基本运行支持(例如存储分配和运行时类型信息等);
[2]C标准库(做了极少的修改,以便尽可能地减少其中违反类型系统的情况);
[3]字符串和I/O流;
[4]容器和使用容器的算法的框架(即STL);
[5]对数值计算的支持。
3.11 忠告
[1]不要像重新发明车轮一样重复做每件事,去使用库;
[2]不要相信奇迹,要理解你的库能做什么,它们如何做的,它们做时需要多大的代价;
[3]当你遇到一个选择时,应该优先选择标准的库而不是其他的库;
[4]不要认为标准库对应任何事情都是最理想的;
[5]切记#include你所用到的功能的头文件;
[6]标准库的功能定义在名字空间std中;
[7]请用string,而不是char*;
[8]如果怀疑,就用一个检查区间范围的向量;
[9]vector<T>、list<T>和map<key,value>都比T[]好;
[10]如果向一个容器中添加一个元素,用push_back()或back_insert();
[11]采用对vector的push_back(),而不是对数组realloc();
[12]在main()中捕捉公共的异常。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: