热门网站排名,平台公司和项目公司的区别,最好的网站建设公司,设计事务所可以使用using声明而无需专门的前缀#xff1a;using namespace::name;.。位于头文件的代码一般来说不应该使用using声明#xff0c;这是因为头文件的内容会拷贝到所有引用他的文件中去#xff0c;如果头文件中有某个using声明#xff0c;那么每个使用了该头文件的文件都会… 可以使用using声明而无需专门的前缀using namespace::name;.。位于头文件的代码一般来说不应该使用using声明这是因为头文件的内容会拷贝到所有引用他的文件中去如果头文件中有某个using声明那么每个使用了该头文件的文件都会有这个声明。对于某些程序来说由于不经意间包含了一些名字反而可能产生始料未及的名字冲突。 使用string类型需要添加头文件#includestring并且要对string进行声明using std::string; string类型的初始化 string s1; 默认初始化s1是一个空字符串
string s2 s1; s2是s1的副本等价于s2(s1)
string s3 hello; s3是该字符串字面值的副本等价于s3(hello);
string s4(10, c); s4的内容是10个c需要注意的是s3是的内容不包括字面值最后的空字符。当初始值只有一个的时候拷贝初始化使用和直接初始化都可以但是如果有多个初始值s4的初始化就只能够使用直接初始化的方式。 string的操作 oss 将s写入都输出流os中返回os
iss 从is中读取字符串赋给s字符串以空白分隔返回is
getline(is, s) 从is中读取一行赋给s返回is
s.empty() s为空返回true否则返回false
s.size() 返回s中字符的个数
s[n] 返回s中第n个字符的引用
s1s2 返回s1和s2连接后的结果
s1s2 用s2的副本代替s1中原本的字符
s1s2 如果s1和s2所包含的字符完全一样则返回true
s1!s2
,,, 根据字典序进行比较 可以使用while(cins)进行循环读入getline会读入换行符但是不会把换行符保存到string对象中。因为getline返回的也是输入流因此也可以使用while(getline(cin,s))进行循环读入 size()函数返回值是string::size_type类型这是一个无符号整型因此如果我们直接使用size()的返回值和一个负数比较则几乎肯定是true这是因为负数n会自动转换成一个比较大的无符号整数。在C中int和unsigned int在一起的时候前者会自动转换为后者。尽量还是用一个int变量保存返回值或者进行强制类型转换。 如果两个字符串前面都相同长的那个比短的大 复合运算符负责把右侧string对象追加到左侧string对象的后面 当把string对象和字符串字面值混在一条语句中使用时必须确保每个加法运算符两侧的运算对象至少有一个是string。 string a Hello;
string b a world !; //正确
string c Hello world a; //错误字符串字面值与string是不同的类型 应该尽可能使用C版本的C标准库头文件去掉结尾的.h在前面加上c表示属于C标准库的头文件虽然两者内容一样但是在名为cname中的头文件中定义的名字从属于命名空间std而.h头文件则不然。 可以使用库cctype判断一个字符的类别 isalnum(c) 当c为字母或数字为真
isalpha(c) 当c为字母为真
iscntrl(c) 当c为控制字符为真
isdigit(c) 当c为数字为真
islower(c) 当c为小写字母为真
ispunct(c) 当c为标点符号为真
isspace(c) 当c为空白字符为真
isupper(c) 当c为大写字母为真
tolower(c) 如果c是大写字母则返回小写字母否则原样输出
toupper(c) 如果c是小写字母则返回大写字母否则原样输出 如果想要改变string对象中字符的值则必须把循环变量定义成引用类型 string s;
cin s;
//将s中每个字母变成大写
for(auto c : s)
{c toupper(c);
}
cout s endl;从这里也可以看出c每次会重新定义 string类型的下标是string::size_type类型的任何一个带符号类型的值将自动转化为这种无符号类型。注意不要越界越界的行为是未定义的。 注意逻辑运算符和||的短路性质 const string的每一个字符是const char类型的 模板本身不是类或者函数可以将模板看做编译器生成类或者函数编写的一份说明。编译器根据模板创建类或函数的过程成为实例化 。当使用模板时需要指出编译器应把类或函数实例化成何种类型。 vectorint a;
vectorvectorstring file; vector能容纳绝大多数类型的对象作为元素但是因为引用不是对象所以不存在包含引用的vector。 需要指出的是在旧版本中多维vector的声明中最后的之间必须有空格否则编译器会认为是右移运算符。 vector初始化 vectorT v1; v1是一个空的vector潜在的元素是T类型的执行默认初始化
vectorT v2(v1); v2包含有v1所有元素的副本
vectorT v2 v1; 等价于v2(v1)
vectorT v3(n, val)v3包含了n个重复元素每个元素的值都是val
vectorT v4(n) v4包含了n个重复地执行了值初始化的对象
vectorT v5{a, b, c,...}v5包含了初始值个数的元素每个元素被赋予对应的初始值
vectorT v5 {a, b, c...}等价于v5{a, b, c,...} C几种初始化方式一般来说可以相互等价地使用但是也有几种特殊情况 使用拷贝初始化使用的时候只能提供一个初始值类内初始化只能使用拷贝初始化或花括号的形式如果提供的是初始元素之的列表则只能把初始值放在花括号里而不能放在圆括号里 可以只提供vector对象容纳的元素数量而略去初始值此时库会创建一个值初始化的元素初值并把它赋给容器中的所有元素。但是如果元素对象是一个类而这个类明确要求需要提供初始值则无法完成初始化工作。 如果使用圆括号来初始化可以说提供的值是用来构造vector对象的如果使用花括号可以表述成我们想列表初始化该vector对象。但是如果提供的值不支持列表初始化编译器就会尝试理解为直接初始化把{当做(来处理如果仍旧无法进行初始化则报错 使用push_back方法向vector的尾部添加元素。C标准要求vector应该能在运行时高效添加元素因为vector对象能够高效地增长在定义vector对象设定其大小没有什么必要事实上这么做性能可能更差这一点和Java不同。 如果循环体内部包含向vector对象添加元素的语句则不能使用范围for循环for(auto item:a) 常见的vector操作 v.empty()
v.size()
v.push_back(t)
v[n]
v1 v2 用v2中元素的拷贝替换v1中的元素
v1 {a,b,c...} 用列表中元素的拷贝替换v1中的元素
v1 v2 v1和v2相等当且仅当他们的元素数量相同而且对应位置的元素值都相同
, , , 顾名思义以字典顺序进行比较 size函数返回size_type类型需要指定对应的模板类型例如 vectorint::size_type //正确
vector::size_type //错误 使用比较运算符需要元素可以相互比较 vector的下标运算符可用于访问已经存在的元素而不能用于添加元素 所有标准库容器都可以使用迭代器但是其中只有少数几种才同事支持下标运算符。严格来说string对象不属于容器类型但是string支持很多与容器类型类似的操作。这些类型都拥有名为begin和end的成员其中begin成员负责指向第一个元素的迭代器end成员负责返回指向容器尾元素的下一位置的迭代器尾后迭代器或尾迭代器。如果容器为空begin和end返回同一个迭代器。使用auto进行迭代器的定义比较方便。 常见操作 *iter 返回迭代器所指元素的引用
iter-member 相当于(*iter).member
iter 令迭代器指向容器的下一个元素
--iter 令迭代器指向容器的上一个元素
iter1 iter2 判断两个迭代器是否相等
iter1 ! iter2 试图解引一个尾后迭代器是未定义的行为 //以此处理s的字符串直到我们全部处理完或遇到空白字符
for(auto it s.begin(); it ! s.end() !isspace(*it); it)
{*it toupper(*it);
} 在C中我们更愿意使用迭代器和!判断是否到达尾部。这样做的原因是所有容器都支持这些操作而下标和则只有很少的容器定义。 迭代器的类型有两种iterator和const_iterator后者表示不能修改元素值如果vector或string是const的则只能使用这种类型。 string::iterator it1;
vectorint::const_iterator it2;如果容器是常量则begin和end返回的类型是const_iterator类型的迭代器。如果我们使用cbegin和cend则无论容器是否是常量都返回const_iterator类型的迭代器。 //依次输出text的每一行直到遇到第一个空白行
for(auto it text.cbegin(); it ! text.cend() !it-empty(); it)
{cout *it endl;3
} 使用范围for循环或者使用迭代器进行循环都不能改变容器对象的容量否则有可能使得迭代器失效 迭代器运算string和vector的迭代器提供了更多的运算符可以让迭代器每次跨过多个元素另外也支持迭代器进行关系运算 //小心越界
iter n 迭代器向后移动n个元素
iter - n 迭代器向前移动n个元素
iter n
iter - niter1 - iter2 返回两个迭代器之间的距离
, , , 其中迭代器之间的-返回difference_type的带符号整数 int bSearch(const vectorint a, int x)
{ auto begin a.cbegin();auto end a.cend();auto mid begin (end - begin) / 2;while(mid ! end *mid ! x){if(*mid x)begin mid 1;else end mid;mid begin (end - begin) / 2;}if(mid end) return -1;else return mid - begin;
}数组也是存放类型相同的对象的容器这些对象本身没有名字需要通过其所在位置访问不过数组的大小不能改变。 数组是一种复合类型元素的个数也属于数组类型的一部分编译的时候维度应该是已知的维度必须是一个常量表达式。数组的元素会被默认初始化如果数组的元素是内置类型而且数组在函数内部定义则每个元素不会被初始化。不允许用auto关键字由初始值的列表推断类型且不存在引用的数组 如果用初始值列表初始化数组则数组的维度可以不指明默认为初始值列表的长度。如果指定维度的话则维度至少要比初始值列表的长度长剩下的元素会被默认初始化 字符数组可以用字符串字面值进行初始化不过需要注意的是字符串字面值的末尾有一个空字符也会被拷贝到字符数组中因此字符数组的长度应该是可见的字符个数加一 不能将数组的内容拷贝给其他数组作为初始值也不能用数组为其他数组赋值 对于声明中有括号的应该先理解括号里面的再从右往左进行理解 int *ptr[10]; ptr是含有10个整型指针的数组
int ptr[10]; 错误不存在引用的数组
int (*ptr)[10]; ptr是指针指向含有10个元素的数组
int (ptr)[10] arr; ptr是引用,指向一个含有10个元素的数组 在使用数组下标时通常将其定义为size_t了类型。size_t是一种机器相关的无符号类型被设计得足够大能够表示内存中任意对象的大小。在cstddef头文件中定义 对于数组我们同样可以使用范围for循环 unsigned scores[11] {}; //进行初始化
for (auto i : scores)cout i ; 在C中使用指针的时候编译器一般会把它转换成指针。在很多用到指针名字的地方编译器都会自动将其替换为一个指向数组首元素的指针。 当我们将数组作为一个auto变量的初始值时推断得到的类型是指针而非数组。但是用decltype返回的类型仍然是数组 int ia[] {0, 1, 2, 3, 4};
auto ia2(ia); //ia2是一个整型指针
decltype(ia) ia3 {}; //含有5个元素的整型数组 我们可以像使用迭代器一样使用指针为了让指针的使用更简单、安全C11新标准引入两个名为begin和end的函数。这两个函数定义在iterator头文件中 int a[10] {};
int *beg begin(a); //相当于int *beg a;
int *last end(a); //相当于int *last a[10];同尾后迭代器一样尾后指针不能执行解引操作和递增操作 迭代器支持的操作指针都支持包括和整数进行加减、指针和指针的减法、指针和指针比较大小但是需要注意的是上面的操作两个指针要在同一个数组中才有意义。特别地允许给空指针加上或减去一个值为0 的整型常量表达式。两个空指针也循序彼此相减结果当然是0。 指针同时有解引和其他运算的时候最好加上括号标明运算顺序 标准库类型限定使用的下标必须是无符号类型而内置的下表运算无此要求 尽管C支持C风格字符串但在C程序中最好还是不要使用他们这是因为C风格字符串不仅使用起来不太方便而且极容易引发程序漏洞是诸多安全问题的根本原因。 C风格字符串存放在字符数组中并以空字符结束。 在头文件cstring中有一些操作C风格字符串的函数 strlen(p) 返回p的长度
strcmp(p1, p2) 比较p1和p2如果p1p2返回0如果p1p2返回负数否则返回正数
strcat(p1, p2) 将p2附加到p1之后返回p1
strcpy(p1, p2) 将p2拷贝给p1返回p1传入此类函数的指针必须指向以空字符作为结束的数组 任何出现字符串字面值的地方都可以用以空字符结束的字符数组来替代 允许使用以空字符结束的字符数组来初始化string对象或为string对象赋值在string对象的加法运算中允许使用以空字符结束的字符数组作为其中一个运算对象不能两个对象都是在string对象的复合赋值运算中允许使用以空白字符结尾的字符数组作为右侧的运算对象 string对象的成员函数c_str()返回值是一个C风格的字符串也就是说函数的返回值是一个指针 该指针指向一个以空字符结束的字符数组而这个数组所存的数据恰好与那个string对象一样。结果指针的类型是const char*从而确保我们不会改变字符数组的内容。我们无法保证c_str()函数返回的数组一直有效事实上如果后续的操作改变了s的值就可能让之前返回的数组失去作用。如果执行完c_str()函数后程序想一直都能使用其返回的字符数组最好将该数组重新拷贝一份。 const char *str s.c_str(); 允许使用数组来初始化vector对象只需要指明拷贝区域的首元素地址和尾后地址即可。 int int_arr[] {0, 1, 2, 3};
vectorint a(begin(int_arr), end(int_arr)); 现代的C程序应当尽量使用vector和迭代器避免使用内置数组和指针应该尽量使用string避免使用C风格的基于数组的字符串 C语言中没有多维数组通常所说的多维数组其实是数组的数组。 多维数组的初始化 int ia[3][4] {{0, 1, 2, 3}.{4, 5, 6, 7},{8, 9, 10, 11}
};
int ia[3][4] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
int ia[3][4] { {0}, {4}, {8} }; 只初始化每行的首元素其他未列出的元素执行默认初始化
int ia[3][4] {0, 3, 6, 9}; 只初始化第一行的元素其他的初始化为0 多维数组的操作 int (row)[4] ia[1]; //把row绑定到ia的第二个4元素数组上
int cnt 0;
for (auto row : ia) {for( auto col : row) {col cnt;}
} 注意要使用范围for循环处理多维数组除了最内层的循环外其他所有循环控制变量都应该是引用类型。如果不是引用类型编译器的会把数组类型转化成指针类型这样内层循环就无法使用范围for语句了因为对一个指针进行循环显然没有意义。 当程序使用多维数组的名字时也会自动将其转换成指向数组首元素的指针。因为多维数组实际上是数组的数组所以由多维数组名转换得来的指针实际上是指向第一个内层数组的指针。 int ia[3][4]
int (*p)[4] ia; //p指向含有4个整数的数组ia[0]
p ia[2]; //p指向ia的尾元素ia[2] 上面的括号必不可少如果没有括号int *p[4]的意义将会是大小为4的整型指针数组 随着C11新标准的提出通过使用auto或者decltype就能尽可能避免在数组前面加上一个指针类型了。 int a[3][4];
for (auto p ia; p ! ia 3; p) {
//int (*p)[4]for (auto q *p; q ! p 4; q) {//int *qcout *q ;}cout endl;
} 可以使用标准库函数begin和end实现同样的功能 for (auto p begin(ia); p ! end(ia); p) {for (auto q begin(*p); q ! end(*p); q) {cout *q ;}cout endl;
} 可以使用类型别名简化多维数组的指针 using int_arr int[4];
typedef int int_arr[4]; //同上面等价 第三章看完啦啦啦啦啦后面要稍微加快进度