C++ primer 学习笔记(1)

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

三 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 s2

混合使用

<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 << endl

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);

}

时间: 2024-08-26 21:28:48

C++ primer 学习笔记(1)的相关文章

C++ Primer 学习笔记_98_特殊工具与技术 --优化内存分配

特殊工具与技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自动运行合适的构造函数来初始化每个动态分配的类类型对象. new基于每个对象分配内存的事实可能会对某些类强加不可接受的运行时开销,这样的类可能需要使用用户级的类类型对象分配能够更快一些.这样的类使用的通用策略是,预先分配用于创建新对象的内存,需要时在预先分配的内存中构造每个新对象. 另外一些类希望按最小尺寸为自己的数据成员分配需要的内存.例如,

C++ Primer 学习笔记_73_面向对象编程 --再谈文本查询示例

面向对象编程 --再谈文本查询示例 引言: 扩展第10.6节的文本查询应用程序,使我们的系统可以支持更复杂的查询. 为了说明问题,将用下面的简单小说来运行查询: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful fiery bird, he

C++ Primer 学习笔记_74_面向对象编程 --再谈文本查询示例[续/习题]

面向对象编程 --再谈文本查询示例[续/习题] //P522 习题15.41 //1 in TextQuery.h #ifndef TEXTQUERY_H_INCLUDED #define TEXTQUERY_H_INCLUDED #include <iostream> #include <fstream> #include <sstream> #include <vector> #include <set> #include <map&g

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员)、拷贝构造函数

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员).拷贝构造函数  从概念上将,可以认为构造函数分为两个阶段执行: 1)初始化阶段: 2)普通的计算阶段.计算阶段由构造函数函数体中的所有语句组成. 一.构造函数初始化列表 推荐在构造函数初始化列表中进行初始化 1.对象成员及其初始化 <span style="font-size:14px;">#include <iostream> using namespace std;

C++ Primer 学习笔记_14_标准模板库_bitset位集合容器

C++ Primer 学习笔记_14_标准模板库_bitset位集合容器 bitset容器是一个bit位元素的序列容器,每个元素只占一个bit位,取值为0或1,因而很节省内存空间.下图是一个bitset的存储示意图,它的10个元素只使用了两个字节的空间. 使用bitset需要声明头文件"#include <bitset>" 1.创建bitset对象 创建bitset对象时,必须要指定容器的大小.bitset对象的大小一经定义,就不能修改了.下面这条语句就定义了bitset对

C++ Primer 学习笔记_23_标准模板库_stack.

C++ Primer 学习笔记_11_标准模板库_stack.queue队列容器与priority_queue优先队列容器 1.stack堆栈 stack堆栈是一个后进先出(Last In First Out,LIFO)的线性表,插入和删除元素都只能在表的一端进行.插入元素的一端称为栈顶,而另一端称为栈底.插入元素叫入栈(Push),删除元素叫出栈(Pop).下图是堆栈示意图 堆栈只提供入栈,出栈,栈顶元素访问和判断是否为空等几种方法.采用push()方法将元素入栈:采用pop()方法出栈:采用

C++primer学习笔记(二)——Chapter 4

4.1  Fundamentals 1.Basic Concepts (1)操作符分为一元,二元或者三元操作符: (2)复杂的表达式中含有很多操作符时: 规则一:分为不同的级别,级别高的先运行: 规则二:相同级别的操作符有执行顺序的确定: (3)操作符可以改变操作数的类型 一般将级别低的转化成级别高的 (4)重载运算符 相同的运算符在对不同类型的对象进行操作的时候,会有不同的功能: (5)Lvalue和Rvalue 显而易见:Lvalue指的是Left value,Rvalue指的是Right

C++ Primer 学习笔记_104_特殊工具与技术 --嵌套类

特殊工具与技术 --嵌套类 可以在另一个类内部(与后面所讲述的局部类不同,嵌套类是在类内部)定义一个类,这样的类是嵌套类,也称为嵌套类型.嵌套类最常用于定义执行类. 嵌套类是独立的类,基本上与它们的外围类不相关,因此,外围类和嵌套类的对象是互相独立的.嵌套类型的对象不具备外围类所定义的成员,同样,外围类的成员也不具备嵌套类所定义的成员. 嵌套类的名字在其外围类的作用域中可见,但在其他类作用域或定义外围类的作用域中不可见.嵌套类的名字将不会与另一作用域中声明的名字冲突 嵌套类可以具有与非嵌套类相同

C++ Primer 学习笔记_102_特殊工具与技术 --运行时类型识别[续]

特殊工具与技术 --运行时类型识别[续] 三.RTTI的使用 当比较两个派生类对象的时候,我们希望比较可能特定于派生类的数据成员.如果形参是基类引用,就只能比较基类中出现的成员,我们不能访问在派生类中但不在基类中出现的成员. 因此我们可以使用RTTI,在试图比较不同类型的对象时返回假(false). 我们将定义单个相等操作符.每个类定义一个虚函数 equal,该函数首先将操作数强制转换为正确的类型.如果转换成功,就进行真正的比较:如果转换失败,equal 操作就返回 false. 1.类层次 c

C++ Primer 学习笔记_77_模板与泛型编程 --实例化

模板与泛型编程 --实例化 引言: 模板是一个蓝图,它本身不是类或函数.编译器使用模板产生指定的类或函数的特定版本号.产生模板的特定类型实例的过程称为实例化. 模板在使用时将进行实例化,类模板在引用实际模板类型时实例化,函数模板在调用它或用它对函数指针进行初始化或赋值时实例化. 1.类的实例化 当编写Queue<int>qi时,编译器自己主动创建名为Queue<int>的类.实际上,编译器通过又一次编写Queue模板,用类型int取代模板形參的每次出现而创建Queue<int