C++编程细节(持续更新)

1. \n 与 endl 的区别

\n和endl均有换行功能,区别在于:
    endl比’\n’多了一个“刷新”流缓冲的flush操作。以文件输出流为例:当流的缓冲区未满时,写入’\n’不会马上写到文件里,但执行endl会“强行”把缓冲区的内容写入文件。故endl不仅换行,还刷新流缓冲。并且在VS2015中按F12转到endl定义,写着insert newline and flush stream。综上,\n比endl高效。
    在不同操作系统中,endl比\n可移植性要好(有待探索)。

2. sizeof函数

定义
sizeof是一个操作符(operator)。
其作用是返回一个对象或类型所占的内存字节数。

语法
1) sizeof (object); //sizeof (对象)
2) sizeof object; //sizeof 对象
3) sizeof (type_name); //sizeof (类型)

说明
        1. 对象可以是各种类型的变量,以及表达式。一般sizeof不会对表达式进行计算。
        2. sizeof对对象求内存大小,最终都是转换为对对象的数据类型进行求值。
        3. sizeof (表达式); //值为表达式的最终结果的数据类型的大小。

实例

int i;
cout << sizeof(int) << "\n"; //值为4  
cout << sizeof(i) << "\n"; //值为4,等价于sizeof(int)  
cout << sizeof i << "\n"; //值为4  
cout << sizeof(2) << "\n"; 
//值为4,等价于sizeof(int),因为2的类型为int  
cout << sizeof(2 + 3.14) << "\n";
//值为8,等价于sizeof(double),因为此表达式的结果的类型为double  

了解更多:c++中sizeof()的用法介绍

3. float保留7位有效数字的问题

  1. 有效位包括整数部分和小数部分,不包括小数点。
  2. float的有效位数是6位 或 7位,具体取决于编译器。
  3. double的有效位数是15位 或 16位,具体取决于编译器。
  4. %f默认保留小数点后六位。
float f1 = 7.123456789;
float f2 = 7.123456885;
float f3 = 7.123459;
cout << (f1 != f2 ? "not same\n" : "same\n");//same,前7位相等,均为7.123456
cout << (f1 != f3 ? "not same\n" : "same\n");//not same,前7位不等
//说明float的有效位数是7位

double d1 = 12345.123456789012345;
double d2 = 12345.123456789012222;
double d3 = 12345.123456789022222;
cout << (d1 != d2 ? "not same\n" : "same\n");//same
cout << (d1 != d3 ? "not same\n" : "same\n");//not same
//说明double的有效位数是16位

其他例子:

float f = 12.123456789;
float m = 12.123466666;//与f前6位相同
float x = 12.123457999;//与f前7位相同
float y = 12.123457001;//与f前7位相同
printf("%f\n", f);//12.123457
cout << f << "\n";//12.1235
cout << m << "\n";//12.1235
cout << x << "\n";//12.1235
//printf与cout都进行了四舍五入,不过%f默认保留小数点后六位,C++默认流输出数值有效位是6。
cout << (f != m ? "not same\n" : "same\n");//not same
cout << (f != x ? "not same\n" : "same\n");//not same
cout << (f != y ? "not same\n" : "same\n");//same
//这里分析为,两浮点数之差接近0,就认为相等,否则不等。

了解更多:关于float有效位数为7位的研究

4. string类元素存取

       可使用下标操作符[]和函数at()对元素包含的字符进行访问。但要注意操作符[]并不检查索引是否有效(有效索引0~str.length()-1),如果索引失效,会引起未定义的行为。而at()会检查,如果使用at()的时候索引无效,会抛出out_of_range异常。
       有一个例外,const string a;的操作符[]对索引值a.length()仍然有效,其返回值是’\0’。其他的各种情况,a.length()索引都是无效的。
       举例如下:

const string Cstr("const string");
string Str("string");
//两种方法都可以存取元素
cout<< Str[3];    //ok
cout<< Str.at(3);  //ok

//无效索引时的情况
cout << Str[100]; //未定义的行为
cout << Str.at(100);  //throw out_of_range 

cout<< Str[Str.length()]; //【未定义行为=>似乎也返回'\0'(有待理论研究)】
cout<< Cstr[Cstr.length()];//返回'\0' 

