一年前的部分学习笔记,现在整理并复习它们。

三 C++数据类型

十进制,8进制,16进制——20;024;0x14.
迭代:多次循环,反复执行。
缺省:default,系统默认状态。

c可打印字符

基本的 ASCII 字符集共有 128 个字符,其中有 96 个可打印字符,包括常用的字母、数字、标点符号。(另外还有 32 个控制字符)

Unicode

(统一码、万国码、单一码):是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

宽字符

用多个字节来代表的字符称之为宽字符,而Unicode只是宽字符编码的一种实现。
全局变量定义后系统会给它赋初值0,而局部变量则不会。
赋值操作的显示和隐式:

string s="I love C++"; 
string s("I love C++");

void show(vector<int> vec,int x){
vector<int>::iterator ix;
printf("vec%d: \n",x);
for(ix=vec.begin();ix!=vec.end();ix++){
printf("%3d",*ix);
}
puts("");
}
int main()
{
vector<int> vec1(10); //定义10个元素,初始化为0
vector<int> vec2(10,2); //difine 10 ones, initialize all 2
vector<int> vec3(vec2.begin(),vec2.begin()+3); //copy the first three ones from vec2 to vec3
show(vec1,1);
show(vec2,2);
show(vec3,3);
return 0;
}
/*
vec1:
0 0 0 0 0 0 0 0 0 0
vec2:
2 2 2 2 2 2 2 2 2 2
vec3:
2 2 2
*/

补丁:把某些东西展开以便补上现有程序中的漏洞。
string 函数的强大:

string s("C++"); 
int len=s.size();//len cantains the length of s.
empty:s.empty();//if it's empty return true, if not return false.
string str2(str1);// copy str1 to str2.
string s3=s1+s2;// strcat s1 and s2
string s2+=s1;// add s1 to

混合使用
<1>C风格的字符串和 <2>string对象:

int main()
{
const char *p=", ";
string s1="I love China";
string s2="it never change";
string s3=s1+p+s2; //<1>can be tansformed to <2>, but <2> can't be used as <1>, unless:
const char *str = s1.c_str(); //c_str()函数返回一个指向正规C字符串的指针, 内容与本字符串相同.
cout<<s1<<endl;
cout<<s2<<endl;
cout<<s3<<endl;
cout<<str<<endl;
return 0;
}
/*
I love China
it never change
I love China, it never change
I love China
*/

string 的泛型算法之一:

replace( str.begin(), str.end(), '.', '_' ); //把原来的字符串中所有的"."替换成"_", 这个算法的起始位置可以自己设置。

引用类型:

应用类型一经声明必须初始化。

int main()
{
int ival = 1024;
int &refVal; //[Error] 'refVal' declared as reference but not initialized
return 0;
}

引用的所有操作都将附加到所指的对象上,这一点很像指针。

STL

standard Template Library 标准模板库。惠普实验室开发的一系列软件的统称。STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件。
整型值可以隐式转化成bool值,false对应着0,true对应着1。

输出枚举成员的结果是整数值,枚举成员不能迭代。

int main()
{
enum elements{table=1,cope=2,list=4,stone}; //在缺省的情况下,stone=5。
elements me=stone;
cout<<me<<endl;
//stone=2; //wrong.
//stone=list+3; // [Error] lvalue required as left operand of assignment
return 0;
}

利用begin与end的迭代器对控制输出:

for ( vector<string>::iterator it = text.begin();
it != text.end(); ++it )
cout << *it << ' ';
cout

iterator 是标准库中的类, 它具有指针的功能

typedef

提供了一种通用的类型定义设施,可以用来为内置的或用户定义的数据类型引入助记符。typedef double wages; //即用wages代替了double。–> 替代作用。
volatile 修饰符的主要目的是提示编译器该对象的值可能在编译器未监测到的情况下被改变,因此编译器不能武断地对引用这些对象的代码作优化处理。它和const比较相似。

pair函数:

#include <utility>
pair< string, string > author( "James", "Joyce" );
string firstBook;
if ( author.first == "James" &&author.second == "Joyce" )
firstBook = "Stephen Hero";

if(s[i++]>s[i])的运算顺序:C 或C++语言并不保证从左到右的计算顺序实际上的实现可能是先计算右边的操作数,保险的做法:if(s[i+1]>s[i]).

四 表达式

sizeof的返回一个对象或者类型名的字节长度,返回值的类型是size_t, 它在编译时刻运行,所以被视为常量表达式。

#include<bitset>
bitset<32> bitvec;//声明了一个含有32 个位的bitset 对象
bool is_set = bitvec.any();//如果bitvec有一个和一个以上的位是1,返回true。
bool is_not_set = bitvec.none();//如果bitvec没有一个位是1,返回true。
int bits_set = bitvec.count();//返回被设置为1 的位的个数。
for ( int index = 0; index < 32; ++ index )
if ( index % 2 == 0 ) bitvec[ index ] = 1; //通过下标操作符来设置位。

bitset 操作

操作

功能

用法

test( pos )

pos 位是否为1

a.test( 4 )

any()

任意位是否为1

a.any()

