文章来源http://xuexi88.blogspot.com/
1.关于求模与求余。
首先他们是不同地。
求余:取整除后的余数。
如果 a mod b 两个数异号,那么结果符号同a.公式: a mod b= a-(a DIV b)*b;
求模:首先模不能小于0.分3中情况: a mod b
<1>如果a<b,那就是求余数了。
<2>如果a<b但是 a>0那么也是求余数。
<3>不同的是当a<0时,是不断的把b加到a上,知道a大于0为止,那时的a就是模数。
所以当a b都大于0时,求模和取余的结果相同。当a<0时就不是了。
取余是从绝对值中向外减绝对值,然后加上符号。取模是把模加上去,加到一个整数。
形象的来分析,当a<0时,就相当于把模跨在0点上,余数是小于0的部分,模数是大于0的部分。
3.std::cout<<"xx" 该操作数返回的是左操作数,即sdt:cout
所以可以连着写输出操作。endl是操纵符,把他写入输出流,具有换行的效果。
4。如何刷新输出流?
5.::作用域操作符
6.cin 接受两个操作数,左操作数一个istream对象,从左操作数中读取一个数存到右操作数的变量中。
7.空格不允许出现在预处理中。
8当我们确定变量在使用时会赋一个新值,那就不需要创建初始值。
9.dos命令下,cls清除屏幕;
10.cin操作成功时返回的时true,否则返回的时false.
11.标准库的头文件用<>括起来。非标准库的头文件用""括起来。
12. .操作符通过左操作数取得右操作数。
13. 函数后便的()叫,调用操作符。
14.默认情况下,cin会刷新cout 程序正常结束时,也会刷新cout.
15. c++是静态类型语言,会在编译时检查类型。
16. 类型时所有程序的基础。类型告诉我们数据代表什么意思,以及可以对数据执行哪些操作。
17.c++定义的类型:算数类型: 整形,浮点型,单个字符,布尔值。特殊类型:void, c++标准规定了,每个算数类型的最小存储空间,但是不阻止编译器使用更大的存储看空间。
18. wchar_t宽字符类型,用来扩展字符集,比如汉字,日语。
19.一般short 表示半个机器字,int表示一个机器子,long 表示1个或2个机器字。32位机,字长32位。
20.c++中 char 也分为signed char 和 unsigned char.
21 溢出时,如果时unsigned类型,编译器会对其取值数目求模。
22 浮点数有 单精度 float 双精度 double 扩展精度:long double. float 一个字,double 2个字,long double 3-4个字。
23.float能保证6位有效数字。double能保存10位。
24.在一些实现中,char被当作 signed类型,另外一些实现把他当作unsigned类型,所以把char作为计算类型很容易出问题。
25.使用双精度进行计算要付出的单价相比单精度可以忽略。事实上,有些机器,double比float运行的速度还要快。
26.字面值常量。就是常量,只有内置类型可以是常量。
27. 0开头的常量通常表示8进制 加U表示unsigned,L表示long
28.默认浮点的常量是double类型,F是float L是扩展性
29,在字符常量的前边加上 L表示是宽字符。
30.不可打印的字符用 转移字符表示 形式为 \.任何字符都可以用转义字符来表示 形式为 \000 三个8进制数 或\xddd若干16进制数。
31 一种特殊的常量 字符串 形式:多个转义字符链接,或双引号
32.字符串的末尾都有一个空字符。前面加个L表示宽字符常量,以一个宽空字符结束。
33两个相邻的仅有空格 制表符 或换行符分开的字符串字面值,或宽字符字面值,可链接成一个字面值,不需要+号。仅限常量。
34 不能链接字符常量和宽字符常量。
35 如果不是两个字符串链接,而是程序需要断开两行,可以使用\在端口处,但是\后只能是一个换行符和后边相连。
36.什么是变量:程序可以操作的有名字的存储区。
37.左值:可以出现在赋值语句的左边或右边。如变量。
右值:只能出现在表达式的右边。如常量。
38 a*b=c是错误的因为左值必须是lvalue.
39.通常。对象描述的是内存中,具有类型的区域。
40 变量名:标识符: identifier
41 c++中不能用作标识符的有两类:关键字,标识符代替名。
42 c++标识符特殊规则:不能有两个连续的下划线,不能下划线开头,然后紧跟一个大写字母,函数外定义的标识符不能以下划线开头。
43 初始化分为两种,一种是复制初始化,一种是直接初始化,
int ival(1024) ; int ival = 1024;
初始化并不是赋值。初始化是赋初值,而赋值是擦除用新值代替。
44 int a=1,b=2,c=3; int c=add(a,b);初始化示例。
2.3.4
1.内置类型是否自动初始化取决域变量的位置,函数体外定义的变量都初始化为0.在函数体内定义的变量不自动初始化。
2.c++也提供默认的构造函数,在程序员没有定义构造函数的时候。
3.c++区别了声明和定义。变量的定义(define)用于变量分配存储空间,还可以为变量指定初始值。一个程序中,变量有且仅有一个定义。声明:用于向程序表明变量的类型和名字。定义也可以是声明:当定义变量时我们声明了他的类型的名字。可以通过使用extern关键字声明变量名而不定义它。
extern int i;//声明但是不定义
int i;//声明并且定义变量,分配内存。
extern 声明不是定义,也不分配存储空间。事实上,它只是说明,变量定义在程序的其他地方。程序中,变量可以声明多次,但是只能定义一次。
只有声明也是定义时,声明才可以有初始化式,因为只有定义才分配存储空间。初始化必须要有存储空间来进行初始化。
如果声明有初始化式,那么它可以被当作是定义,即使声明标记为extern.
但是,只有extern声明位于函数外时,才可以有初始化式。
这样声明并且初始化后,随后带有初始化式的声明便是错误的。
extern double pi=3.1416 //
用法:任何在多个文件中使用的变量都需要有与定义分离的声明。在这种情况下,一个文件含有变量的定义,使用该变量的其他文件则包含该变量的声明。
4. 同一个程序中,一个变量名可以使用多次,只要他们不在同一个上下文中。
5.作用域:作用域用花括号界定;一般来说,名字从其声明点开始直到声明所在的作用域结束都是可见的。
6.和c#不同,变量名可以在内部作用域中重新定义。内部的重新定义隐藏了全局变量。使外部变量在重新定义之后不可见。
7 c++中的作用域:全局作用域,局部作用域,语句作用域,类作用域,命名空间作用域。
8 如何定义一个常量 const int bufSize=80; bufSize 是不可以修改的。修改会导致错误。常量在定义后必须显示的初始化。非常量变量可以在其他文件中,使用extern声明并使用。const不可以,只能是本文件中使用,除非,在定义时,指定const变量为extern,就亦可以在整个程序中访问const对象。
举例:
// file1.c
extern const int bufSize=215;必须显示初始化;
//file2.c
extern const int bufsize;//使用文件1中的变量
----------------
1.引用是复合类型,符合类型是用其他类型定义的类型。在引用的情况下,每一种引用类型都关联到某一其他类型。不能定义引用类型的引用(区分一下引用与引用类型),但可以定义其他类型的引用。
引用必须用和该引用同类型的对象初始化。
当引用初始化后,只要引用存在,就绑定在初始化时绑定的对象,不可能绑定到别的对象上。
重要概念:引用只是对象的另外一个名字。
必须要在定义引用时进行初始化。初始化是指明引用指向哪个对象的唯一办法。
const引用是指向const对象的引用。 将普通的引用绑定到const对象是不合法的。cosnt对象的引用在定义时也要加const关键字。 const 引用是只读的。
---------------------------------------------------------
强烈不解:
非const 引用只能帮顶到与该引用同类型的对象。
const引用则可以帮顶到不同但相关的类型的对象或绑定到右值。
虽然这两条规则我不会用到,但是我不理解。
---------------------------------------------------------
2.6 typedef
1. typedef 可以用来定义类型的同义词。
typedef double wages;//wages 是double 的同义词。
2.typedef 通常被用于以下3种目的:
为了隐藏特定类型的实现,强调使用类型的目的。
简化复杂类型的定义,使其容易理解。
允许一种类型用于多个目的。同时使得每次使用该类型的目的明确。
2.7 枚举 enum
1. 枚举举例: enum open_modes {input ,output ,append};
默认的,第一个枚举赋值0,后面递加1.
2.常量表达式:编译器在编译时就能够计算出结果的整形表达式。整形字面值常量通常就是常量表达式。
3. 举例: enum forms {shape=1,sphere,cylinder,polygon};
后边也是按1递加。无论初始化时给几个值,没显示初始化的都会按前边初始化的值默认加1初始化。
4.每个enum都定义了一种新的类型。并规定了这种类型可以取哪些值,当定义了这种枚举类型并对他进行赋值时,只能是枚举中定义的几个值,或前边定义过的该枚举类型的对象。
enum Points{ point2d=2,point2w,point3d=3,point3w};
Points pt3d=point3d;//ok:point3d is a points enumerator
Points pt2w=3;//error: pt2w initialzed with int
pt2w=polygon; //error: polygon is not a Points enumerator
pt2w=pt3d;//ok:both are objects of points enum type;
2.8 类类型:
1.标准库类型 string、istream、osteam都定义成类。
---------------------------------------------------------------------
强烈不解:
2.定义类时,通常先定义该类的接口,即该类所提供的操作。通过这些操作,
可以决定其功能所需要的数据,以及是否需要定义一些函数来支持该类的实现
---------------------------------------------------------
3.类的定义后边要有分号,不要忘记。
举例:
class Test
{
public:
//
private:
//
}
4.定义变量和定义数据成员存在非常重要的区别:一般不能把类成员的初始化作为其定义的一部分。当定义数据成员时,只能指定该数据成员的名字和类型。因为:类并不是在类定义里 定义并初始化数据成员,而是在构造函数里初始化数据成员。
5. public 部分定义的成员在程序的任何部分都可以访问。 不是类组成部分的代码,不能访问private区成员。
6.struct 与 class struct 是从c中继承过来。也可以定义类。区别:如果使用class来定义类,那么定义在第一个访问标号前的任何成员都隐式指定为pirvate;如果使用struct定义类,那么这些成员都是public.使用struct 还是class来定义类,仅仅影响默认的初始访问级别。
2.9 头文件
1.一般类定义都会放进头文件 .h.
2.头文件为相关的声明提供了一个集中存放的位置。头文件一般包括类定义、extern变量的声明和函数的声明。
3.头文件的好处:保证所有的文件使用给定实体的同一声明;当声明需要修改时。只有头文件需要更新。
4.头文件不应该包含定义,但有3中例外:头文件可以定义类、值在编译时就已经直到的const对象和inline函数。
5.如果const变量不是用常量表达式初始化,那么他就不应该出现在头文件中定义。那么他就要加上extern关键字,来使他能被多个文件共享。
2.9 预处理介绍
1.#include设施是c++预处理器的一部分。预处理器处理程序的园代码,在编译器之前执行。
2.设计头文件时,应使其可以多次包含在同一个源文件中。这一点很重要。我们必须保证多次包含同一
头文件不会引起,该头文件定义的类和对象,被多次定义。使得头文件安全的通常做法,是使用预处理器定义头文件保护符。
3.为避免名字冲突,预处理器变量经常用全大写字母表示。
4.预处理器变量有两种状态:已定义或者未定义。定义预处理器变量和检查其状态所使用的预处理器指示不同。#difine指示接受一个名字,并定义该名字未预处理器变量。#ifndef 指示检测指定的预处理器变量是否未定义。如果预处理器变量未定义,那么跟在其后的所有指示都将被处理,直到出现endif.
举例:
#ifndef TEST_H
#define TEST_H
//Definition
#endif
5.头文件应该含有保护符,即使这些头文件不会被其他文件包含。编写头文件保护符并不困难,而且如果头文件被包含多次,它可以避免难以理解的编译错误。
小结:
1.算术计算中避免使用short 和char ,unsigned可用于计数。
2. enumeration 枚举,是一种类型。inumerator枚举成员,枚举类型有名字的成员。
3.c++认为 类定义中public 是接口 而private是定义.
第三章
1.标准库:高级的抽象数据类型:高级是因为其中反映了更复杂的概念;之所以说抽象,因为我们不用关心他们内部如何实现。
2.bitset 语言级的设施。
3.域操作符的含义:右操作数的名字可以在左操作数的作用域中找到。
4.在一种情况下,必须总是使用完全限定的标准库名字:在头文件中。理由是头文件的内容会被预处理器放到程序中。如果头文件中防治了using声明,那就相当于所有包含这个头文件的源文件都使用了using声明,不管那个源程序需要不需要。这样是不好的。
5.我记得还有一种方法: using namespace std;这样一句搞定。
6. string 有四个构造函数: string s1;string s2(s1);string s3("hello");string s4(n,'x');
7.为了与C兼容,字符串字面值与标准库string类型不是同一类型。重要。
8.使用cin读入字串时,读取的是第一个两个空白中间的部分。
-----------------------------------------------------------------
强烈不解:
输入输出缓冲区!
cin以回车作为结束标志
那么
while(cin>>str)
cout<<str<<endl;
上例中,用输入操作符来读取string对象。该操作符返回所读的istream对象
,在读取结束后,作为while判断的条件。如果输入流是有效的。即还未到达文件
尾且未遇到无效输入,则执行while循环体,并将读取到的字符串输出到标准输出。
如果到达了文件尾,则跳出while循环。
我的理解:
回车,给流中写入一个结束符。并且执行读操作。
读只是从流中读取一段合法的string,然后结束读取,然后输入操作
然后继续去读操作。。直到读到结束符。
string s1;string s2;
cin>>s1;
cout<<s1;
cin>>s2;
cout<<s2;这个例子说明,输出操作不会影响输入缓冲区。
输入的原则大概是这样,如果缓冲区有数据,不管合法与否读进来。
如果没有数据,进程挂起,等待客户段输入,当输入一个结束符后。
通知cpu读取数据。
getline函数丢弃了换行符。
-------------------------------------------------------------------
9.string::size_type类型:目的是实现机器无关。不要把size()的返回值付给一个int型。使用size()最安全的方法是使用string::size_type类型。不要使用int 和long.
10.计算机中大写字母出现在小写之前。所以任何一个大写字母都小于小写字母。
11.string对象大小比较的原则:如果短的一个和长的一个的前部分完全相同,则短的小;否则从第一个不同的字母比较。
12.字符串的赋值操作分3步:先把s1的空间释放,然后非配s2大小的空间,然后把s2的字符复制到s1.
13.c++string加操作特别注意,+两边必须由一个是string类型的变量,不允许把两个字符串常量相加。
但是:string s2=s1+"aa"+"bb";是ok的。说明是顺序相加。
14.与c#不同,标准库是不检查索引值的。如果索引越界,会导致严重的运行时错误。
15.常用的字符操作函数在cctype头文件中。
Vector 容器
1.vector中的元素必须是同一种类型。
2.举例Vector<int> var. 注意vector不是一个类型,而是一个类型模板。vector<int>才是数据类型。
3.vector的构造函数
vector<T> v1; vector<T> v2(v1); vector<T> v3(n,i);v3包含n个值为i的元素。
vector<T> v4(n); v4含有值初始化的元素的n个副本。
4.虽然可以对给定元素个数的vector对象预先分配内存,但是更高效的办法是先初始化一个空的vector对象,然后再动态地增加元素。 奇哉怪哉。。。。。。。。。。。。。
5.初始化:如果没有元素的初始化式,那么标准库将自行提供一个元素初始值进行值初始化,value initializationd.这个由库生成的初始值将用来初始化容器中的每个元素,具体值为何,取决于存储在vector中的元素的数据类型。如果是内置类型,则是0,否则使用类型的默认构造函数。
6.12章要介绍一些有自定义构造函数,但是没有默认构造函数的类类型。这种情况下,在初始化这种类型vector对象时。程序员不仅要提供元素个数,还需要提供初始化值。第3中定义方式。
7.说白了,vector就是个泛型类型嘛。。
8.vector常用操作: v.empty(); v.size();v.push_back(t);末尾加上一个值为t的元素。要使用push_back()而不要使用下标直接赋值的方法。必须是已经存在的元素才可以用下标对其进行操作。
9.关于size() string 的是 string::size_type; vector的是 vector<int>::size_type;
迭代器 iterator
1.标准库为每一种标准容器包括(vector)定义了一种迭代器类型。迭代器提供了比下标操作更通用的方法。只有少数的容器支持下标操作。因为迭代器对所有的容器都适用。所以现代c++程序更倾向于适用迭代器,而不是下标访问元素。即使对支持下标操作的vector类型也是如此。
2.每个容器都定义了自己的迭代器,如vector: vector<int>::iterator iter;这个语句定义了一个名为iter的变量。
3.迭代器是个概念,如果一个类型支持一组确定的操作,这些操作可以用来遍历容器内的元素,并访问这些元素的值,我们就称这种类型为迭代器。
4.每种容器都定义了一对命名为begin和end的函数,用于返回迭代器。如果容器中有元素的化,返回的迭代器指向第一个元素。如:vector<int>::iterator iter=ivec.begin(); iter 即指该元素为ivec[0]
end返回的是末端元素的下一个,是个不存在的元素。如果vector为空,begin返回的迭代器与end返回的迭代器相同。
5.end 返回的迭代器是个哨兵的作用,表示我们已经处理完了vector中的元素。
6.迭代器用 解引用操作符 * 来访问迭代器所指的具体元素。如 *iter=0;
7.迭代器使用自增操作符移动到下一个元素。
8. == 和 != 如果两个迭代器指向了同一个元素,那么这两个迭代器相同。
9.这个迭代器怎么看着像指针啊。
10 和下标操作符一样,解引用操作符返回的是一个左值。
11 每种元素还定义了一种const_iterator类型,这种类型只能读取容器内的元素,但不能改变其值。定义方法为 vector<string>::const_iterator iter=text.begin(); 也是用begin 和end 函数来返回指针。
12 注意不要把const_iterator 这种类型和 const 关键字下的iterator对象混合。声明一个const类型的iterator时,同样要初始化,并且不能改变,就是说初始化时指向了哪个元素,就不能再变了。但是可以改变他指向的那个元素的值。
举例:
vector<int> nums (10);
const vector<int>::iterator cit=nums.begin();//返回的是第一个元素,那就不能变了。
*cit=1;//对所指的元素赋值。
cit++;//error 不允许改变,因为是cosnt
13.任何改变vector长度的操作都会使已存在的迭代器失效。例如,在调用push_back之后,就不能信赖指向vector的迭代器的值了。
14. vector<int>::iterator mid=(vi.begin()+vi.end())/2
15.当两个迭代器相减时,返回的是命名为 difference_type 的signed类型。
bitset
1. bitset 也是一种类模板,但是bitset类对象之间的区别仅仅是其长度而不是类型。
bitset<32> bitvec;// 32位,并且都是0;
2.bitset 构造函数: bitset<n> b; 有n位,都是0;
bitset<n> b(u); b 是 unsigned long型 u的副本。
bitset<n> b(s); b 是 string 对象s 中含有位串的副本
bitset<n> b(s,pos,n); b 是 s中位置从pos开始的n个位的副本
3.用unsigned long 来初始化时,如果bitset定义的长度长,那高阶余下的都是0;如果端,则抛弃高阶的。
4.用string 初始化时。从string对象中读入位集的顺序是从右到左。如"1100"对应为1100.
如果bitset长,那高阶补0;
5.注意stringbi说如果bitset短于string怎么办啊。
7、count和size操作返回的也是标准库中命名为size_t的类型。
8.to_ulong 操作仅当bitset 类型的长度小于或等于unsign long 的长度时,才可以进行to_ulong操作。否则会产生运行时异常。
9.输出二进制位
bitset<16> var(0xffff);
cout<<var<<endl;//1111111111111111
10 5.3节讲位操作符。
小结
1.数组和指针是类似vector和string 的标准库类型的低级抽象类型。
2.getline返回 istream对象。
3.iterator arithmetic 迭代器算数操作
第四章 数组指针
1. c++提供了两种类似于vector和迭代器的低级复合类型:数组和指针。建议尽量使用vector和迭代器,尽量比诶半使用数组指针,除非追求速度的时候。
2.数组也是容器,靠位置来访问。
3.数组的定义:数组是由类型名、标识符、和维数组成的复合数据类型。类型名约束类型。而维数约束了个数。这里的类型不能是引用。位数必须是大于或等于1的常量表达式。包括:字面常量,枚举常量,const常量(注意不能是运行期的const变量)。不能是变量。
4. 猜想 :数组大小在编译期要确定。所以维数一定要确定
5.初始化 int array[array_size]={0,1,2};
6.数组初始化原则:函数体外的内置类型的数组,初始化为0.
函数体内的内置类型,不初始化。
类类型,不管在哪,自动调用默认构造函数,如果没有默认,必须显示初始化。
7.显示初始化时可以省略维数如 : int array[]={1,2,3};
8.如果有维数也显示初始化,那初始化里的个数,不能超过维数。
9.字符数组:可以用单个字符初始化,也可以用字符串字面值,但是字面值的会在末尾加一个空字符。 \0.
10 注意: 和vector不同,一个数组不能用另外一个数组初始化,也不能将一个数组赋值给另外一个。
11. vector使用vector::size_type作为下标类型。数组的下标类型是size_t;
指针
1.指针是用于数组的迭代器。
2。 *是 dereference operator 解引用操作符 ++increment操作符 & address-of
3.指针迭代器不通,指针指向单个对象。迭代器只用于访问容器内的元素。
4. &只用于左值。
5.指针与数据类型相关联。 c++用一个*号把一个标识符声明为指针。
6.指针举例:
vector<int> *pvec; int *ip1; string *pstr; double *dp;
int ip1,*ip2;
注意:string* str1,str2. str1是指针 str2不是。
7.一个有效指针的三种状态:保存一个特定对象的地址;指向某个对象的后一个对象。或者是0值。 int *pi = 0;//pi initialized to address no object. int *p;//ok uninitialized.
8.如果使用未初始化的指针,会将指针中存放的不确定值视为地址。c++不会检查指针是否被初始化。但是会检查出0值的指针。
9.指针值有四中情况:0;类型匹配的对象的地址;同类型的另外一个有效指针;匹配类型的对象的下一个地址。 NULL也是0; 注意NULL不是在std中。
10特殊类型指针:void * 他可以存储任何类型的指针。 void*只支持几种有限的操作。
与令一种指针比较;向函数传递或从函数返回void指针;给另外一个void*赋值。
指针操作
1.指针和引用的区别,引用总之指向一个对象,定义引用不初始化是错误的。而是赋值,给引用赋值直接付给了对象。
2.指向指针的指针
int ival=1024;
int *pi=&ival;
int **ppi=π
指针与数组
1. int ia[]={1,2,3}; int *p=ia;
2.只要两指针指向同一数组,或有一个指向数组末端的下一个单元,支持减操作;返回标准库类型 ptrdiff_t 是一个signed类型。
3.可以直接对指针的加减表达式子做解引用 int last=*(ia+4);
4.使用下标访问数组时。实际上是对指向数组元素的指针做下标操作。
int *p=&ia[2];
int j=p[1]//等效于 *(p+1)
int k=p[-2]//等效于 *(p-2)
5.计算数组超出末端的指针值
const size_t arr_size=5;
int arr[arr_size]={1,2,3,4,5};
int *p=arr;
int *p2=p+arr_size;//指向末端下一个元素
6.for循环特殊性质:只要定义多个变量具有相同的数据类型,就可以在for循环的初始化语句部分,同时定义他们。
指针使用举例: 遍历数组元素
const size_t arr_size=5;
int int_arr[5]={1,2,3,4,5};
for(int *pbegin=int_arr , *pend=int_arr+arr_size;pbegin!=pend;++pbegin)
cout<<*pbegin<<' ';
指针和const
1.c++语言,强制要求,指向const对象的指针也必须具有const特性。
const double * ctpr;const限定了cptr指针所指向的对象的类型,而并非cptr本身。也就是说cptr本身不是const,在定义时不需要对他进行初始化。如果需要的话,允许给cptr重新赋值。但是重要的是:不能用cptr对其所指对象赋值。这是关键。
2.不能把const对象地址给非const对象的指针,也就是上面的指针声明和const对象的定义是对应的。
如: const double pi=3.14; double *ptr=π错误。const double *cptr=π正确;
3.不能用void *指针保存const对象的地址。而必须用const void*;
4.但是,可以把非const对象的地址赋给const对象的指针,
如; double dval=3.14; const int *ptr=&dval;
5,区别一下 const对象的指针 和 const指针-本身的值不能修改。如:
int var=3.14;
int *const p=&var;
6.还有一种 指向const 的const指针 如:
const double pi=3.14;
const double *const p=π
指针和typedef
1.typedef string *pstring; const pstring cstr;
cstr 不是指向const string 的指针,而是 指向 string的 const指针。
所以真实的定义是 string *const cstr;第二句中const 防止pstring 前,修饰的是类型, 不是变量。指的是不可变类型的变量某某某,此处是不可变pstring的变量cstr。就是cstr不可 变,不是cstr指向的对象不可变。
2.理解复杂的的类型声明;
const 可以防止类型前,也可以放在类型后。如:string cosnt s1;和const string s2;
string s;
typedef string *pstring;
const pstring cstr1=&s;
pstring cosnt cstr2=&s;
string *const cstr3=&s; 这三个定义的指针是相同的。 见p114
C风格的字符串
1.字符串字面值的类型是const char类型的数组。同时也是c风格的字符串。
实际上c风格的字符串既不是c类型,也不是c++类型,而是带有null结尾的字符数组。
举例:
char ca1[]={'C','+','+'};//不是c-style string
char ca2[]={'C','+','+','\0'};//是
char ca3[]="C++";是,并且是4个字符
const char *cp="C++";//也是 这样也可以啊。初始化一个指针??但是指针会跑的啊。
char *cp1=ca1;//不是
char *cp2=ca2;//是
2. c++通常使用(const)char * 类型来操纵c风格的字符串。
如:
const char *p="some value";
while(*cp)//等待 *cp 返回空 null,仔细注意这个用法。真值是除null以外的字符。
{
....
++cp;
}
3.c-style string 库函数 #include<cstring> c++版本 参数都是首指针
strlen(s) strcmp(s1,s2) strcat(s1,s2) 串联 strcpy(s1,s2,n)复制
strncat(s1,s2,n) strncpy(s1,s2,n)
4. c-style string 比较时,比较的是存放的地址值,而并非他们所指向的字符串:
if (cp1<cp2) 如果两个指向的是同一数组的元素(或溢出位置),则比较其地址,如果两个指针指向不通数组。则表达式没意义。
如果要进行字符串的比较应该用 strcmp 试试p105的例子;还有 p119
动态数组:
1.每一个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,这个区域是free store 或堆 heap。c有一对标准函数 malloc 和 free在堆中分配存储空间。c++用new 和delete .
2.动态数组只需要指定类型和数组长度。不需要指定对象名,使用new返回指向新非配数组的第一个元素的指针。在自由区创建数组是没有名字的,程序员通过地址来访问它。
int *pia = new int[10];
3.初始化,如果元素的类型是类类型,则使用默认构造函数。如果内置类型,就不初始化。
也可以在数组长度后边跟上一对括号,来初始化。
如 int *pia = new int[10]();做默认初始化
注意这里的初始化,只能初始化为默认值,不能做显示的初始化。
4,如果动态数组前加了const,则必须要初始化,因为cosnt无法赋值。c++允许定义类类型的const数组,但是这些类型要有默认构造。而创建前者意义不大。
5 允许动态分配空数组如:
seze_t n=get_size();//返回0也能运行,虽然不允许定义长度为0的数组变量,但是这里动 态可以
int *p=new int[n];
for( int *q=p;q!=p+n;q++)
...............
用new 动态创建长度为0的数组时,new返回有效的非0指针。该指针不能进行解引用操作。因为他是空。但是可以比较运算,对他加减0.或者本身,得0值。
6,用new定义的空间必须用delete []释放 如 delete [] pia.如果没有那个括号,是编译器无法发现的错误,将导致程序运行时出错。
新旧代码兼容:
1.可以把c风格字符串用在任何可以使用字符串字面值的地方:
可以用c风格字符串对string 对象赋值。(试试)
string 加法需要两个操作数,可以用c风格字符串作为其中一个操作数(试试)
也允许将c风格字符串用作复合赋值操作的右操作数。
但是反之不行,如 char *str=st2; 不能用string 给 c-style赋值。
但是string 提供了一个c_str()满足我们的要求 char *str=st2.c_str();
注意:c_str返回的数组不保证一定有效。接下来对st2的操作可能会改变st2的值。如果程序需要持续访问该输入,应该复制c_str函数返回的数组。
2 使用数组初始化vector对象 如
const size_t arr_size=6;
int int_arr[arr_size]={0,1,2,3,4,5};
vector<int> ivec(int_arr,int_arr+arr_size);第二个指针指向了要复制的最后一个元素的下一个空间。
4.4多维数组
1.严格来说 c++没有多维数组,只有数组的数组
文章来源http://xuexi88.blogspot.com/
0 评论:
发表评论