Str.at(Str.length());//throw out_of_range
Cstr.at(Cstr.length()); //throw out_of_range

       不赞成类似于下面的引用或指针赋值:
           char& r=s[2];
           char* p= &s[3];
       因为一旦发生重新分配,r,p立即失效。避免的方法就是不使用。

string类函数列表
在这里插入图片描述
了解更多:C++之string类型详解


5. string类的size()与length()函数

       C++ string的size()和length()函数没有区别
       C++标准库中的string中两者的源代码如下:

  size_type   __CLR_OR_THIS_CALL   length()   const   
  { //   return   length   of   sequence   
  return   (_Mysize);   
  }   
    
  size_type   __CLR_OR_THIS_CALL   size()   const   
  { //   return   length   of   sequence   
  return   (_Mysize);   
  }   

       所以两者没有区别。
       length是因为沿用C语言的习惯而保留下来的,string类最初只有length,引入STL之后,为了兼容又加入了size,它是作为STL容器的属性存在的,便于符合STL的接口规则,以便用于STL的算法。
       string类的size()/length()方法返回的是字节数,不管是否有汉字。

       参考文章:C++ string的size()和length()函数没有区别

6. sort()函数

  • sort函数可以三个参数也可以两个参数;
  • 必须的头文件是#include < algorithm>和using namespace std;
  • 它使用的排序方法是类似于快排的方法,时间复杂度为n*log2(n);
  • sort函数有三个参数:(第三个参数可不写)
    1)第一个是要排序的数组的起始地址;
    2)第二个是结束的地址(最后一位要排序的地址);
    3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。

两个参数的用法:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void main() {
	int a[] = { 33,61,12,19,14,71,78,59 };
	vector<int> aa(a, a + 8);
	sort(aa.begin(), aa.end());//两个参数
	for (vector<int>::iterator it = aa.begin(); it != aa.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}
//运行结果:12 14 19 33 59 61 71 78(默认升序排列)

三个参数的用法:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

bool descend(int i, int j) { 
	return (i>j); 
}

void main() {
	int a[] = { 33,61,12,19,14,71,78,59 };
	vector<int> aa(a, a + 8);
	sort(aa.begin(), aa.end(),descend);//三个参数
	for (vector<int>::iterator it = aa.begin(); it != aa.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}
//运行结果:78 71 61 59 33 19 14 12(降序排列)

sort和stable_sort的区别

  • sort是快速排序实现,因此是不稳定的;stable_sort是归并排序实现,因此是稳定的;
  • 对于相等的元素sort可能改变顺序,stable_sort保证排序后相等的元素次序不变;
  • 如果提供了比较函数,sort不要求比较函数的参数被限定为const,而stable_sort则要求参数被限定为const,否则编译不能通过。

参考文章:c++中sort()函数的用法
                 C++中sort和stable_sort的区别

7. clock函数

定义

clock_t clock( void );

说明

  • clock() 函数返回从开启这个程序进程到程序中调用clock()函数时之间的CPU时钟计时单元(clock tick)数,也称挂钟时间(wal-clock)。
  • typedef long clock_t,clock_t实际为long 类型。
  • 常量CLOCKS_PER_SEC表示一秒会有多少个时钟计时单元,其定义如下:

// The number of clock ticks per second
#define CLOCKS_PER_SEC ((clock_t)1000)
#define CLK_TCK CLOCKS_PER_SEC

用法

#include <iostream>
#include <time.h>
using namespace std;
int main(int argc, char** argv) {	 
	clock_t start = clock();
	for (int i = 0; i < 10000; i++)
		cout << i << " ";
	clock_t finish = clock();
	double  duration = (double)(finish - start) / CLOCKS_PER_SEC;
	cout << "\nThe duration is " << duration << "seconds" << endl;
	system("pause");
} 

运行结果:
在这里插入图片描述

8. 常数后缀说明

1.数值常数有:整型常数、浮点常数;
2.只有数值常数才有后缀说明;
3.数值常数后缀不区分字母大小写。
1)整型常数的表示形式有:十进制形式、以0开头的八进制形式、以0x开头的十六进制形式,无二进制形式。
   整型常数默认是signed int的。
   对整型常数进行类型转换的后缀只有:u或U(unsigned)、l或L(long)、u/U与l/L的组合(如:ul、lu、Lu等)。例:100u;  -123u;  0x123l;
2)浮点常数的表示形式有:科学计数形式和小数点形式。
   浮点常数默认是double的。
   对浮点常数进行类型转换的后缀只有:f或F(单精度浮点数)、l或L(长双精度浮点数)。(注:因浮点型常数总是有符号的,故没有u或U后缀)。例:1.23e5f;  1.23l;  -123.45f;

