my FAQ about c++/c/mfc .

来源:互联网 发布:上瘾网络剧全集百度云 编辑:程序博客网 时间:2024/04/29 02:21
                                                My FAQ about c++/c/mfc programming
1.       如何通过iterator取得结构中的值?
比如,map<pair<int_left,int_right>,int_value>::iterator iter;
通过iter访问它所指对象的值,做法如下:
int left_int = (*iter).first.first;
int right_int = (*iter).first.right;
int value_int = (*iter).second;
2.       如何通过iterator取得下标或者相反。
例如,vector<int>::iterator iter;
int index = iter-vec.begin();
iter = vec.begin()+index;
3.       如何取得随机整数?
Example:
#include<time.h>
#include <stdlib.h>
main()
{
    int BIG_NUM = 100;
srand( (unsigned)time( NULL ) );
while(true){
    cout << rand_num = rand() %100;//输出0~99的整数
 
}
}
4.       如何给vector预设大小?
如果事先知道vector所需空间大小,不需要动态增长,以便节约空间。在定义vector后可以调用reseave函数预设其大小。
Vector<int> vec;
Vec.researve(100);//预设100
5.       泛型容器和泛型算法中的predicate function object(谓词函数对象)如何写?
比如在调用泛型容器map或者泛型算法如:sort,lower_bound,upper_bounder,equal_rang的时候都需要指明参数: “BinaryPredicate _Comp”如何用呢?通过一个使用sort的例子来说明一下。
假定,有一个结构node里面包含一个整形值,一个string型值。现在想对一个vector<node> 型对象vec_node里面的内容用sort进行排序。那么有三种方法。
方法1: 不给sort显式提供比较准则,那么会自动调用vec_node里面所放类型的”<”操作,如果没有重载”<”,则编译器报错。
方法2: 显式提供比较准则, 用一般的函数来提供。
方法3: 显式提供比较准则, function object来提供。
方法2,3其实一样,不过用function object比一般的函数指针有很多的优点。
Function objects (also called "functors") are ordinary class objects that overload the () operator. Thus, syntactically, they behave like ordinary functions.
对于map容器,因为它本身是有序容器,所以存放用户定义的较复杂的结构时也需要自己定义predicate,不过是对于key类型进行比较的。但是一般的如keyint,或者key类型为pair<int,int>的情况下,map结构有默认的增序排列。
示例代码如下:
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct node{
   int value;
   string key;
   public :
bool operator < (const node n) //方法1:重载”<”操作符
{
        return value > n.value;
}
}node;
class func2{//方法2:定义function object
 public:
    bool operator() (const node n1,const node n2)
{
        return n1.value > n2.value;
}
 
};
bool func3(node n1,node n2) //方法3:定义一般函数
{
return n1.value > n2.value;
}
void main()
{
vector<node> intVec;
node n1 ;
n1.key = "hf4";
n1.value = 4;
intVec.push_back(n1);
n1.key = "hf2";
n1.value = 2;
intVec.push_back(n1);
n1.key = "hf1";
n1.value = 1;
intVec.push_back(n1);
n1.key = "hf3";
n1.value = 3;
intVec.push_back(n1);
n1.key = "hf5";
n1.value = 5;
intVec.push_back(n1);
sort(intVec.begin(),intVec.end());//方法1:重载”<”操作符
sort(intVec.begin(),intVec.end(),func2());//方法2:定义function object,注意加’()’
sort(intVec.begin(),intVec.end(),func3);//方法3:定义一般函数
for(int i=0;i<intVec.size();i++)
{
        cout << intVec[i].value << "/t";
}
}
 
6.       泛型算法里面的二分查找算法都有哪些?如何使用?
有比如lower_bound,upper_bound,equal_range这类的。
一个找给定区间的下限,一个上限,一个是区间。
使用时一样要根据情况看需不需要写predicate,
但是有些细微问题还需要注意,以lower_bound的用法为例。
typedef struct BigramNode{
int LeftWrdID;
int RightWrdID;
double LogProb;
}BigramNode;
class Comp
{
public :
       bool operator()(const BigramNode n1,const int WordID)
       {
              return n1.RightWrdID<WordID;
       }
       //注意点1:两个方向的比较都要考虑到。
       bool operator()(const int WordID,const BigramNode n2)
       {
              return n2.RightWrdID<WordID;
       }
};
 