none()

是否没有位为1

a.none()

count()

值是1 的位的个数

a.count()

size()

位元素的个数

a.size()

[pos]

访问pos 位

a[ 4 ]

flip()

翻转所有的位

a.flip()

flip( pos )

翻转pos 位

a.flip( 4 )

set()

将所有位置1

a.set()

set( pos )

将pos 位置1

a.set( 4 )

reset()

将所有位置0

a.reset()

reset(pos)

将pos 位置0

a.reset( 4 )

四舍五入:double a=5.6; int A=a+0.5;

五 语句

goto 语句

它不能向前跳过没有被语句块包围的声明语句。
goto end;/错误: 跳过声明语句 [Error] jump to label ‘end’ [-fpermissive] /
int ix = 10;
end: ;
在标号语句后面加一个空语句是处理这种限制的典型方法。例如 end: ; // 空语句

六 抽象文本类型

顺序容器

(sequence container) 拥有由单一类型元素组成的一个有序集合两个主要的. 顺序容器是list 和vector, 第三个顺序容器为双端队列deque 发音为”deck”.

关联容器

“associative container” 支持查询一个元素是否存在并且可以有效地获取元素, 两个基本的关联容器类型是map 映射和set 集合
map 和set 都只包含每个键的惟一出现即每个键只允许出现一次, multimap 多映射和multiset 多集合支持同一个键的多次出现

int main(int argc, char *argv[]) {
multimap <int,string> mp;
mp.insert(make_pair(1,"wei"));
mp.insert(make_pair(1,"wang"));
mp.insert(make_pair(1,"zeng"));
mp.insert(make_pair(2,"xu"));
//mp[4]="xu";
multimap <int,string>::iterator ix;
for(ix=mp.begin();ix!=mp.end();ix++){
cout<<(*ix).first<<" "<<(*ix).second<<endl;
}
return 0;
}
/*
1 wei
1 wang
1 zeng
2 xu
*/

vector

表示一段连续的内存区域, 在任意位置而不是在vector 末尾插人元素则效率很低, 类似地删除任意一个而不是vector的最后一个元素效率同样很低, 因为待删除元素右边的每个元素都必须被复制一遍.

deque

也表示一段连续的内存区域, 但是与vector 不同的是它支持高效地在其首部插入和删除元素, 它通过两级数组结构来实现. 一级表示实际的容器, 第二级指向容器的首和尾

list

表示非连续的内存区域并通过一对指向首尾元素的指针双向链接起来, 从而允许向前和向后两个方向进行遍历. 在list 的任意位置插入和删除元素的效率都很高, 指针必须被重新赋值但是不需要用拷贝元素来实现移动, 另一方面它对随机访问的支持并不好, 访问一个元素需要遍历中间的元素. 另外每个元素还有两个指针的额外空间开销

下面是选择顺序容器类型的一些准则:
1.如果我们需要随机访问一个容器则vector 要比list 好得多
2.如果我们已知要存储元素的个数则vector 又是一个比list 好的选择
3.如果我们需要的不只是在容器两端插入和删除元素则list 显然要比vector 好
4.除非我们需要在容器首部插入和删除元素否则vector 要比deque 好

substr()操作

生成现有string 对象的子串的一个拷贝, 它的第一个参数指明开始的位置. 第二个可选的参数指明子串的长度, 如果省略第二个参数将拷贝字符串的余下部分.

find_first_of()

查找与被搜索字符串中任意一个字符相匹配的第一次出现(联想图书检索,百度等)

find()

是最简单的实例给出一个字符串,它返回匹配子串的第一个字符的索引位置或者返回一个特定的值:string::npos表明没有匹配例。
虽然返回的索引类型差不多总是int 类型, 但是更严格的可移植的正确声明应该使用形式: string::size_type
我们可以通过给出第二个参数来实现这个参数指明了字符串中起始查找位置的索引

while (( pos = name.find_first_of( numerics, pos ))
!= string::npos )
tolower(A);//#include<ctype>,return a.

string的字符插入:string_object.insert( position, new_string );
assign()和append()字符串操作, 它们允许我们顺次地把一个string 对象的部分拷贝或连接到另一个string 对象上.