参考文章:c++ 常数后缀说明


9. cin.ignore()

cin.ignore()用于输入流,其调用形式为cin.ignore(n,终止字符)。函数原型如下:

istream &ignore( streamsize num = 1, int delim = EOF );

作用: 跳过输入流中n个字符,或在遇到指定的终止字符时提前结束(此时跳过包括终止字符在内的若干字符)。

cin.ignore(1024.’\n’);

效果: 第一个参数设置的足够大,表示将回车(包括回车)之前的数据全部清除,此举在保证回车符之前的数据被使用后,可以当作刷新输入缓冲区的方式使用。

#include <iostream>
using namespace std;

int main(int argc, char** argv) {
	char array[20];
	//cin.ignore();	//默认 n = 1,忽略第一个字符:Apple  => pple
	//cin.ignore(8, 'e');//遇到指定结束符'e'而结束:ApplePie => Pie
	cin.ignore(3, 'e');//忽略掉3个字符而结束:ApplePie => lePie
	cin.getline(array, 8);
	cout << array << endl;	
}
#include <iostream>
using namespace std;

int main(int argc, char** argv) {
	int a, b, c;
	cout << "input a:";
	cin >> a;
	cin.ignore(1024, '\n');
	cout << "input b:";
	cin >> b;
	cin.ignore(1024, '\n');
	cout << "input c:";
	cin >> c ;
	cout << a << "\n" << b << "\n" << c << endl;
	//如果没有cin.ignore(),可以一次输入3个数,用空格隔开,但是不美观
}

/*运行结果:
	input a:12 34 56
	input b:78 90 92
	input c:98
	12
	78
	98	
*/

参考文章:ignore函数——百度百科
                  一眼就能看懂的cin.ignore()函数详解
                  C++ cin.ignore() 的使用
                  std::istream::ignore() 函数

10. 强制类型转换

        强制类型转换的一般形式为: (类型名)(表达式) 。

注意: 如果要进行强制类型转换的对象是一个变量,该变量可以不用括号括起来。如果要进行强制类型转换的对象是一个包含多项的表达式,则表达式应该用括号括起来。

        以上强制类型转换的形式是原来C语言使用的形式,C++把它保留了下来,以利于兼容。
        C++还增加了以下形式:类型名(表达式) ,如 int(x) 或 int(x+y) 。
        类型名不加括号,而变量或表达式用括号括起来。这种形式类似于函数调用。但许多人仍习惯于用第一种形式,把类型名包在括号内,这样比较清楚。
        在强制类型转换时,得到一个所需类型的中间变量,但原来变量的类型未发生变化。

参考文章:C++强制类型转换

11. seekg()用法

seekp:设置输出文件流的文件流指针位置,p是put缩写
seekg:设置输入文件流的文件流指针位置,g是get缩写

seekg()
Moves the read position in a stream.//移动在流中读的位置
------------------------------------------------------------------------
basic_istream<Elem, Tr>& seekg(  //一个参数
    pos_type pos
);
basic_istream<Elem, Tr>& seekg( //两个参数
    off_type off,                                    
    ios_base::seekdir way
);
------------------------------------------------------------------------
//参数
pos 
The absolute position in which to move the read pointer.
//移动读取指针的绝对位置

off //偏移量
An offset to move the read pointer relative to way.

way //  基地址
One of the ios_base::seekdir enumerations.
//它有三个取值
//ios::beg:表示输入流的开始位置
//ios::cur:表示输入流的当前位置
//ios::end:表示输入流的结束位置
#include <fstream>
#include <iostream>
using namespace std;