vector<BigramNode>::iterator BiNodeIter;
vector<BigramNode>::iterator StartIter = m_vBigramNodes.begin() + BigramsStartP;
vector<BigramNode>::iterator EndIter = m_vBigramNodes.begin() + BigramsEndP;
//注意点2:如果索要找的范围内的值是不重复的,那么先要看尾部迭代器所指是否为//所求。
if((*EndIter).RightWrdID == RightWordID)
       {
              return (*EndIter).LogProb;
       }
       BiNodeIter = lower_bound(StartIter,EndIter,RightWordID,Comp());
       //注意点3:找完后要查看两点,结果是所求而且不是给定查找范围的尾部。因为//如果找不到就会返回查找区间尾部。
       if(BiNodeIter != EndIter && (*BiNodeIter).RightWrdID == RightWordID)
       {
              return (*BiNodeIter).LogProb;
       }
7. 
1.       文本的读写常用的操作?
在这里先总结一下c/c++/MFC中文本处理常用的文件读写。
1. C里面
a)         在标准c里面,所有的文件读写操作都要通过文件指针进行,即FILE * fp;
b)        对于文件模式是二进制还是文本模式,每种处理方法都是一样的,就比如采用fscanf/fprintf 打开读写二进制文本还是文本模式文本,其效果是一样的。(个人意见,简单试验后的看法)
c)        fscanf/fprintf函数对磁盘文件读写,使用方便,容易理解,但由于输入时要将ASCII字符转换成二进制数,输出时要将二进制数转换成ASCII字符,花费时间较多,因此,在内存与磁盘频繁交换数据的情况下,最好不用fprintffscanf函数,而用freadfwrite函数。
d)        FILE文件的打开和关闭
                         i.              打开:fp = fopen(filename,文件使用方式);如果打开不成功,返回一个空指针NULL.
                       ii.              关闭:fclose(fp); 要养成关闭文件的习惯,因为c编译系统允许打开的文件数是有限的,而且可以防止丢失缓存区中的数据。
                      iii.              判断文件是否结束:
1.         while(! feof(fp)) {如果文件未结束进行操作}
e)         文件的读写方式有三种,
                         i.              按字符()读写
1.         char ch = fgetc(fp); fputc(ch,fp);
2.         char *fgets( char *string, int n, FILE *stream );
3.         int fputs( const char *string, FILE *stream );
4.         想读入一行的话,可用fgets(str,ENOUGH_BIG_NUM,fp); 因为fgets碰到newline 字符(‘/n’)会自动截断。
                       ii.              按数据块读写文件
1.         fread(buffer,size,count,fp);
2.         fwrite(buffer,size,count,fp);
3.         返回值:读/写的数据块数
4.         举例:struct MT *ebmt, *smt;
a)         FILE * fp;
If((fp= fopen(“mt_method.dat”,”wb+”))==NULL){
Printf(“open error”);
Return;
}
ebmt = new MT;
smt = new MT;
…..//赋值
//写入文件
fwrite(ebmt,sizeof(struct MT),1,fp);
fwrite(smt,sizeof(struct MT),1,fp);
 
 
struct MT *new_ebmt, *new_smt;
 
//read in
fread(new_ebmt,sizeof(struct MT),1,fp);
fread(new_smt,sizeof(struct MT),1,fp);
fclose(fp);
                      iii.              按格式读写
1.         fscanf(文件指针,格式控制参数,地址参数列表)
2.         fprintf(文件指针,格式控制参数,地址参数列表)
3.         FILE *stream; char str[];
fprintf( stream, "%s %ld %f%c", "a-string", 
                                 65000, 3.14159, 'x' );
                                
  如果想每次输入一个词fscanf(fp,”%s”,str);