// 拷贝s1 的前4 个字符  
s3.assign( s1, 0, 4 ); //使用另外一种形式则不用提供位置和长度而是提供一个iterator对 s3.assign( s1, s1.begin(), s1.begin()+4 );
// 连接一个空格
s3 += ' ';
// 连接s2 的前4 个字符
s3.append( s2, 0, 4 );
s3.assign( s1, 0, 4 ).append( ' ' ).append( s2, 0, 4

string的swap可以实现两个字符串的互换
string的replace可以实现字符串的替换:

string sentence(
"An ADT provides both interface and implementation." );
string::size_type position = sentence.find_last_of( 'A' );
string::size_type length = 3;

由multiset 和multimap 的特殊操作

equal_range()

返回iterator 对值, 如果这个值(搜索对象)存在,则第一个iterator 指向该值的第一个实例,且第二个iterator 指向这个值的最后实例的下一位置,如果最后的实例是multiset 的末元素,则第二个iterator 等于end()。

int main()
{
multimap<int,string> mp;
mp.insert(make_pair(1,"Elena"));
mp.insert(make_pair(1,"Stephen"));
mp.insert(make_pair(1,"Demon"));
mp.insert(make_pair(2,"Jermy"));
mp.insert(make_pair(3,"Tyler"));
typedef multimap<int,string>::iterator itType;
pair<itType,itType> pos=mp.equal_range(1);
//printf("%d-%s, %d-%s\n",(pos.first)->first,(pos.first)->second,(pos.second)->first,(pos.second)->second);
printf("%p, %p\n",pos.first,pos.second);
mp.erase(pos.first,pos.second);
for(itType iter=mp.begin(); iter!=mp.end(); ++iter)
cout<<iter->first<<"\t"<<iter->second<<endl;
return 0;
}

不支持下标操作是访问multimap 元素的一个限制。

七 函数

所有的函数都使用在程序运行栈run-time stack 中分配的存储区.
如果函数已经被声明为inline(内联),则函数体可能已经在编译期间它的调用点上就被展开,如果没有被声明为inline 则函数在运行时才被调用。
当参数是引用时函数接收的是实参的左值而不是值的拷贝,这意味着函数知道实参在内存中的位置因而能够改变它的值或取它的地址
使用引用参数函数可以访问被指定为实参的类对象而不必在函数的活动记录中拷贝它。
引用参数的实参不能为0。
如果一个参数可能在函数中指向不同的对象,或者这个参数可能不指向任何对象则必须使用指针参数。
函数参数也可以是多维数组这样的参数, 必须指明第一维以外的所有维的长度. 例如
void putValues( int matrix[][1a], int rowSize );
把matrix 声明成一个二维数组每行由10 个列元素构成matrix 可以被等价地声明为 int (*matrix)[10]

在左边参数的任何缺省实参被提供之前最右边未初始化参数必须被提供缺省实参,这是由于函数调用的实参是按照位置解析的
// 错误: 在指定height 之前, width 必须有一个缺省实参
char *screenInit( int height = 24, int width, char background = ’ ’ );

若一个函数被指定为inline 函数则它将在程序中每个调用点上被内联展开. 写成函数的额外执行开销从而被消除了

链接指示符

由关键字extern 后跟一个字符串常量以及一个普通的函数声明构成.
关键字extern用来告知编译器变量在当前范围之外声明过了.被extern语句描述过的变量将分派不到任何空间,因为他们在别的地方被定义过了.
C++ 语言为了实现对C 语言的支持, 因而提供了 extern “C” 关键字, 以实现代码的复用. (告诉编译器以C的方式进行编译执行,如果直接用C++的方式可能出现函数名损坏问题)
链接指示符不能出现在函数体中.

#include <stdio.h>
#include <stdlib.h>
using namespace std;
const char *str = "hello";
extern "C"{
char *strcpy( char *, const char * );
int printf( const char *, ... );
int strlen( const char * );
}
int main()
{ /* C 语言程序 */
char* s = (char *)malloc( strlen(str)+1 );
strcpy( s, str );
printf( "%s, world\n", s );
exit( 0 );
}
/*
mian.o: 二进制目标文件
如果没有extern "C", 将出现链接错误:
[Linker error] main.o:main.cpp:(.text+0x17): undefined reference to `strlen(char const*)'
[Linker error] main.o:main.cpp:(.text+0x39): undefined reference to `strcpy(char*, char const*)'
*/

int pf (); 返回int 型指针的函数
int (*pf) (); 指向int函数的指针
指向函数的指针可如下被初始化
int (*pfi)() = lexicoCompare;
函数指针可以用0 来初始化或赋值,以表示该指针不指向任何函数
指向函数的指针:pf( ia, iaSize ); 也可以用显式的指针符号写出 (*pf)( ia, iaSize );
如果函数指针的值为0 ,则两个调用都将导致运行时刻错误。只有已经被初始化或赋值的指针引用到一个函数才可以被安全地用来调用一个函数。

指向函数的指针 void (*p)():

void print1(){
puts("this is a print 1");
}
void print2(){
puts("this is a print 2");
}
int get3(){
return 3;
}
double getPI(){
return 2*acos(0);
}
int main(int argc, char *argv[]) {
void (*p)()=print1;
(*p)();
p=print2;
(*p)(); // point to another void ()
p=(void (*)())get3; // point to another int ()
printf("%d\n",(*((int (*)())p))());
printf("%d\n",p);
char s[20]="123456789";
p=(void (*)())s; // point to char []
printf("%s\n",(char *)p);
printf("%s\n",p);
p=(void (*)())getPI;
printf("%lf\n",(*(double (*)())p)());
printf("%lf\n",p);
return 0;
}
/*
this is a print 1
this is a print 2
3
4199384
123456789
123456789
3.141593
3.141592
*/

指向extern “C”函数的指针:
extern “C” void exit(int);
// pf 指向C 函数exit()
extern “C” void (*pf)(int) = exit;
int main() {
// …
// 调用名为 exit() 的 C 函数
(*pf)(99);
}