int main(int argc, char** argv) {
	ifstream in("test.txt");//test.txt内容为:0123456789abcdefg
	char c1, c2, c3,c4,c5;
	in.seekg(0);
	in >> c1;//c1 = 0
	in.seekg(6);
	in >> c2;//c2 = 6
	in.seekg(4, ios::beg);
	in >> c3;//c3 = 4
	in.seekg(-1, ios::end);
	in >> c4;//c4 = g
	in.seekg(2, ios::end);//一旦指针到达文件末尾,就无法再将指针指向文件其他位置
	in >> c5;//c5 = 空
	cout << "c1 = " << c1 << "\n"
		 << "c2 = " << c2 << "\n"
		 << "c3 = " << c3 << "\n"
		 << "c4 = " << c4 << "\n"
		 << "c5 = " << c5 << "\n" << endl;
}
	
/*运行结果:
	c1 = 0
	c2 = 6
	c3 = 4
	c4 = g
	c5 =
*/

参考文章:C++ seekg()函数
                 c++ fstream中seekg()和seekp()的用法

12. STL函数

count()函数

  • 形式:count(first,last,value),返回int型。
  • first是容器的首迭代器,last是容器的末迭代器,value是询问的元素。
  • 功能:统计容器中等于value元素的个数。

set_difference()函数

       用于求两个集合的差集,结果集合中包含所有属于第一个集合但不属于第二个集合的元素。
       由于区间S1,S2内的每个元素都不需唯一,因此,如果某个值在S1中出现m次,在S2中出现n次,那么该值在输出区间中出现的次数为max(m-n,0),且全部来自S1。

重载1
OutputIterator set_difference(
       InputIterator1 first1,
       InputIterator1 last1,
       InputIterator2 first2,
       InputIterator2 last2,
       OutputIterator result
);
注:需保证第一集合和第二集合有序,并从小到大排序,内部使用默认“<”操作符比较元素大小;

重载2
OutputIterator set_difference(
       InputIterator1 first1,
       InputIterator1 last1,
       InputIterator2 first2,
       InputIterator2 last2,
       OutputIterator result,
       Compare comp
);
注:需保证第一集合和第二集合有序,排序方式参照Compare确定,内部使用Compare比较元素大小。

参数:first1、last1分别是第一个集合的开始位置、结束位置,first2、last2分别是第二个集合的开始位置、结束位置,result是结果集合的插入迭代器。

返回值:结果集合的结束位置迭代器。

说明:
1.第五个参数可有多重版本。
2.set_difference(A.begin(),A.end(),B.begin(),B.end(),inserter( C1 , C1.begin() ) );第五个参数的意思是将集合A、B取差集后的结果存入集合C中。
3.set_difference(A.begin(),A.end(),B.begin(),B.end(),ostream_iterator(cout," “)); 第五个参数的意思是将集合A、B取差集后的结果直接输出,(cout,” ")双引号里面是用来间隔集合元素的符号或空格。

实现:

#include <iterator>
#include <iostream>
#include<algorithm>
using namespace std;

int main(int argc, char** argv) {
	string s = "14325";
	string t = "21";
	string C1;
	sort(s.begin(), s.end());//12345
	sort(t.begin(), t.end());//12
	set_difference(s.begin(), s.end(), t.begin(), t.end(), inserter(C1, C1.begin()));
	cout << C1 << endl;//345
	set_difference(s.begin(), s.end(), t.begin(), t.end(), ostream_iterator<char>(cout, " "));
	cout << endl;//3 4 5
}	

参考文章:关于C++里set_difference的使用总结
                  STL之交集、并集、差集
                  C++集合操作之集合并集:std::set_difference
                  set_difference的使用

13. find函数

功能:在字符串中查找某字符或某子串,如果找到,就返回字符在字符串中的位置或子串在字符串中第一次出现的位置,否则返回string::npos,即 -1。

#include <iostream>
using namespace std;

int main(int argc, char** argv) {
	string s1 = "abcdefjklmn";
	int pos1 = s1.find('d'); //在s1中查找字符'd',返回下标3
	int pos2 = s1.find("de");//在s1中查找子串"de",返回下标3
	int pos3 = s1.find("d", 3);//在s1中查找子串"de",从下标3开始查找,返回下标3
	int pos4 = s1.find("uvw");//在s1中查找子串"uvw",返回-1
	//判断s1是否包含子串"lmn"
	if (s1.find("lmn") == string::npos)
		cout << "Not" << endl;
	else
		cout << "Yes" << endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值