因为fscanf可以按White-space characters: blank (' '); tab ('/t'); or newline ('/n'). 来截断。但是要注意在用fscanf 取词的时候,特别要注意最后一个词是否会取到两次。比如在文本末尾是几行空行。
如果代码为
void main( void )
{
   FILE *stream;
   char line[100];
 
   if( (stream = fopen( "fgets.c", "r" )) != NULL )
   {
          while(!feof(stream))
          {     fscanf( stream, "%s", line );
printf( "%s#/n", line);
          }
     
      fclose( stream );
   }
}
则最后一个词就会被输出两次,原因是,最后一次因为文件中还有回车换行符所以while循环进来,然后fscanf没取到新的词,line中保存的依然是上一个词,再次被输出,然后while循环也终止。所以要对fscanf的执行情况判一下,这里可以判断一下是否到了文件尾。改动上面加黑部分为:
if(fscanf( stream, "%s", line )!=EOF)
       printf( "%s#/n", line);
 
 
2.  c++
a)         C++中为输入输出提供了丰富的流库,具体信息可以参看<<C++ Primer 3rd Edition>> 中的第20章。在这里,只是简单地介绍一下常用的文件流操作。
b)        文件打开创建关闭:
                         i.              输入/出文件流的创建打开:ifstream in(“input.txt”); 或者ifstream in; in.open(“input.txt”); 或者fstream outfile(“output.txt”,ios_base::out),追加模式的话,fstream outfile(“output.txt”,ios_base::app);判断是否正确打开:if(!in) cerr<< “input file open error./n”;
                       ii.              关闭:filestream.close();
c)        读入一行或者一个词
ifstream infile(“infile.txt”);
string line,next_word;
getline(infile,line)//第三个参数分隔符默认为’/n’
//如果词汇之间用white characters(‘/t’,’ ’,’/n’)分割,那么读入一个词
infile >> next_word;
d)        输出
                         i.              一般用 outfile<< out_content;就够了。
 
 
3.  VC/MFC
a)         首先我们看到在MFC层次表中的关于文件的继承关系图如下:在我们文本处理实际操作中常用的两个文件类型是CFileCStdioFile.
b)        CStdioFile继承自CFile, 而且CFile directly provides unbuffered, binary disk input/output services, and it indirectly supports text files and memory files through its derived classes
Use CFile and its derived classes for general-purpose disk I/O. Use ofstream or other Microsoft iostream classes for formatted text sent to a disk file.
CFile除了Read/Write外,还提供了很多函数比如GetFilePath, GetFileName 等。
 
CStdioFile

A CStdioFile object represents a C run-time stream file as opened by the run-time functionfopen. Stream files are buffered and can be opened in either text mode (the default) or binary mode.

Text mode provides special processing for carriage return–linefeed pairs. When you write a newline character (0x0A) to a text-mode CStdioFile object, the byte pair (0x0D, 0x0A) is sent to the file. When you read, the byte pair (0x0A, 0x0D) is translated to a single 0x0A byte.
CStdioFile CFile 多提供了两个函数:
Text Read/Write
ReadString
Reads a single line of text.
WriteString
Writes a single line of text.
 
 
 
8. 
8.       vector.reserve(N)vector.resize(N)
前者是预留N个空间,并不填充,此时返回的vector.size()还是0,而且这样就要去访问它的某个元素,如vector[10]的话就会出现运行时错误。后者不仅预留了空间,而且为每个空间调用元素对应的构造函数填充了默认的值。实际上就是push_backN个默认的值。另外记住,在刚定义了一个vector时,还没有用resize()这样的函数填充任何元素的时候,要往里面填元素,必须用push_back(),而不能通过vector[index] = item;这样的
操作。
9.       如何让程序得到运行时间
   例子程序:
#ifdef WIN32
    // The FILETIME structure is a 64-bit value representing the number of
    // 100-nanoseconds. One nanosecond = 10e-9 seconds.
    typedef __int64    INT64;
    FILETIME    ftDummy, ftKernel, ftUser;
    GetProcessTimes(GetCurrentProcess(), &ftDummy, &ftDummy, &ftKernel, &ftUser);
    printf("real %.3fs/n", double(clock() - startClk) / CLOCKS_PER_SEC);
    printf("user %.3fs/n", (INT64(ftUser.dwHighDateTime << 32) | ftUser.dwLowDateTime) / 1e7);
    printf("sys %.3fs/n", (INT64(ftKernel.dwHighDateTime << 32) | ftKernel.dwLowDateTime) / 1e7);
#endif
 
其中的clock() 是在”time.h”中的函数 ,startClk 是一个clock_t 类型。
GetProcessTimes是一个windows API函数,用来返回当前进行所用的相关时间。
10.       TBC
原创粉丝点击