近期在图像处理(主要是硬件方面)刚接触C/C++语言,毫无头绪,特写一篇语法指令的博客,记录一些学习心得,供自己与他人一同学习。
注:本博客撰写过程中参考了网上许多大佬的博客,都有在每个函数中标注,再次表示感谢!
1、ifstream,ofstream
下面是常用的读取文件流的方式,ifstream实际是一种定义,类似常见的int,只不过这里定义的是“输入文件流”,ofstream定义的是“输出文件流”。常用的代码如下:
ifstream listFile; //定义listFile为输入流文件
string fileName = "images.txt"; //定义字符串fileName=“images.txt"
listFile.open(fileName); //调用文件流的成员函数open,打开文件fileName,建立磁盘文件和文件流的联系
listFile.close(); //调用成员函数close,断开文件流listFile和磁盘文件的联系,使listFile可以读取其他磁盘文件的信息
ifstream fin("data.txt");
也有人写成这种形式,实际等效于下面这种表示方式(data.txt应该与.c文件放在同一目录)
ifstream fin;
string fileName = "data.txt";
fin.open(fileName)
2、getline
C++虽然可以使用 cin 和 >> 运算符来输入字符串,但cin无法读取整行,遇到空格会停止,为实现整行读取,引入getline函数。getline不是C库函数,而是gcc的扩展定义或者C++库函数。它会生成一个包含一串从输入流读入的字符的字符串,直到以下情况发生会导致生成的此字符串结束。
1)到文件结束,
2)遇到函数的定界符,
3)输入达到最大限度。
用法:
getline ( is, str, delim);
is是一个文件流,例如cin
str是一个string类型的引用,读入的字符串将直接保存在str里面
delim是结束标志,默认为换行符,也可以为空
注意:getline无法读取换行符
3、imread,imshow用法(文件路径)
imread读取图片时有两种路径填写方式
A:绝对路径
绝对路径有两种方式,注意双反斜杠\和单斜杆的区别:
frame = imread("D:\\Desktop\\Basketball\\img\\0001.jpg");
frame = imread("D:/Desktop/Basketball/img/0001.jpg");
B:相对路径
frame = imread("./Basketball/img/0001.jpg");
./指的是在当前路径下,即省略.c文件所在文件的目录。
…/指的是上一级目录。
imshow使用时,需要与waitKey(N)
使用,waitKey(N)表示等待N毫秒
4、C 语言中 include <> 与include “” 的区别
#include < > 引用的是编译器的类库路径里面的头文件。
#include " " 引用的是你程序目录的相对路径中的头文件,如果在程序目录没有找到引用的头文件则到编译器的类库路径的目录下找该头文件。
5、cin、cout输入输出
在C++程序中,输入与输出可以看做是一连串的数据流,输入即可视为从文件或键盘中输入程序中的一串数据流,而输出则可以视为从程序中输出一连串的数据流到显示屏或文件中。cin与cout类似于C语言中的scanf
和printf
。
在编写C++程序时,如果需要使用输入输出时,则需要包含头文件iostream。
使用 cout 进行输出时需要紧跟“<<”操作符,使用 cin 进行输入时需要紧跟“>>”操作符。
例子:
cout<<fixed<<A;
fixed就是用一般的方式输出浮点数A,而不是科学计数法;
6、void
void在C和C++中含义略有不同。
在C语言中
如果在声明函数的时候如果没有任何参数那么需要将参数定义为void以此来限定此函数不可传递任何参数(下面代码的第二种情况),如果不进行限定让参数表默认为空其意义是可以传递任何参数(下面代码中的第一种情况)。
//空参数表代表可以传递任意的参数,
void fun();
fun(1);//正常编译
fun(1,2,3);//正常编译
//参数表定义为void才是表示不能传递任何参数
void noargfun(void);
noargfun(1);//编译错误,有的编译器仅仅是警告
在C++中
- 如果函数没有返回值,那么应声明为void类型
void fun()
; - 如果函数无参数,那么应声明其参数为void----
fun(void)
; - 如果函数的参数可以是任意类型指针,那么应声明其参数为
void *
,比如void *pst
,类似于int*
,只不过不表示指针类型为int; - void不能代表一个真实的变量;
参考:关于C++中的void及void *
C++标准规定如果没有对参数列表进行定义那么就表示函数不能传递任何参数(参考C++ void参数)
//空参数表的意义是不可以传递任何参数
void fun();//void fun(void)含义相同
fun(1);//编译错误
fun(1,2,3);//编译错误
7、Vector函数使用
vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间的目的.即vector能存放任意类型的动态数组,并随时增加或删除数据。
使用方法如下
vector<int> c.
c.clear() 移除容器中所有数据。
c.empty() 判断容器是否为空。
c.erase(pos) 删除pos位置的数据
c.erase(beg,end) 删除[beg,end)区间的数据
c.front() 传回第一个数据。
c.insert(pos,elem) 在pos位置插入一个elem拷贝
c.pop_back() 删除最后一个数据。
c.push_back(elem) 在尾部加入一个数据。
c.resize(num) 重新设置该容器的大小
c.size() 回容器中实际数据的个数。
c.begin() 返回指向容器第一个元素的迭代器
c.end() 返回指向容器最后一个元素的迭代器
例子
vector<pair<int,string> >
pair<int,string>就是定义一个对象类型,该类型对象有两个数据度,first是int型,second是string类型。比如可以把一个页码值和该页出现的单词对应起来。pair<int,string>放入内容器vector就是建立了一个pair类型的集合,就能把每一页的内容集合起来写一本字典。
参考网页vector<int>test;//建立一个vector
test.push_back(1);
test.push_back(2);//把1和2压入vector,这样test[0]就是1,test[1]就是2,push.back主要是在test末尾加一个成员vector<vector <int> > array(3);
//定义了行数为3列数不定的二维数组
array.size()//返回二维数组的行数
array[0].size()//返回二维数组第一行的列数std::vector<cv::Mat> a;
//定义一个矩阵向量,比如10×10×5,a[1]
就是一个10×10
矩阵
8、filesystem详解
filesystem是boost库下的一个函数
path 类:该类只是对字符串(路径)进行一些处理,这也是文件系统的基石,用于存储文件的母路径等。
directory_entry 类:文件入口,这个类才真正接触文件。
directory_iterator 类:获取文件系统目录中文件的迭代器容器,其元素为directory_entry对象(可用于遍历目录)
file_status 类:用于获取和修改文件(或目录)的属性(需要了解C++11的强枚举类型(即枚举类))
#include<boost/filesystem.hpp>
{
boost::filesystem::path path("/test/test1"); //初始化,定义一个path存储在filesysten::path中
boost::filesystem::path old_cpath = boost::filesystem::current_path(); //取得当前程序所在目录 old_cpath
boost::filesystem::path parent_path = old_cpath.parent_path();//取old_cpath的上一层父目录路径
boost::filesystem::path file_path = old_cpath / "file"; //path支持重载/运算符
if(boost::filesystem::exists(file_path)) //判断文件存在性
{
std::string strPath = file_path.string();
int x = 1;
}
else
{
//目录不存在;
boost::filesystem::create_directory(file_path); //目录不存在,创建
}
bool bIsDirectory = boost::filesystem::is_directory(file_path); //判断file_path是否为目录
boost::filesystem::recursive_directory_iterator beg_iter(file_path);
boost::filesystem::recursive_directory_iterator end_iter;
for (; beg_iter != end_iter; ++beg_iter)
{
if (boost::filesystem::is_directory(*beg_iter))
{
continue;
}
else
{
std::string strPath = beg_iter->path().string(); //遍历出来的文件名
int x=1;
}
}
boost::filesystem::path new_file_path = file_path / "test.txt";
if(boost::filesystem::is_regular_file(new_file_path)) //判断是否为普通文件
{
UINT sizefile = boost::filesystem::file_size(new_file_path); //文件大小(字节)
int x =1;
}
boost::filesystem::remove(new_file_path);//删除文件new_file_path
}
9、memcpy函数
复制任意内容,例如字符数组、整型、结构体、类,并由第三个参数决定复制内容的长度
例子
void *memcpy(void *dest, const void *src, size_t n);
功能:
从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中所需头文件:
与strcpy的差异
strcpy只能复制字符串,直到遇到“/0”字符才停止复制
10、ioctl函数
ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等
例子
int ioctl(int fd, int cmd, struct cmddata);
其中fd就是用户程序打开设备时使用open函数返回的设备文件描述符;
cmd就是用户程序对设备的控制命令
cmddata与控制命令cmd一一对应
11、select函数
select是Linux/Unix环境下的高级网络I/O编程接口,它使我们能够进行基于I/O多路转接。I/O多路转接(multiplexing)的核心思想是:先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已经准备好进行I/O时,该函数才返回。在返回时,它告诉进程哪些描述符已准备好可以进行I/O操作。
例子参考博客
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
(1)执行fd_set set;
(2) FD_ZERO(&set);清零,set用位表示是0000,0000。
(3)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
(4)若再加入fd=2,fd=1,则set变为0001,0011
(5)执行select(6,&set,0,0,0)阻塞等待
(6)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。
由于我是服务器端主程序,只关心是否收到对端发来的消息或通知事件,因此我只需要监听某个端口
采用select检查相应的套接字描述符是否有数据可读。
调用FD_ZERO(&readfds)将一个指定的fd_set变量(read_fds)所有位设置为0
调用FD_SET(m_server_sock, &readfds)将read_fds变量的第m_server_sock个位置1。
如果select返回-1,说明有错误;如果为0, 说明超时了;否者说明我们关心的描述符准备好了。当有数据可读时,内核(I/O)根据状态修改文件描述符集,select返回一个大于0的数,该数值表示已经准备好的描述符个数
可以理解为select是一个监视的过程,fd_set建立一个所有端口fd的集合,fd_zero负责清零,之后fd_set负责将我们要关心的端口fd进行标记,即将一个给定的文件描述符加入集合之中,当这些文件描述符对应的端口在指定时间内有数据进入,select返回大于0的值表示端口设备fd已就绪。
12、feof函数
feof()
是检测流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回0。文件结束符EOF是一个计算机术语,为End Of File
的缩写,在操作系统中表示资料源无更多的资料可读取。资料源通常称为档案或串流。通常在文本的最后存在此字符表示资料结束。
对feof()来说,它的工作原理是,站在光标所在位置,向后看看还有没有字符。如果有,返回0;如果没有,返回非0。它并不会读取相关信息,只是查看光标后是否还有内容。
对于一个空文件来说,当程序打开它的时候,它的光标会停在文件的开头,但是由于文件里什么内容都没有存(但是EOF是存在的),即整个文件就存贮了一个EOF。当程序打开文件,并直接调用feof()时,这个函数就会站在光标的位置向后张望,结果就看见了EOF,然后就当然返回0了。所以检测文件是否为空文件通常和getc
函数相结合。
例子
#include<stdio.h>
int main(void)
{
FILE *p;
p = fopen("open.txt", "r");
getc(p); ##getc 先读取一个字符,光标向后移动一个字符,如果是空文档,此时EOF将被getc读取到p,而feof将返回非0值
if (feof(p))
{
printf("文件为空。");
}
else
{
rewind(p);//将光标跳回到文件开头
int a;
fscanf(p,"%d",&a);
printf("%d", a);
}
return 0;
}
13、fseek函数,rewind函数,ftell函数
C语言读取文件内容的流程大致是:打开文件–>一个字节一个字节读取–>遇到结束符–>关闭文件,而如何确定读取文件中哪个位置的字节内容呢?主要是利用文件指针确定读取文件内容的位置。
fseek函数主要是定位文件指针的位置,以下面这句为例,表示以origin为基准位置,偏移offset个字节位置,如果返回失败(比如偏移量offset超出文件大小),则不改变当前文件指针位置,详细定义如下
int fseek( FILE *stream, long offset, int origin )
1、stream为文件指针
2、offset为偏移量,整数表示正向偏移,负数表示负向偏移。单位是字节。
3、origin设定从文件的哪里开始偏移,可能取值为:SEEK_CUR
(当前位置)、 SEEK_END
(文件结尾) 或 SEEK_SET
(文件开头)
其中SEEK_SET,SEEK_CUR和SEEK_END
和依次为0,1和2.
例子
fseek(fp,100L,0);把fp指针移动到离文件开头100字节处;
fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处;
fseek(fp,100L,2);把fp指针退回到离文件结尾100字节处。
参考博客
rewind 函数用于将文件内部的位置指针重新指向一个流(数据流或者文件)的起始位置。函数原型:void rewind(FILE *fp);
ftell函数用于得到文件位置指针当前位置相对于文件首的偏移字节数。一般可以用来获取文件的长度。
fseek(fp, 0L,SEEK_END);
len =ftell(fp);
14、fread/fwrite函数
fwrite 和 fread 是以记录为单位的 I/O 函数,fread 和 fwrite 函数一般用于二进制文件的输入输出。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr用于接收数据的内存地址,大小至少是 size* count字节;
size单个元素的大小,单位是字节;
nmemb元素的个数,每个元素是size字节;
sream输入流文件
详解:fread 和 fwrite 用于读写记录,这里的记录是指一串固定长度的字节,比如一个 int、一个结构体或者一个定长数组。参数 size
指出一条记录的长度,而 nmemb
指出要读或写多少条记录,这些记录在 ptr 所指的内存空间中连续存放,共占 size * nmemb
个字节,fread 从文件 stream 中读出size * nmemb
个字节保存到 ptr
中,而 fwrite 把 ptr 中的 size * nmemb
个字节写到文件 stream
中。
返回值为实际读取/写入的个数,如果与nmemb不相等,则可能存在错误
15、fopen与fopen_s函数
FILE * fp
fp=fopen(const char *filename, const char *mode); 文件打开成功后,将文件指针返回fp
int result
result=fopen_s( FILE* pFile, const char *filename, const char *mode);文件打开成功返回0,否则返回其他值。
例子
int result;
FILE *fp;
result=fopen_s(&fp,"C:\\Users\\HHH\\abc.txt","rb");
两者的区别
1.fopen_s相比于函数fopen多了溢出检测,所以理解为更加高级,很多情况,比如在vs里运行fopen,所以会显示unsafe的字眼,这时就应该考虑用fopen_s,或者直接在头文件之前加上#define _CRT_SECURE_NO_DEPRECATE。
2.在使用上,函数fopen的返回值是文件指针,如果返回的文件指针为NULL时,则表示打开文件失败。而函数fopen_s的返回值是相应的错误代码,通过查看错误代码代表的含义,有助于排查问题。
3.fopen_s打开的文件不能共享,如果你打开的文件需要共享的话,不能使用fopen_s函数。可以考虑_fopen,_wfsopen这两个函数。
参考博客
C/C++打开文件函数fopen和fopen_s用法的比较
16、map函数
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的函数
std::map<int, std::map<std::string, std::string> > A
表示定义了A[int]["type"]["num"]
,第一个存储int
类型的关键字,可用于索引(一般不能重复),后两个存储string
类型