1、C++ string类的方法
string 函数列表
函数名 描述
begin 得到指向字符串开头的Iterator
end
得到指向字符串结尾的Iterator
rbegin
得到指向反向字符串开头的Iterator
rend
得到指向反向字符串结尾的Iterator
size
得到字符串的大小
length
和size函数功能相同
max_size
字符串可能的最大大小
capacity
在不重新分配内存的情况下,字符串可能的大小
empty
判断是否为空
operator[]
取第几个元素,相当于数组
c_str
取得C风格的const char* 字符串
data
取得字符串内容地址
operator=
赋值操作符
reserve
预留空间
swap
交换函数
insert
插入字符
append
追加字符
push_back
追加字符
operator+=
+= 操作符
erase
删除字符串
clear
清空字符容器中所有内容
resize
重新分配空间
assign
和赋值操作符一样
replace
替代
copy
字符串到空间
find
查找
rfind
反向查找
find_first_of
查找包含子串中的任何字符,返回第一个位置
find_first_not_of
查找不包含子串中的任何字符,返回第一个位置
find_last_of
查找包含子串中的任何字符,返回最后一个位置
find_last_not_of
查找不包含子串中的任何字符,返回最后一个位置
substr
得到字串
compare
比较字符串
operator+
字符串链接
operator==
判断是否相等
operator!=
判断是否不等于
operator<
判断是否小于
operator>>
从输入流中读入字符串
operator<<
字符串写入
1)string substr(offset, length)
需要添加头文件<string>,头文件区分大小写
获取从offset位置开始,length长度的字符串
如果 length 为 0 或负数,将返回一个空字符串,如果没有指定该参数,则子字符串将延续到字符串的结尾。
2)int find_last_of(char c)
查找字符串中最后一个出现的c。有匹配,则返回匹配位置;否则返回-1.
2、char和string相互转化
string可以看成是以字符为元素的一种容器,标准的string类提供了STL容器接口,具有一些成员函数如begin()、end()
与char*不同的是,string不一定以NULL('\0')结束。
1)string转换成char*
不能将string直接赋值给char*
string.c_str() 返回有”\0“的字符串数组
string.data() 返回没有”\0“的字符串数组
2)char转换成string
可以直接赋值
string s;
char *p = "adghrtyh";
s = p;
也可以用char *来初始化string
string s(char *)
3、int stat(const char *file_name, struct stat *buf);
可以用来判断路径对应是文件还是目录,需要添加头文件 #include <sys/stat.h>、#include <unistd.h>
函数说明: 通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值: 执行成功则返回0,失败返回-1,错误代码存于errno
错误代码:
ENOENT 参数file_name指定的文件不存在
ENOTDIR 路径中的目录存在但却非真正的目录
ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接
EFAULT 参数buf为无效指针,指向无法存在的内存空间
EACCESS 存取文件时被拒绝
ENOMEM 核心内存不足
ENAMETOOLONG 参数file_name的路径名称太长
-----------------------------------------------------
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
先前所描述的st_mode 则定义了下列数种情况:
S_IFMT 0170000 文件类型的位遮罩
S_IFSOCK 0140000 scoket
S_IFLNK 0120000 符号连接
S_IFREG 0100000 一般文件
S_IFBLK 0060000 区块装置
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符装置
S_IFIFO 0010000 先进先出
S_ISUID 04000 文件的(set user-id on execution)位
S_ISGID 02000 文件的(set group-id on execution)位
S_ISVTX 01000 文件的sticky位
S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限
S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限
S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限
S_IRGRP 00040 用户组具可读取权限
S_IWGRP 00020 用户组具可写入权限
S_IXGRP 00010 用户组具可执行权限
S_IROTH 00004 其他用户具可读取权限
S_IWOTH 00002 其他用户具可写入权限
S_IXOTH 00001 其他用户具可执行权限
上述的文件类型在POSIX中定义了检查这些类型的宏定义:
S_ISLNK (st_mode) 判断是否为符号连接
S_ISREG (st_mode) 是否为一般文件
S_ISDIR (st_mode) 是否为目录
S_ISCHR (st_mode) 是否为字符装置文件
S_ISBLK (s3e) 是否为先进先出
S_ISSOCK (st_mode) 是否为socket
若一目录具有sticky位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名。
此处摘自:http://www.360doc.com/content/11/0110/16/4559801_85509847.shtml#
4、statvfs获取文件系统统计信息
摘自:http://yiibai.com/unix_system_calls/fstatvfs.html
#include <sys/statvfs.h>
5、map
标准std中只有map,是使用平衡二叉树实现的,查找和添加的复杂度都为O(log(n)),
没有提供hash map,gnu c++提供了hash_map,是一个hash map的实现,查找和添加复杂度均为O(1)。
map的功能自动建立”key - value“的对应,Key和Value可以是任意你需要的类型。每个key在map中只能出现一次。
包含头文件#include <map>
std:map<int, string> ,这样就定义了一个用int为索引,并拥有相关联的指向string的指针
C++Maps是一种关联式容器,包含“关键字/值”对
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数
1)map中3种插入数据的方法
第一种,用insert函数插入pair数据
第二种:用insert函数插入value_type数据
第三种:用数组方式插入数据,map数组可以用来赋值和读取,而vector只能读取
第一种和第二种在效果上是完成一样的,用insert函数插入数据,
在数据的插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是插入数据不了的,但是用数组方式就不同了,它可以覆盖以前该关键字对应的值,用程序说明
2)map的大小
在往map里面插入了数据,我们怎么知道当前已经插入了多少数据呢,可以用size函数,用法如下:
Int nSize = mapStudent.size();
3)数据的查找
第一种:用count函数来判定关键字是否出现,其缺点是无法定位数据出现位置,由于map的特性,一对一的映射关系,就决定了count函数的返回值只有两个,要么是0,要么是1,出现的情况,当然是返回1了
第二种:用find函数来定位数据出现位置,传入的参数是key,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器,程序说明
4)数据的清空与判空
清空map中的数据可以用clear()函数,判定map中是否有数据可以用empty()函数,它返回true则说明是空map
5)数据的删除
这里要用到erase函数,它有三个重载了的函数,下面在例子中详细说明它们的用法
在map insert value的时候出现问题如下:
一大串错误说实话很不想看,但我猜了一下估计是key值的问题,于是谷歌一下,发现确实
原来map中的key默认是以less<>升序对元素排序(排序准则也可以修改),也就是说key必须具备operator<对元素排序,而平常我们的用的基本上都是基本类型元素作为key,所以就不存在这个问题了,更详细的解释请看C++标准程序库一书,第六章,set容器章节。
因此,原则上只要支持操作符 < 都可以作为key类型。
在我的map的定义中map<MtpInt128, ObjHandle>里面的key MtpInt128是个类,里面没有实现operator < 这个成员函数
具体的实现如下,格式必须满足要求,常函数,参数类型是常数:
6、vector
容器中所有对象必须是同种类型,我们可以定义保存string对象的 vector,或保存int值的vector,又或是保存自定义的类类型对象。
基本操作
(1)头文件#include<vector>.
(2)创建vector对象,vector<int> vec;
(3)尾部插入数字:vec.push_back(a);在末尾增加一个值为a的元素
(4)使用下标访问元素,cout<<vec[0]<<endl;记住下标是从0开始的。记住下标只能用于访问,不能用于赋值。
(5)使用迭代器访问元素.
(6)插入元素: vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;
(7)删除元素: vec.erase(vec.begin()+2);删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
(8)向量大小:vec.size();
(9)清空:vec.clear();
7、list
#include <list>
C++ STL提供了一些容器,list、vector、map、set
STL iterator是容器中指向对象的指针,STL使用iterator在容器上进行操作。
1)push_back和push_front,push_back将对象放到一个list的后面,而push_front把对象放到前面。
list<string> a;
a.push_back("chocolate");
a.push_back("strawberry");
2)empty()
8、vector与list的区别
vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,因此他能很好的支持随机存取(即使用[]操作符访问元素),但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝(复杂度是O(n)),另外,当该数组后的内存空间不够时,需要重新申请一块足够大的内存并进行内存的拷贝。这些都大大影响了vector的效率。
list是由数据结构中的双向链表实现的,因此它的内存空间可以是不连续的。因此只能通过指针来进行数据的访问,这个特点使得它的随机存取变的非常没有效率,需要遍历中间的元素,搜索复杂度O(n),因此它没有提供[]操作符的重载。但由于链表的特点,它可以以很好的效率支持任意地方的删除和插入。
另外list::iterator与vector::iterator也有一些不同
由于vector拥有一段连续的内存空间,能非常好的支持随机存取,因此vector<int>::iterator支持“+”、“+=”、“<”等操作符。
而list的内存空间可以是不连续,它不支持随机访问,因此list<int>::iterator则不支持“+”、“+=”、“<”等操作符运算。只能使用“++”进行迭代
总之,如果需要高效的随即存取,而不在乎插入和删除的效率,使用vector;如果需要大量的插入和删除,而不关心随即存取,则应使用list。
摘自:http://genwoxuevc.blog.51cto.com/1852984/503337
9、C/C++中的日期和时间tmie_t,struct tm
1)struct tm
在标准C/C++中,我们可通过tm结构来获得日期和时间,tm结构在time.h中的定义如下:
#ifndef _TM_DEFINED
struct tm {
int tm_sec; /* 秒 – 取值区间为[0,59] */
int tm_min; /* 分 - 取值区间为[0,59] */
int tm_hour; /* 时 - 取值区间为[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
int tm_year; /* 年份,其值等于实际年份减去1900 */
int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */
int tm_yday; /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */
int tm_isdst; /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst()为负。*/
};
#define _TM_DEFINED
#endif
ANSI C标准称使用tm结构的这种时间表示为分解时间(broken-down time)。
2)time_t
而日历时间(Calendar Time)是通过time_t数据类型来表示的,用time_t表示的时间(日历时间)是从一个时间点(例如:1970年1月1日0时0分0秒)到此时的秒数。在time.h中,我们也可以看到time_t是一个长整型数:
#ifndef _TIME_T_DEFINED
typedef long time_t; /* 时间值 */
#define _TIME_T_DEFINED /* 避免重复定义 time_t */
#endif
3)time_t转成struct tm
struct tm * gmtime(const time_t *timer);
struct tm * localtime(const time_t * timer);
4)将时间结构体转为字符串
我们可以通过asctime()函数和ctime()函数将时间以固定的格式显示出来,两者的返回值都是char*型的字符串。返回的时间格式为:
星期几 月份 日期 时:分:秒 年\n\0
例如:Wed Jan 02 02:03:55 1980\n\0
其中\n是一个换行符,\0是一个空字符,表示字符串结束。下面是两个函数的原型:
char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);
10、linux c++输出debug信息
三个重要的宏
__LINE__ 当前的行号
__FILE__ 当前的文件名(xxx.cpp)
__PRETTY_FUNCTION__/__FUNCTION__ 带签名和不带签名的函数名
11、C++类构造函数初始化
上面的例子中两个构造函数的结果是一样的。
上面的构造函数(使用初始化列表的构造函数)显式的初始化类的成员;而没使用初始化列表的构造函数是对类的成员赋值,并没有进行显式的初始化。
有的时候必须用带有初始化列表的构造函数:
1.成员类型是没有默认构造函数的类。若没有提供显示初始化式,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败。
2.const成员或引用类型的成员。因为const对象或引用类型只能初始化,不能对他们赋值。
初始化数据成员与对数据成员赋值的含义是什么?有什么区别?
首先把数据成员按类型分类并分情况说明:
1.内置数据类型,复合类型(指针,引用)
在成员初始化列表和构造函数体内进行,在性能和结果上都是一样的
2.用户定义类型(类类型)
结果上相同,但是性能上存在很大的差别。
因为类类型的数据成员对象在进入函数体前已经构造完成,也就是说在成员初始化列表处进行构造对象的工作;
调用构造函数,在进入函数体之后,进行的是对已经构造好的类对象的赋值,又调用个拷贝赋值操作符才能完成(如果并未提供,则使用编译器提供的默认按成员赋值行为)
Note:
初始化列表的成员初始化顺序:
C++初始化类成员时,是按照声明的顺序初始化的,而不是按照出现在初始化列表中的顺序。
Example:
你可能以为上面的代码将会首先做m_y=y,然后做m_x=m_y,最后它们有相同的值。但是编译器先初始化m_x,然后是m_y,,因为它们是按这样的顺序声明的。结果是m_x将有一个不可预测的值。有两种方法避免它,一个是总是按照你希望它们被初始化的顺序声明成员,第二个是,如果你决定使用初始化列表,总是按照它们声明的顺序罗列这些成员。这将有助于消除混淆。