您的位置:首页 > 编程语言 > C语言/C++

C++入门学习笔记

2016-11-10 08:40 393 查看
这些是我刚学习C++的笔记,拿出来与大家分享,希望大家更容易入门!

1、 运算符<<(送出)用作输出运算符;cout是标准输出流。运算符>>(取入)用作输入运算;cin是标准的输入流。

2、 输出:一个输出表达式的结果本身还可以用于进一步的输出。

void h2(int i)
{
Cout<<”the value of I is”<<i<<’\n’;
}


3、 输入:

Void h3(int i)
{
Cin>>x;
Getline(cin,str);
}


4、 迭代器是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针接口,所谓迭代器是一种概念上的抽像:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,他可以把抽象的容器和同用的算法有机的结合起来。

迭代器提供一些基本操作符:*、++、==、!=、=。这些操作和c/c++操作array元素时的指针接口一致。不同之处在于迭代器是个所谓的复杂指针。具有遍历复杂数据结构的能力。其下层运行机制取决于其所遍历的数据结构。因此每一种容器型别都必须提供自己的迭代器。事实上每一种容器都将其迭代器以嵌套的方式定义域内部。因此各种迭代器的接口相同,型号却不同。这直接导出了泛型程序设计概念:所有操作行为都是用相同接口虽然他们的型别不同。

功能

迭代器使开发人员能够在类或结构中支持foreach迭代,而不必整个实现IEnumerable或者IEnumerator接口。只需提供一个迭代器,即可遍历类中的数据结构。当编译器检测到迭代器时,将自动生成IEnumerable接口或者IEnumerator接口的Current,MoveNext和Dispose方法。

特点

1.迭代器是可以返回相同类型值的有序序列的一段代码;

2.迭代器可用作方法、运算符或get访问器的代码体;

3.迭代器代码使用yieldreturn语句依次返回每个元素,yield break将终止迭代;

4.可以在类中实现多个迭代器,每个迭代器都必须像任何类成员一样有惟一的名称,并且可以在foreach语句中被客户端,代码调用如下所示:foreach(int x in SimpleClass.Iterator2){};

5.迭代器的返回类型必须为IEnumerable和IEnumerator中的任意一种;

6.迭代器是产生值的有序序列的一个语句块,不同于有一个 或多个yield语句存在的常规语句块;

7.迭代器不是一种成员,它只是实现函数成员的方式,理解这一点是很重要的,一个通过迭代器实现的成员,可以被其他可能或不可能通过迭代器实现的成员覆盖和重载;

8.迭代器块在C#语法中不是独特的元素,它们在几个方面受到限制,并且主要作用在函数成员声明的语义上,它们在语法上只是语句块而已;

9.yield关键字用于指定返回的值。到达yieldreturn语句时,会保存当前位置。下次调用迭代器时将从此位置重新开始执行。 迭代器对集合类特别有用,它提供一种简单的方法来迭代不常用的数据结构(如二进制树)。

简介

迭代器是一种检查容器内元素并遍历元素的数据类型。

5、 枚举(enum)

枚举在C/C++/c#中,是一个被命名的整型常数的集合, 枚举在日常生活中很常见。

例如表示星期的SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,

SATURDAY, 就是一个枚举。

枚举的说明与结构和联合相似, 其形式为:

enum 枚举名{
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数]
} 枚举变量;


如果枚举没有初始化, 即省掉”=整型常数”时, 则从第一个标识符开始, 顺

次赋给标识符0, 1, 2, …。但当枚举中的某个成员赋值后, 其后的成员按依次

加1的规则确定其值。

例如下列枚举说明后, x1, x2, x3, x4的值分别为0, 1, 2, 3。

enum Num{x1, x2, x3, x4}x;

当定义改变成:

enum Num
{
x1,
x2=0,
x3=50,
x4
}x;


则x1=0, x2=0, x3=50, x4=51

注意:

1. 枚举中每个成员(标识符)结束符是”,”, 不是”;”, 最后一个成员可省略

“,”。

2. 初始化时可以赋负数, 以后的标识符仍依次加1。

3. 枚举变量只能取枚举说明结构中的某个标识符常量。

例如:

enum Num
{
x1=5,
x2,
x3,
x4
};
enum Num x=x3;


此时, 枚举变量x实际上是7。

枚举类型变量的赋值和使用

枚举类型在使用中有以下规定:

1.枚举值是常量,不是变量。不能在程序中用赋值语句再对它赋值。例如对枚举weekday的元素再作以下赋值: sun=5;mon=2;sun=mon; 都是错误的。

2. 枚举元素本身由系统定义了一个表示序号的数值,从0 开始顺序定义为0,1,2…。如在weekday中,sun值为0,mon值为1, …,sat值为6。

main(){
enum weekday
{ sun,mon,tue,wed,thu,fri,sat } a,b,c;
a=sun;
b=mon;
c=tue;
printf("%d,%d,%d",a,b,c);
}


只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量。如: a=sun;b=mon; 是正确的。而: a=0;b=1; 是错误的。如一定要把数值赋予枚举变量,则必须用强制类型转换,如: a=(enum weekday)2;其意义是将顺序号为2的枚举元素赋予枚举变量a,相当于: a=tue; 还应该说明的是枚举元素不是字符常量也不是字符串常量, 使用时不要加单、双引号。

main(){
enum body
{ a,b,c,d } month[31],j;
int i;
j=a;
for(i=1;i<=30;i++){
month[i]=j;
j++;
if (j>d) j=a;
}
for(i=1;i<=30;i++){
switch(month[i])
{
case a:printf(" %2d %c\t",i,'a'); break;
case b:printf(" %2d %c\t",i,'b'); break;
case c:printf(" %2d %c\t",i,'c'); break;
case d:printf(" %2d %c\t",i,'d'); break;
default:break;
}
}
printf("\n");
}


10个数字,任意取出不相等的5个数字,
谁还记得这个算法的公式????????
用javascript有什么好的计算方法??
m n*(n-1)*(n-2)*...*(n-m+1) n!
C = --------------------------------------------- = --------------------------
n m*(m-1)*(m-2)*...*3*2*1 m!*(n-m)!


这个是公式,但是对枚举作用不大,还是要遍历循环才行.

这就需要一个好的算法

6、 typedef

typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。

在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。

7、 大小

C++对象的大小事用char的大小的倍数表示的。按照定义char的大小为1,。一个对象或类型的大小可以用sizeof运算符得到。

类型 大小

Char bool   1
Short,wchar_t   2
Int,long,float  4
Float,long double   8


8、 显式类转换

显示类型转换只是得到了一个所需类型的中间变量,原来变量的类型并不发生改变。

标准C++中主要有4中显式类转换类型运算reinterpret_cast,static_cast,const_cast,dynamic_cast.

1. reinterpret_cast

语法:

returnvalue=reinterpret_cast(casting value);


这个操作符修改了操作数类型,但仅仅是重新解释了对象的比特模型而没有进行二进制转换。从语法上看,这个操作符仅用于指针类型的转换(返回值是指针)。它用来将一个类型指针转换为另一个类型指针,它只需在编译时重新解释指针的类型。这个操作符基本不考虑转换类型之间是否是相关的。

reinterpret_cast常用的场景如下:

1)普通指针转换,T*—>U*—>T*,保证T*经过一些列转换值不变

比如将不同类型的指针存在一个容器里,vector可以存int*,char*,string*等各种指针,只要有别的方式确定某个void*当初的类型是T*,标准保证reinterpret_cast(v[i])可以得到当初的值。

2)自己做memory allocator,可以将T*转换为U*,这个时候可能要注意字节对其的问题。

2、static_cast

语法:
T static_cast (expression);


该运算符把expression转换成type-id类型,但没有运行时类型检查来保证转换的安全性。

static_cast是最经常用到的转换操作符,它最经常的一个应用就是将隐式转换变成显示转换,以消除编译器可能产生的warning,同reinterpret_cast不同,采用static_cast转换的两个类型之间一般有某种相关性。

static_cast主要应用场景如下:

1)用于类层次结构中基类和派生类之间指针或引用的转换。这个转换中,将派生类转成基类是安全的,将基类转成派生类时由于没有进行动态类型检查,所以是不安全的。

2)用于基本数据之间的转换。如把int转成char,int转成num等。

3)把空指针转换成目标类型的空指针。

4)把任何类型的表达式转换成void类型。

3、dynamic_cast

语法:dynamic_cast < type-id > ( expression )

该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;

dynamic_cast的转换是在运行时进行的,它的一个好处是会在运行是做类型检查,如果对象的类型不是期望的类型,它会在指针转换的时候返回NULL,并在引用转换的时候抛出一个std::bad_cast异常。

dynamic_cast一般只在继承类对象的指针之间或引用之间进行类型转换。如果没有继承关系,则被转化的类具有虚函数对象的指针进行转换。

4.const_cast

const_cast< type-id > (exdivssion)

这个运算符可以用来去除一个对象的const或volatile属性。type-id必须是一个指针或者引用。

- 9、&—–取地址符运算

例如:

int e[3]={1,2,3};
Int *p;
p=&e[2];
则:
*p=2;
*(p+1)=3;
*(p-1)=1;


10、C++语言中的基本数据类型及其范围 11、类

类描述了一类食物,以及食物所应具有的属性,是一种用户自定义的数据类型。声明一个类时,以class关键字开始,接着是类的名字,其语法结构为:

Class <类名称>
{
private:
[<私有数据和函数>]
public:
[<公有数据和函数>]
}


类表示了一组相似的对象,是创建对象的有效模板,用它可以产生多个对象。类所代表的是一个抽象的概念或事物,在客观世界中世纪存在的是类的实例,即对象。

类时具有相同属性和服务的一组对象的集合,它为属于该类的全部对象提供了一个统一的抽象描述,其内部包括属性和服务两个主要部分。

类包含以下3种类型:

- private:私有类型包含数据和函数,在private关键字后面声明。如果省略private关键字,则必须紧跟在类名的后面声明。在类中声明的数据和函数如果不特别指明,都被视为私有类型。私有类型的数据值允许类本身声明的函数对其进行存取,而类的外部的任何函数都不能访问。

- public:公有类型public关键字后面声明,他们是类与外部的接口,任何外部函数都可以访问公有类的数据和函数。

- protect:保护类型用于类的继承,当类的成员被声明为protect时,从类的外部就不能对其进行访问。

类时面向对象程序最基本的单元。在设计面向对象程序时,首先要以类的方式设计实际待解决的问题,也就是将问题索要处理的数据定义成类的私有或公有类型数据,同时将处理问题的方法定义成类的公有或私有成员函数。

11、对象

对象时系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位,有一组属性和对这组属性进行操作的一组服务组成。

属性和服务是构成对象的两个基本要素,其定义是:属性是用来描述对象静态特征的一个数据项;服务是用来描述对象动态特征的一个操作序列。

对象是类的实例,可以声明类时直接定义对象。此外,还可以在声明类之后再单独声明类对象。

Class example
{
Int I;
Public;
Float f;
Void fun();
};
Example A;


对象声明后即可使用,使用方法如下:

对象名.成员函数名和对象名,数据成员名

例,可以按一下方式调用类example中的成员函数fun();

A.fun();

12、类和类之间的关系

1.关联关系

关联关系表示两个类之间存在某种语义上的联系,即与该关联链接的类的对象之间具有一定的语义链接关系,该关系表达了类之间的一种相关性。

2.依赖关系

依赖关系描述的是两个类之间的语义上的连接关系,它是一种Use-A关系。假设两个元素A与B,如果修改元素A的定义可能会一起对另一个元素B的定义的修改,则称元素B依赖于A。

3.聚合关系

聚合关系是一种Has-A关系,它体现的是类之间的一种整体与部分的关系。

4.泛化关系

泛化关系是一种Is-A关系,它描述的是类之间“一般”与“特殊”的关系。具有共同特性的元素可以抽象为一般类,并通过增加其内涵,进一步抽象成特殊类。改关系可以将类组成一种有层次,有分类的结构。

13、多态性

多态性是指类中具有相似功能的不同函数使用同一个名称实现。

多态性的实现与联编有关。将一个函数的调用与其相应的函数体代码相链接的过程,成为函数联编。

静态联编,动态联编

编译时的多态性是通过静态联编来实现的。静态联编是指在调用同名函数时,编译器将根据调用时所使用的实际参数个数、类型的不同确定应该调用哪一个函数的实现,它是在程序编译阶段就确定下来的多态性。静态联编通过使用重载机制来获得,重载机制包括函数重载和运算符重载。

14、形参和实参

形参:全称为“形式参数”是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传递的参数。

形参的作用是实现主调函数与被调函数之间的联系,通常将函数所处理的数据,影响函数功能的因素或者函数处理的结果作为形参。没有形参的函数在形参表的位置应该写void.main 函数也可以有形参和返回值,其形参也称为命令行参数,由操作系统在启动程序时初始化,其返回值传递给操作系统。

实参:可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。

实参和形参的区别:

空白或占位符

1.函数的形参列于函数声明中,在函数定义的函数体内使用。当函数调用时,形参(任何种类的)是一类将被填充的空白或是占位符。

用来填充形参

2.实参是用来填充形参的。当函数被调用时,实参列在函数名后面的括号里。执行函数调用时,实参被传递给形参。

传值调用和引用调用

3.传值调用和引用调用指的是用于参数传递过程中的一种机制。传值调用中,只使用了实参的值。传值调用机制里,形参是一个局部变量,其初始值为相应实参的值。在引用调用机制里,将实参的地址传递给形参,从表面上看是以实参变量取代形参,因此任何发生在形参上的改变实际上都发生在实参变量上。

15、运算符重载

运算符重载本质上就是函数的重载,是函数重载的特殊形式(函数名为运算符号)。C++语言中允许程序员重新定义运算符的语义,这一机制称作运算符重载。

16、正则表达式

正则表达式又称正规表达式,常规表示法,计算机科学的一个概念。正则表达式使用单个字符串来描述。匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式常用来检索、替换那些符合摸个模式的文本。

许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

给定一个正则表达式和另一个字符串,我们可以达到如下的目的:

给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);

可以通过正则表达式,从字符串中获取我们想要的特定部分。

正则表达式的特点是:

灵活性、逻辑性和功能性非常的强;

可以迅速地用极简单的方式达到字符串的复杂控制。

对于刚接触的人来说,比较晦涩难懂。

由于正则表达式主要应用对象是文本,因此它在各种文本编辑器场合都有应用,小到著名编辑器EditPlus,大到Microsoft Word、Visual Studio等大型编辑器,都可以使用正则表达式来处理文本内容。

17、MFC

MFC应用程序有自己特殊的运行机制,一般包括以下5步:

调用CWinApp的构造函数。

程序入口函数WinMain接收控制。

WinMain调用应用程序类的InitInstance函数。

WinMain进入消息循环。

WinMain退出,程序终止。

1、 应用程序类CTestApp

从MFC的CWinApp类派生,对应的源文件Test.h和Test.cpp,为应用程序的入口,负责应用程序对象的定义与创建、程序的启动、命令行参数处理、主框架窗口的创建、文档模板的创建、文件菜单的处理、About对话框的创建和显示等。

2、 主框架窗口类CmainFrame

从MFC的CFrameWnd或CMDIFrameWnd派生,对应的源文件为MainFrm.h和MainFrm.cpp。为应用程序的界面,包含菜单栏、工具栏和状态栏,负责子框架窗口或视图类的创建。

3、 字框架窗口类CchildFrame

从MFC的CMDIChildWnd类派生,只有MDI程序才有,对应的源文件为ChildFram.h

和ChildFrm.cpp,包含子框架窗口的标题条和边框,负责视图类的创建。 4、 文档类CtestDoc

从MFC的CDocument类派生,对应的源文件为TestDoc.h和TestDoc.cpp,负责文件读写和数据处理。

5、 视图类CTestView

一般从MFC的CView类派生,也可以冲CScrollView等其他MFC视图类派生,对应的源文件TestView.h和TestView.cpp。对应于框架窗口的客户区,负责数据的显示、图形的绘制和用户的交互等。

18、map的用法

1、Map的简介

Map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key。

2、map的功能

自动建立Key - value的对应。key 和 value可以是任意你需要的类型。

根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。 快速插入Key - Value 记录。 快速删除记录 根据Key 修改value记录。 遍历所有记录。

3、使用map

使用map得包含map类所在的头文件

#include<map>//STL头文件没有扩展名.h


Map对象是模板类,需要关键字和存储对象两个模板参数,

Std::map<int,string>personal;


这样就定义了一个用int作为索引,并拥有相关联的指向string的指针;

为了使用方便,可以对模板类进行一下类型定义。

Typedef map<int,CString>UDT_MAP_INT_CSTRING;
UDT_MAP_INT_CSTRING enumMap;


4、在map中插入元素

改变map中的条目非常简单,因为map类已经对[]操作符进行了重载

enumMap[1] = "One";
enumMap[2] = "Two";
.....


这样非常直观,但存在一个性能的问题。插入2时,先在enumMap中查找主键为2的项,没发现,然后将一个新的对象插入enumMap,键是2,值是一个空字符串,插入完成后,将字符串赋为”Two”; 该方法会将每个值都赋为缺省值,然后再赋为显示的值,如果元素是类对象,则开销比较大。我们可以用以下方法来避免开销:

enumMap.insert(map<int, CString> :: value_type(2, "Two"))


19、删除文件

到底如何查找文件呢?我们需要一个结构体和几个大家可能不太熟悉的函数。这些函数和结构体在的头文件中,结构体为struct _finddata_t ,函数为_findfirst、_findnext和_fineclose。具体如何使用,我会慢慢讲来~

首先讲这个结构体吧~ struct _finddata_t ,这个结构体是用来存储文件各种信息的。说实话,这个结构体的具体定义代码,我没有找到,不过还好,文档里面在_find里有比较详细的成员变量介绍。我基本上就把文档翻译过来讲吧:

unsigned atrrib: 文件属性的存储位置。它存储一个unsigned单元,用于表示文件的属性。文件属性是用位表示的,主要有以下一些:_A_ARCH(存档)、 _A_HIDDEN(隐藏)、_A_NORMAL(正常)、_A_RDONLY(只读)、_A_SUBDIR(文件夹)、_A_SYSTEM(系统)。这些都是在中定义的宏,可以直接使用,而本身的意义其实是一个无符号整型(只不过这个整型应该是2的几次幂,从而保证只有一位为 1,而其他位为0)。既然是位表示,那么当一个文件有多个属性时,它往往是通过位或的方式,来得到几个属性的综合。例如只读+隐藏+系统属性,应该为:_A_HIDDEN | _A_RDONLY | _A_SYSTEM 。

time_t time_create: 这里的time_t是一个变量类型(长整型?相当于long int?),用来存储时间的,我们暂时不用理它,只要知道,这个time_create变量是用来存储文件创建时间的就可以了。

time_t time_access: 文件最后一次被访问的时间。

time_t time_write: 文件最后一次被修改的时间。

_fsize_t size: 文件的大小。这里的_fsize_t应该可以相当于unsigned整型,表示文件的字节数。

char name [_MAX_FNAME ]:文件的文件名。这里的_MAX_FNAME是一个常量宏,它在头文件中被定义,表示的是文件名的最大长度。

以此,我们可以推测出,struct _finddata_t ,大概的定义如下:

struct _finddata_t
{
unsigned attrib;
time_t time_create;
time_t time_access;
time_t time_write;
_fsize_t size;
char name[_MAX_FNAME];
};


前面也说了,这个结构体是用来存储文件信息的,那么如何把一个硬盘文件的文件信息“存到”这个结构体所表示的内存空间里去呢?这就要靠_findfirst、_findnext和_fineclose三个函数的搭配使用了。
首先还是对这三个函数一一介绍一番吧……


long _findfirst( char *filespec, struct _finddata_t *fileinfo );
返回值: 如果查找成功的话,将返回一个long型的唯一的查找用的句柄(就是一个唯一编号)。这个句柄将在_findnext函数中被使用。若失败,则返回-1。
参数:
filespec:标明文件的字符串,可支持通配符。比如:*.c,则表示当前文件夹下的所有后缀为C的文件。
fileinfo :这里就是用来存放文件信息的结构体的指针。这个结构体必须在调用此函数前声明,不过不用初始化,只要分配了内存空间就可以了。函数成功后,函数会把找到的文件的信息放入这个结构体中。
int _findnext( long handle, struct _finddata_t *fileinfo );
返回值: 若成功返回0,否则返回-1。
参数:
handle:即由_findfirst函数返回回来的句柄。
fileinfo:文件信息结构体的指针。找到文件后,函数将该文件信息放入此结构体中。
int _findclose( long handle );
返回值: 成功返回0,失败返回-1。
参数:
handle :_findfirst函数返回回来的句柄。


大家看到这里,估计都能猜到个大概了吧?先用_findfirst查找第一个文件,若成功则用返回的句柄调用_findnext函数查找其他的文件,当查找完毕后用,用_findclose函数结束查找。恩,对,这就是正确思路。下面我们就按照这样的思路来编写一个查找C:/WINDOWS文件夹下的所有 exe可执行文件的程序。


#include
#include
const char *to_search="C://WINDOWS//*.exe";        //欲查找的文件,支持通配符
int main()
{
long handle;                                                //用于查找的句柄
struct _finddata_t fileinfo;                          //文件信息的结构体
handle=_findfirst(to_search,&fileinfo);         //第一次查找
if(-1==handle)return -1;
printf("%s/n",fileinfo.name);                         //打印出找到的文件的文件名
while(!_findnext(handle,&fileinfo))               //循环查找其他符合的文件,知道找不到其他的为止
{
printf("%s/n",fileinfo.name);
}
_findclose(handle);                                      //别忘了关闭句柄
system("pause");
return 0;
}


当然,这个文件的查找是在指定的路径中进行,如何遍历硬盘,在整个硬盘中查找文件呢?大家可以在网络上搜索文件递归遍历等方法,这里不再做进一步介绍。
细心的朋友可能会注意到我在程序的末尾用了一个system函数。这个与程序本身并没有影响,和以前介绍给大家的使用getchar()函数的作用相同,只是为了暂停一下,让我们能看到命令提示符上输出的结果而已。不过system函数本身是一个非常强大的函数。大家可以查查MSDN看看~ 简单来说,它是一个C语言与操作系统的相互平台,可以在程序里通过这个函数,向操作系统传递command命令。这个简单的函数会在下一篇的文章中大放异彩,大家拭目以待吧~~


20判断文件类型

for example:
printf("File type: ");

switch (sb.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}


#include <io.h> 主要是对磁盘文件路径进行操作的函数
#include <direct.h>目录遍历
#include <stdio.h>主要是输入输出的函数
#include <string.h>主要是字符串函数 例如:strcpy
#include <sys/stat.h>基本系统数据类型 win32 api


21、遍历文件夹

C++下遍历文件夹

编写程序遍历文件夹及其子文件夹下所有文件,并输出到标准输出流或者文件流。

1. 先考虑在单层目录下,遍历所有文件。以C:\WINDOWS为例:

用到数据结构_finddata_t,文件信息结构体的指针。

struct _finddata_t
{
unsigned attrib;     //文件属性
time_t time_create;  //文件创建时间
time_t time_access;  //文件上一次访问时间
time_t time_write;   //文件上一次修改时间
_fsize_t size;  //文件字节数
char name[_MAX_FNAME]; //文件名
};


文件属性是无符号整数,取值为相应的宏:_A_ARCH(存档),_A_SUBDIR(文件夹),_A_HIDDEN(隐藏),_A_SYSTEM(系统),_A_NORMAL(正常),_A_RDONLY(只读)。容易看出,通过这个结构体,我们可以得到关于该文件的很多信息。结合以下函数,我们可以将文件信息存储到这个结构体中:

//按FileName命名规则匹配当前目录第一个文件
_findfirst(_In_ const char * FileName, _Out_ struct _finddata64i32_t * _FindData);
//按FileName命名规则匹配当前目录下一个文件
_findnext(_In_ intptr_t _FindHandle, _Out_ struct _finddata64i32_t * _FindData);
//关闭_findfirst返回的文件句柄
_findclose(_In_ intptr_t _FindHandle);
_findfirst 函数返回的是匹配到文件的句柄,数据类型为long。遍历过程可以指定文件类型,这通过FileName的赋值来实现,例如要遍历C:\WINDOWS下的所有.exe文件

bool transfer(string fileName = "C:\\Windows\\*.exe", int exeNum = 0)
{
_finddata_t fileInfo;
long handle = _findfirst(fileName.c_str(), &fileInfo);

if (handle == -1L)
{
cerr << "failed to transfer files" << endl;
return false;
}

do
{
exeNum ++;
cout << fileInfo.name <<endl;
} while (_findnext(handle, &fileInfo) == 0);
cout << " .exe files' number:  " << exeNum << endl;

return true;
}


遍历文件夹及其子文件夹下所有文件。操作系统中文件夹目录是树状结构,使用深度搜索策略遍历所有文件。用到_A_SUBDIR属性,可运行程序如下:

void dfsFolder(string folderPath, ofstream &fout)
{
_finddata_t FileInfo;
string strfind = folderPath + "\\*";
long Handle = _findfirst(strfind.c_str(), &FileInfo);

if (Handle == -1L)
{
cerr << "can not match the folder path" << endl;
exit(-1);
}
do{
//判断是否有子目录
if (FileInfo.attrib & _A_SUBDIR)
{
//这个语句很重要
if( (strcmp(FileInfo.name,".") != 0 ) &&(strcmp(FileInfo.name,"..") != 0))
{
string newPath = folderPath + "\\" + FileInfo.name;
dfsFolder(newPath, fout);
}
}
else
{
fout << folderPath << "\\" << FileInfo.name  << " ";
}
}while (_findnext(Handle, &FileInfo) == 0);

_findclose(Handle);
fout.close();
}


22、编译问题

这种错误是怎么回事?

error C2440: 'static_cast' : cannot convert from 'void (__thiscall CDlg::* )(WPARAM,LPARAM)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'


在vc6下没事,可是在vs2005中就有这样的问题,请问怎么改正?

我是这么解决的,希望对大家有帮助:

在我的代码中

1.根据出错信息是ON_MESSAGE(WM_NOTIFYICON, OnNotifyIcon)函数,在这个函数中存在OnNotifyIcon()函数,然后找到其定义

2.将void Dlg::OnNotifyIcon(WPARAM wParam, LPARAM lParam)->LRESULT Dlg::OnNotifyIcon(WPARAM wParam, LPARAM lParam)

{

在最后加上return TRUE;

}

3.将afx_msg void OnNotifyIcon(WPARAM wParam, LPARAM lParam)->该成afx_msg LRESULT OnNotifyIcon(WPARAM wParam, LPARAM lParam);

编译下就成功了

23、树形控件

树形控件在Windows系统中很常见,树形视图中以分层结构显示数据,每层的缩进不同,层次越低缩进越多。属性控件的节点一般都由标签和图标两部分组成,图标用来抽象的描述数据,能够使树形控件的层次关系更加清晰。树形控件插入新的树节点时需要制定新节点与已有节点的关系。

TVN_SELCHANGING和TVN_SELCHANGED:在用户改变了对树节点的选择时,控件会发送这两个消息。消息会附带一个指向NMTREEVIEW结构的指针,程序可从该结构中获得必要的信息。两个消息都会在该结构的itemOld成员中包含原来的选择项信息,在itemNew成员中包含新选择项的信息,在action成员中表明是用户的什么行为触发了该通知消息(若是TVC_BYKEYBOARD则表明是键盘,若是TVC_BYMOUSE则表明是鼠标,若是TVC_UNKNOWN则表示未知)。两个消息的不同之处在于,如果TVN_SELCHANGING的消息处理函数返回TRUE,那么就阻止选择的改变,如果返回FALSE,则允许改变。
TVN_KEYDOWN:该消息表明了一个键盘事件。消息会附带一个指向NMTVKEYDOWN结构的指针,通过该结构程序可以获得按键的信息。
TVN_BEGINLABELEDIT和TVN_ENDLABELEDIT:分别在用户开始编辑和结束编辑节点的标签时发送。消息会附带一个指向NMTVDISPINFO结构的指针,程序可从该结构中获得必要的信息。在前者的消息处理函数中,可以调用GetEditControl()成员函数返回一个指向用于编辑标题的编辑框的指针。如果处理函数返回FALSE,则允许编辑,如果返回TRUE,则禁止编辑。在后者的消息处理函数中,NMTVDISPINFO结构中的item.pszText指向编辑后的新标题,如果pszText为NULL,那么说明用户放弃了编辑,否则,程序应负责更新节点的标签,这可以由SetItem()或SetItemText()函数来完成。


树形控件的创建也是有两种方式,一种是在对话框模板中直接拖入Tree Control控件创建,另一种就是通过CTreeCtrl类的Create成员函数创建。下面主要讲后者。

CTreeCtrl类的Create成员函数的原型如下:

virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID
);


此函数的原型与前面讲到的所有控件类的Create函数都类似。dwStyle指定树形控件风格的组合,rect指定树形控件窗口的位置和大小,pParentWnd为指向树形控件父窗口的指针,nID指定树形控件的ID。


CTreeCtrl类的主要成员函数

CImageList* SetImageList(CImageList * pImageList,int nImageListType);

如果树节点需要显示图标时,则必须先创建一个CImageList类的对象,并为其添加多个图像组成一个图像序列,然后调用SetImageList函数为树形控件设置图像序列,在用InsertItem插入节点时传入所需图像在图像序列中的索引即可。后面的例子中会演示。参数pImageList为指向图像序列类CImageList的对象的指针,若为NULL则删除树形控件的所有图像。参数nImageListType指定图像序列的类型,可以是TVSIL_NORMAL(普通图像序列)或TVSIL_STATE(状态图像序列,用图像表示节点的状态)。

UINT GetCount( ) const;

获取树形控件中节点的数量。

DWORD_PTR GetItemData(HTREEITEM hItem) const;

获取树形控件中某个指定节点的附加32位数据。参数hItem为指定的树节点的句柄。

BOOL SetItemData(HTREEITEM hItem,DWORD_PTR dwData);

为树形控件中某个指定节点设置附加的32位数据。参数hItem同上,dwData为要设置的32位数据。

CString GetItemText(HTREEITEM hItem) const;

获取树形控件中某个指定节点的标签文本。参数hItem同上。返回值是包含标签文本的字符串。

BOOL SetItemText(HTREEITEM hItem,LPCTSTR lpszItem);

为树形控件中某个指定节点设置标签文本。参数hItem同上,lpszItem为包含标签文本的字符串的指针。

HTREEITEM GetNextSiblingItem(HTREEITEM hItem) const;

获取树形控件中某个指定节点的下一个兄弟节点。参数hItem同上。返回值是下一个兄弟节点的句柄。

HTREEITEM GetPrevSiblingItem(HTREEITEM hItem) const;

获取树形控件中某个指定节点的上一个兄弟节点。参数hItem同上。返回值是上一个兄弟节点的句柄。

HTREEITEM GetParentItem(HTREEITEM hItem) const;

获取树形控件中某个指定节点的父节点。参数hItem同上。返回值是父节点的句柄。

HTREEITEM GetRootItem( ) const;

获取树形控件根节点的句柄。

HTREEITEM GetSelectedItem( ) const;

获取树形控件当前选中节点的句柄。

BOOL DeleteAllItems( );

删除树形控件中的所有节点。删除成功则返回TRUE,否则返回FALSE。

BOOL DeleteItem(HTREEITEM hItem);

删除树形控件中的某个节点。参数hItem为要删除的节点的句柄。删除成功则返回TRUE,否则返回FALSE。

HTREEITEM InsertItem(LPCTSTR lpszItem,int nImage,int nSelectedImage,HTREEITEM hParent = TVI_ROOT,HTREEITEM hInsertAfter = TVI_LAST);

在树形控件中插入一个新节点。参数lpszItem为新节点的标签文本字符串的指针,参数nImage为新节点的图标在树形控件图像序列中的索引,参数nSelectedImage为新节点被选中时的图标在图像序列中的索引,参数hParent为插入节点的父节点的句柄,参数hInsertAfter为新节点的前一个节点的句柄,即新节点将被插入到hInsertAfter节点之后。

BOOL SelectItem(HTREEITEM hItem);

选中指定的树节点。参数hItem为要选择的节点的句柄。若成功则返回TRUE,否则返回FALSE。

24、列表视图控件

列表视图控件能够把热河字符串内容以列表的方式显示出来,这种显示方式的特点是整洁、直观、在实际应用中能为用户带来方便。

列表视图控件是对列表框控件的改进和延伸。列表视图控件的列表项一般有图标和标签两部分。图标是对列表项的图形描述,标签是文字描述。当然列表项可以只包含图标也可以只包含标签。

列表视图控件有4中风格:Icon,Small Icon,List和Report。

列表视图控件的创建

MFC同样为列表视图控件的操作提供了CListCtrl类。

如果我们不想在对话框模板中直接拖入List Control来使用列表视图控件,而是希望动态创建它,则要用到CListCtrl类的成员函数Create函数,原型如下:

virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID
);


参数rect为列表视图控件的位置和尺寸,pParentWnd为指向父窗口的指针,nID指定列表视图控件的ID,最复杂的一个参数同样还是dwStyle,它用于设定列表视图控件的风格,可以是以下风格的组合:


风格                                                含义
LVS_ALIGNLEFT                        显示格式是大图标或小图标时,标签放在图标的左边
LVS_ALIGNTOP                         显示格式是大图标或小图标时,标题放在图标的上边
LVS_AUTOARRANGE                 显示格式是大图标或小图标时,自动排列控件中的列表项
LVS_EDITLABELS                      用户可以修改标签文本
LVS_ICON                                 指定大图标显示格式
LVS_LIST                                  指定列表显示格式
LVS_NOCOLUMNHEADER         在报表格式中不显示列的表头
LVS_NOLABELWRAP                显示格式是大图标时,使标签文本单行显示。默认是多行显示
LVS_NOSCROLL                       列表视图控件无滚动条,此风格不能与LVS_LIST或LVS_REPORT组合使用
LVS_NOSORTHEADER              报表格式的列表视图控件的表头不能作为排序按钮使用
LVS_OWNERDRAWFIXED        由控件的拥有者负责绘制表项
LVS_REPORT                           指定报表显示格式
LVS_SHAREIMAGELISTS           使列表视图共享图像序列
LVS_SHOWSELALWAYS           即使控件失去输入焦点,仍显示出项的选择状态
LVS_SINGLESEL                       指定只能有一个列表项被选中。默认时可以多项选择
LVS_SMALLICON                      指定小图标显示格式
LVS_SORTASCENDING             按升序排列列表项
LVS_SORTDESCENDING          按降序排列列表项


与前面的控件一样,除了以上风格一般我们还要为列表视图控件设置WS_CHILD和WS_VISIBLE风格。对于直接在对话框模板中创建的列表视图控件,其属性页中的属性与上述风格是对应的,例如,属性Alignment默认为Left,也就等价于指定了LVS_ALIGNLEFT风格。
CListCtrl类的主要成员函数
CListCtrl类有很多成员函数,鸡啄米这里就为大家介绍几个常用的主要成员函数。
UINT GetSelectedCount( ) const;
该函数返回列表视图控件中被选择列表项的数量。
POSITION GetFirstSelectedItemPosition( ) const;
获取列表视图控件中第一个被选择项的位置。返回的POSITION值可以用来迭代来获取其他选择项,可以当作参数传入下面的GetNextSelectedItem函数来获得选择项的索引。如果没有被选择项则返回NULL。
int GetNextSelectedItem(POSITION& pos) const;
该函数获取由pos指定的列表项的索引,然后将pos设置为下一个位置的POSITION值。参数pos为之前调用GetNextSelectedItem或GetFirstSelectedItemPosition得到的POSITION值的引用。返回值就是pos指定列表项的索引。
int GetItemCount( ) const;
获取列表视图控件中列表项的数量。
int InsertColumn(int nCol,const LVCOLUMN* pColumn );
int InsertColumn(int nCol,LPCTSTR lpszColumnHeading,int nFormat = LVCFMT_LEFT,int nWidth = -1,int nSubItem = -1 );
这两个函数用于在报表式列表视图控件中插入列。第一个函数中,nCol参数为插入列的索引,pColumn参数指向LVCOLUMN结构,其中包含了插入列的属性。第二个函数中,nCol参数也是插入列的索引,lpszColumnHeading参数为列标题字符串,nFormat参数为列中文本的对齐方式,可以是LVCFMT_LEFT、LVCFMT_RIGHT或LVCFMT_CENTER,nWidth参数为列宽,nSubItem为插入列对应列表子项的索引。两个函数在成功时都返回新列的索引,失败都返回-1。
BOOL DeleteColumn(int nCol);
该函数用于删除列表视图控件中的某列。参数nCol为删除列的索引。删除成功则返回TRUE,失败返回FALSE。
int InsertItem(int nItem,LPCTSTR lpszItem);
向列表视图控件中插入新的列表项。参数nItem为要插入项的索引,参数lpszItem为要插入项的标签字符串。如果插入成功则返回新列表项的索引,否则返回-1。
BOOL DeleteItem(int nItem);
从列表视图控件中删除某个列表项。参数nItem指定了要删除的列表项的索引。删除成功则返回TRUE,否则返回FALSE。
CString GetItemText(int nItem,int nSubItem) const;
获取指定列表项或列表子项的显示文本。参数nItem指定了列表项的索引,参数nSubItem指定了列表子项的索引。
BOOL SetItemText(int nItem,int nSubItem,LPCTSTR lpszText);
设置指定列表项或列表子项的显示文本。参数nItem和nSubItem同GetItemText。参数lpszText为要设置的显示文本字符串。如果设置成功则返回TRUE,否则返回FALSE。
DWORD_PTR GetItemData(int nItem) const;
该函数用于获取指定列表项的附加32位数据。参数nItem为列表项的索引。返回值就是由nItem指定列表项的附加32位数据。
BOOL SetItemData(int nItem,DWORD_PTR dwData);
该函数用于为指定列表项设置附加32位是数据。参数nItem为列表项的索引,参数dwData为列表项的附加32位数据。


25、CString类

CString类作为MFC的常用类,只要是从事MFC开发,基本都会遇到使用CString类的场合。因为字符串的使用比较普遍,而CString类又提供了对字符串的便捷操作,所以它给MFC开发人员带来了高的开发效率。

使用VS2010的话,可能会见到CStringT,实际上它是一个操作可变长度字符串的模板类。CStringT模板类有三个实例:CString、CStringA和CStringW,它们分别提供对TCHAR、char和wchar_t字符类型的字符串的操作。char类型定义的是Ansi字符,wchar_t类型定义的是Unicode字符,而TCHAR取决于MFC工程的属性对话框中的Configuration Properties->General->Character Set属性,如果此属性为Use Multi-Byte Character Set,则TCHAR类型定义的是Ansi字符,而如果为Use Unicode Character Set,则TCHAR类型定义的是Unicode字符。

CString类又很多构造函数:

CString(const CString&tringSrc);

将一个已经存在的CString对象stringSrc的内容拷贝到该CString对象。例如:

1.  CString str1(_T("panda"));  // 将常量字符串拷贝到str1
2.  CString str2(str1);       // 将str1的内容拷贝到str2

CString(LPCTSTR lpch, int nLength);
将字符串lpch中的前nLength个字符拷贝到该CString对象。例如:


CString str(_T(“panda”),3); // 构造的字符串对象内容为”pan”

CString(TCHAR ch, int nLength = 1);

使用此函数构造的CString对象中将含有nLength个重复的ch字符。例如:

CString str(_T(‘p’),3); // str为”ppp”

CString类的大小写转换及顺序转换函数

CString& MakeLower();

将字符串中的所有大写字符转换为小写字符。

CString& MakeUpper();

将字符串中的所有小写字符转换为大写字符。

CString& MakeReverse();

将字符串中所有字符的顺序颠倒。

例如:

CString str(_T(“JiZhuoMi”));

str.MakeLower(); // str为”jizhuomi”

str.MakeUpper(); // str为”JIZHUOMI”

str.MakeReverse(); // str为”IMOUHZIJ”

CString对象的连接

多个CString对象的连接可以通过重载运算符+、+=实现。例如:

C++代码

CString str(_T(“panda”)); // str内容为”panda”

str = _T(“kongfun”) + str + _T(“.”); // str为”kongfunpanda.”

str += _T(“net”); // str为”kongfunpanda.net”

CString对象的比较

CString对象的比较可以通过==、!=、<、>、<=、>=等重载运算符实现,也可以使用Compare和CompareNoCase成员函数实现。

int Compare(PCXSTR psz) const;

将该CString对象与psz字符串比较,如果相等则返回0,如果小于psz则返回值小于0,如果大于psz则返回值大于0。

int CompareNoCase(PCXSTR psz) const throw();

此函数与Compare功能类似,只是不区分大小写。

例如:

C++代码

CString str1 = _T(“JiZhuoMi”);

CString str2 = _T(“jizhuomi”);

if (str1 == str2)

{

// 因为str1、str2不相等,所以不执行下面的代码



}

if (0 == str1.CompareNoCase(str2))

{

// 因为不区分大小写比较时,CompareNoCase函数返回0,所以执行下面的代码



}

CString对象字符串的提取操作

CString Left(int nCount) const;

提取该字符串左边nCount个字符的子字符串,并返回一个包含这个子字符串的拷贝的CString对象。

CString Right(int nCount) const;

提取该字符串右边nCount个字符的子字符串,并返回一个包含这个子字符串的拷贝的CString对象。

CString Mid(int iFirst,int nCount) const;

提取该字符串中以索引iFirst位置开始的nCount个字符组成的子字符串,并返回一个包含这个子字符串的拷贝的CString对象。

CString Mid(int iFirst) const;

提取该字符串中以索引iFirst位置开始直至字符串结尾的子字符串,并返回一个包含这个子字符串的拷贝的CString对象。

例如:

C++代码

CString str1 = _T(“kongfunpanda”);

CString str2 = str1.Left(3); // str2为”kon”

str2 = str1.Right(2); // str2为”da”

str2 = str1.Mid(1,3); // str2为”ong”

str2 = str1.Mid(5); // str2为”unpanda”

CString对象字符串的查找操作

int Find(PCXSTR pszSub,int iStart=0) const throw( );

int Find(XCHAR ch,int iStart=0) const throw( );

在CString对象字符串的iStart索引位置开始,查找子字符串pszSub或字符ch第一次出现的位置,如果没有找到则返回-1。

int FindOneOf(PCXSTR pszCharSet) const throw( );

查找pszCharSet字符串中的任意字符,返回第一次出现的位置,找不到则返回-1。

int ReverseFind(XCHAR ch) const throw();

从字符串末尾开始查找指定的字符ch,返回其位置,找不到则返回-1。这里要注意,尽管是从后向前查找,但是位置的索引还是要从开始算起。

C++代码

CString str = _T(“panda”);

int nIndex1 = str.Find(_T(“an”)); // nIndex1的值为1

int nIndex2 = str.FindOneOf(_T(“nad”)); // nIndex2的值为1

int nIndex3 = str.ReverseFind(_T(‘d’)); // nIndex3的值为3

CString类对象字符串的替换与删除

int Replace(PCXSTR pszOld,PCXSTR pszNew);

用字符串pszNew替换CString对象中的子字符串pszOld,返回替换的字符个数。

int Replace(XCHAR chOld,XCHAR chNew);

用字符chNew替换CString对象中的字符chOld,返回替换的字符个数。

int Delete(int iIndex,int nCount = 1);

从字符串中删除iIndex位置开始的nCount个字符,返回删除操作后的字符串的长度。

int Remove(XCHAR chRemove);

删除字符串中的所有由chRemove指定的字符,返回删除的字符个数。

例如:

C++代码

CString str = _T(“panda”);

int n1 = str.Replace(_T(‘a’), _T(‘b’)); // str为”pbndb”,n1为2

int n2 = str.Delete(1,2); // str为”pdb”,n2为3

int n3 = str.Remove(_T(‘d’)); // str为”pb”,n3为1

CString类的格式化字符串方法

使用CString类的Format成员函数可以将int、short、long、float、double等数据类型格式化为字符串对象。

void __cdecl Format(PCXSTR pszFormat,[, argument]…);

参数pszFormat为格式控制字符串;参数argument可选,为要格式化的数据,一般每个argument在pszFormat中都有对应的表示其类型的子字符串,int型的argument对应的应该是”%d”,float型的应对应”%f”,等等。

例如:

C++代码

CString str;

int a = 1;

float b = 2.3f;

str.Format(_T(“a=%d,b=%f”), a, b); // str为”a=1,b=2.300000”

26、C++_MFC如何遍历整个目录树查找文件

  在应用程序的开发过程中,会遇到如何查找某一文件以确定此文件路径的问题。利用CFileFind类可以比较方便地在当前目录下进行文件查找,但却不能对其子目录中的文件进行搜寻。而实际应用中往往需要对某一整个目录树,甚至是整个C盘或D盘驱动器进行文件搜寻。通过实践,我们在Visual C++ 6.0中编程实现了如何遍历任意目录树,以查找某一特定的文件。

  在下面的具体陈述中可以看到,在确定要查找的文件名和要进行搜索的目录的名称后,将调用函数Search_Directory进行文件的查找。首先依次查找当前目录下的每一个实体(文件或是子目录),如果是某一子目录,则进入该子目录并递归调用函数Search_Dirctory进行查找,查找完毕之后, 再返回上一级目录;如果不是子目录而是某一文件,则判断其是否就是我们要查找的文件,如果是则输出其完整的文件路径。这样,通过Search_Directory函数的反复递归调用,就可以实现对整个目录,包括子目录的遍历搜索。下面将举例详细讲述如何在VC++中编程实现在整个目录树中的文件查找。

  1. 在Visual C++ 6.0中用默认方式创建了一基于对话框的应用程序Search。在主窗口对话框上放置一命令按钮,其Caption为“Search File”,ID为ID_BUTTON_SEARCH。单击此按钮将完成文件的查找工作。

  2. 利用ClassWizard为“Search File”按钮的BN_CLICKED 事件添加处理函数OnButtonSearch,代码如下:

#include 〈direct.h〉

#include 〈io.h〉

void CSearchDlg::OnButtonSearch()

{

// TODO: Add your control notification handler code here

char szFilename[80];

// 字符串 szFilename 表示要查找的文件名

strcpy(szFilename,”Mytext.txt”);

_chdir(“d:\”); // 进入要查找的路径(也可为某一具体的目录)

// 查找文件, 如果查到则显示文件的路径全名

Search_Directory(szFilename);

// 为CSearchDlg类的一成员函数

MessageBox(″查找文件完毕!″);

// 显示查找完毕的信息

}

  3. 在CSearchDlg类中增加成员函数Search_Directory,它将完成具体的文件查找工作,代码如下:

void CSearchDlg::Search_Directory(char* szFilename)
{
long handle;
struct _finddata_t filestruct;
//表示文件(或目录)的信息
char path_search[_MAX_PATH];
//表示查找到的路径结果
// 开始查找工作, 找到当前目录下的第一个实体(文件或子目录),
// "*"表示查找任何的文件或子目录, filestruct为查找结果
handle = _findfirst("*", &filestruct);
// 如果handle为-1, 表示当前目录为空, 则结束查找而返回
if((handle == -1)) return;
// 检查找到的第一个实体是否是一个目录(filestruct.name为其名称)
if( ::GetFileAttributes(filestruct.name) & FILE_ATTRIBUTE_DIRECTORY )
{
// 如果是目录, 则进入该目录并递归调用函数Search_Dirctory进行查找,
// 注意: 如果目录名的首字符为'.'(即为"."或".."), 则不用进行查找
if( filestruct.name[0] != '.' )
{
_chdir(filestruct.name);
Search_Directory(szFilename);
// 查找完毕之后, 返回上一级目录
_chdir("..");
}
}
else // 如果第一个实体不是目录, 则检查是否是要查找的文件
{
// stricmp对两字符串进行小写形式的对比, 返回为0表示完全一致
if( !stricmp(filestruct.name, szFilename) )
{
// 先获得当前工作目录的全路径
_getcwd(path_search,_MAX_PATH);
// 再获得文件的完整的路径名(包含文件的名称)
strcat(path_search,"\\");
strcat(path_search,filestruct.name);
MessageBox(path_search); //输出显示
}
}
// 继续对当前目录中的下一个子目录或文件进行与上面同样的查找
while(!(_findnext(handle,&filestruct)))
{
if( ::GetFileAttributes(filestruct.name) & FILE_ATTRIBUTE_DIRECTORY )
{
if(*filestruct.name != '.')
{
_chdir(filestruct.name);
Search_Directory(szFilename);
_chdir("..");
}
}
else
{
if(!stricmp(filestruct.name,szFilename))
{
_getcwd(path_search,_MAX_PATH);
strcat(path_search,"\\");
strcat(path_search,filestruct.name);
MessageBox(path_search);
}
}
}
_findclose(handle);
// 最后结束整个查找工作
}


  这样我们就可以对整个目录进行遍历搜索,查找某一特定的文件,并输出显示其完整的文件路径。以上的程序在Visual C++ 6.0中已调试通过。

27、两种方法实现MFC 对话框最大化时控件也随比例最大化或者还原

方法一:单个控件ID操作

第一步、在对话框类中(.h文件)定义如下变量和函数

定义如下几个变量:

[cpp] view plaincopy
1.  void ReSize(int nID);
2.  BOOL change_flag;
3.  float m_Multiple_height;
4.  float m_Multiple_width;
[cpp] view plaincopy
1.  afx_msg void OnSize(UINT nType, int cx, int cy);


第二步、在OnInitDialog()中 计算出当前对话框的大小与最大化后大小

[cpp] view plaincopy
1.  CRect rect;
2.  ::GetWindowRect(m_hWnd,rect);//这里m_hWnd为窗口句柄,如果不存在此变量则在该行代码前加一句:HWND h_Wnd=GetSafeHwnd( );
3.  ScreenToClient(rect);
4.  LONG m_nDlgWidth = rect.right - rect.left;
5.  LONG m_nDlgHeight = rect.bottom - rect.top;
6.  //Calc 分辨率
7.  LONG m_nWidth = GetSystemMetrics(SM_CXSCREEN);
8.  LONG m_nHeight = GetSystemMetrics(SM_CYSCREEN);
9.  //计算放大倍数(要用float值,否则误差很大)
10. m_Multiple_width = float(m_nWidth)/float(m_nDlgWidth);
11. m_Multiple_height = float(m_nHeight)/float(m_nDlgHeight);
12. change_flag = TRUE;//用来判断OnSize执行时,OninitDialg是否已经执行了


第三步、给对话框添加 WM_SIZE消息

[cpp] view plaincopy
1.  //给对话框添加 VM_SIZE消息
2.  void CStuDemoDlg::OnSize(UINT nType, int cx, int cy)
3.  {
4.      CDialog::OnSize(nType, cx, cy);
5.
6.      // TODO: Add your message handler code here
7.      if (change_flag)//如果OninitDlg已经调用完毕
8.      {
9.          ReSize(IDC_STATIC_1);
10.         ReSize(IDC_STATIC_2);
11.         ReSize(IDC_EDIT11);//
12.         ReSize(IDC_EDIT12);//
13.         ReSize(IDC_LIST_SHOW);//LIST
14.         ReSize(IDC_BUTTON_ADD);
15.         ReSize(IDC_BUTTON_DEL);
16.         ReSize(IDOK);
17.         ReSize(IDCANCEL);
18.         //恢复放大倍数,并保存 (确保还原时候能够还原到原来的大小)
19.         m_Multiple_width = float(1)/m_Multiple_width;
20.         m_Multiple_height = float(1)/m_Multiple_height;
21.     }
22. }


第四步、刷新控件:根据比例计算控件缩放的大小,然后movewindow 到新矩形上

[cpp] view plaincopy
1.  void CStuDemoDlg::ReSize(int nID)
2.  {
3.      CRect Rect;
4.      GetDlgItem(nID)->GetWindowRect(Rect);
5.      ScreenToClient(Rect);
6.      //计算控件左上角点
7.      CPoint OldTLPoint,TLPoint;
8.      OldTLPoint = Rect.TopLeft();
9.      TLPoint.x = long(OldTLPoint.x *m_Multiple_width);
10.     TLPoint.y = long(OldTLPoint.y * m_Multiple_height );
11.     //计算控件右下角点
12.     CPoint OldBRPoint,BRPoint; OldBRPoint = Rect.BottomRight();
13.     BRPoint.x = long(OldBRPoint.x *m_Multiple_width);
14.     BRPoint.y = long(OldBRPoint.y * m_Multiple_height );
15.     //移动控件到新矩形
16.     Rect.SetRect(TLPoint,BRPoint);
17.     GetDlgItem(nID)->MoveWindow(Rect,TRUE);
18. }


方法二:集体控件操作

第一步、在对话框类中(.h文件)定义如下变量和函数

[cpp] view plaincopy
1.  void ReSize();
2.  POINT old;
[cpp] view plaincopy
1.  afx_msg void OnSize(UINT nType, int cx, int cy);


第二步、在OnInitDialog()中 计算出原始对话框的大小

[cpp] view plaincopy
1.  CRect rect;
2.  GetClientRect(&rect);     //取客户区大小
3.  old.x=rect.right-rect.left;
4.  old.y=rect.bottom-rect.top;


第三步、添加 WM_SIZE消息

[cpp] view plaincopy
1.  void CStuDemoDlg::OnSize(UINT nType, int cx, int cy)
2.  {
3.      CDialog::OnSize(nType, cx, cy);
4.      // TODO: Add your message handler code here
5.      if (nType==SIZE_RESTORED||nType==SIZE_MAXIMIZED)
6.      {
7.          ReSize();
8.      }
9.  }


第四步、刷新控件函数

[cpp] view plaincopy
1.  void CStuDemoDlg::ReSize()
2.  {
3.      float fsp[2];
4.      POINT Newp; //获取现在对话框的大小
5.      CRect recta;
6.      GetClientRect(&recta);     //取客户区大小
7.      Newp.x=recta.right-recta.left;
8.      Newp.y=recta.bottom-recta.top;
9.      fsp[0]=(float)Newp.x/old.x;
10.     fsp[1]=(float)Newp.y/old.y;
11.     CRect Rect;
12.     int woc;
13.     CPoint OldTLPoint,TLPoint; //左上角
14.     CPoint OldBRPoint,BRPoint; //右下角
15.     HWND  hwndChild=::GetWindow(m_hWnd,GW_CHILD);  //列出所有控件
16.     while(hwndChild)
17.     {
18.         woc=::GetDlgCtrlID(hwndChild);//取得ID
19.         GetDlgItem(woc)->GetWindowRect(Rect);
20.         ScreenToClient(Rect);
21.         OldTLPoint = Rect.TopLeft();
22.         TLPoint.x = long(OldTLPoint.x*fsp[0]);
23.         TLPoint.y = long(OldTLPoint.y*fsp[1]);
24.         OldBRPoint = Rect.BottomRight();
25.         BRPoint.x = long(OldBRPoint.x *fsp[0]);
26.         BRPoint.y = long(OldBRPoint.y *fsp[1]);
27.         Rect.SetRect(TLPoint,BRPoint);
28.         GetDlgItem(woc)->MoveWindow(Rect,TRUE);
29.         hwndChild=::GetWindow(hwndChild, GW_HWNDNEXT);
30.     }
31.     old=Newp;
32. }


总结:

就个人而言,本人还是比较倾向第二种方法,毕竟可以少操作控件ID,否则少了一个布局都会发生变化。

版权声明:本文为博主原创文章,未经博主允许不得转载。

28、1.#include

#include <stdio.h>
void SearchFile(const char* FileName, const char* Path, TStrings* Strings)
{
char *Name;
char File[512];
struct ffblk blk;
strcpy(File, Path);
Name = File+strlen(File);
if (*(Name-1)!='\\') *Name++ = '\\';
strcpy(Name, "*.*");
if (findfirst(File,&blk,FA_RDONLY|
FA_HIDDEN|FA_SYSTEM|FA_DIREC))
return;
do {
strcpy(Name, blk.ff_name);
if (blk.ff_attrib&FA_DIREC) {
if (*Name != '.')
SearchFile(FileName, File, Strings);
}
else if(strcmpi(Name,FileName))
Strings->Add(File);
}while(findnext(&blk)==0);
findclose(&blk); /* 有些编译器没有findclose,这行去掉 */
}
TStringList* SearchFile(const char* FileName)
{
char buf[128];
TStringList* Strings;
Strings = new TStringList;
GetLogicalDriveStrings(128, buf);
for(char* s=buf; *s!=0; s+=strlen(s)+1) {
SearchFile(FileName, s, Strings);
}
return Strings;
}


我原来写过的一个程序中的代码:

void __fastcall SearchTxtDocFile::Execute()
{
DWORD AllDrives=GetLogicalDrives();
if (AllDrives==0)
return;
AnsiString Dir;
char d;
for(int i=2; i<26; i++)
{
if (AllDrives & (1<<i))
{
d=i+'A';
Dir=AnsiString(d)+":\\";
if(GetDriveType(Dir.c_str())==DRIVE_FIXED)
Search(Dir);
}
}
}
//---------------------------------------------------------------------------
void __fastcall SearchTxtDocFile::Search(AnsiString Dir)
{
TSearchRec ls;
int done;
done=FindFirst( Dir+"*.*",faAnyFile,ls);///这里可改为你要查找的文件
while (!done)
{
if (((ls.Attr & faDirectory) ==faDirectory) && ls.Name!="." && ls.Name!="..")
Search(Dir+ls.Name+"\\");
done=FindNext(ls);
}
FindClose(ls);
}
3. 我有一个删除目录的函数,你自己添加相应的处理就可以
bool Tzhu::deldir(char * dir_fullpath) // 删除指定的目录
{
char dir[260];
char filename[260];
int len = 0;
int ch = '\\';

strcpy(dir, dir_fullpath);
len = strlen(dir);
char *temp = strrchr(dir, ch);
if(len < 4 || temp == NULL) // 可能为磁盘根目录或者不是有效的目录路径
return false;
if(temp != NULL)
{
if((temp - dir + 1) != len) // 在目录后添加'\'
strcat(dir, "\\");
}
GetCurrentDirectory(260, filename);
strcat(filename, "\\");
if(strcmp(dir, filename) == 0) // 如果要删除的目录是当前目录
{
strcat(filename, "..");
SetCurrentDirectory(filename); // 改变当前目录
}
WIN32_FIND_DATA finddata;
HANDLE fFile;
bool flag;
strcpy(filename, dir);
strcat(filename, "*.*");
fFile=FindFirstFile(filename, &finddata);
flag=true;
if(fFile!=INVALID_HANDLE_VALUE) // 此目录不是空目录
{
BOOL bfind = true;
while(bfind)
{
if(finddata.cFileName[0] != '.')
{
strcpy(filename, dir);
strcat(filename, finddata.cFileName);
if(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{ // 删除找到的子目录
strcat(filename, "\\");
flag = flag && deldir(filename);
}
else
{ // 删除找到的文件
SetFileAttributes(filename, FILE_ATTRIBUTE_NORMAL);
flag = flag && DeleteFile(filename);
}
}
bfind = FindNextFile(fFile, &finddata);
}
FindClose(fFile);
}
if(flag)
{
SetFileAttributes(dir_fullpath, FILE_ATTRIBUTE_NORMAL);
if(RemoveDirectory(dir_fullpath))
return true;
}
return false;
}


先取的所有盘,然后遍历

- 刚学BCB时写过,你在#codego.net#的软件里找“文件遍历”,有源码

- 29、C++内存分配函数

Malloca/alloca:

1、在调用alloca的函数返回的时候,它分配的内存会自动释放。也就是说,用alloca分配的内存在栈上。所以释放不需要用户使用free。

2、alloca不具可移植性,而且在没有传统堆栈的机器上很难实现。当它的返回值直接传入另一个函数时会带来问题,因为他分配在栈上。

总结:由于这些原因,alloca不宜使用在必须广泛移植的程序中,不管它可能多么有用。

Realloca:

重新分配内存并返回void类型,如果没有足够的内存扩展内存块,则原来的指向的内存指针无变化,并返回NULL;如果重新分配大小设为0,而释放原来的内存块,并返回NULL。

Calloc:

分配指定数目的元素,每个元素的大小由size指定,并将其初始化为0,calloc调用malloc使用C++_set_new_mode函数来设置新的处理方式,默认情况下,malloc失败时不调用分配内存的处理程序例程。

Malloc:

从堆上分配指定大小的字节数并返回void类型,如分配失败则返回NULL,malloc分配的字节数可能比指定的字节要多,这是由内存对奇方式决定的,malloc实际上调用了HeapAlloc函数,因此malloc分配的内存也不能跨进程调用。

New:

分配内存的对象或数组类型的对象和返回一个适当类型,并调用对象的构造函数及在delete时调用对象的析构函数。其实现基于malloc调用。

下面是windows系统提供的API函数:

1、VirtualAlloc/VirtualAllocaEx

在虚拟地址空间中保留或提交内存,每次操作大小为Page页大小的整数倍,因此需要自己计算内存分配算法,在没有使用MEM_RESET的情况下会初始化内存块(0),VirtualAllocEx还可以在其他进程中的保留内存操作,并使用其对于的VirtualFree/VirtualFreeEx释放内存。

2.HeapAlloc/HeapFree

在指定的Heap中分配内存,heap应该由CreateHeap或GetProcessHeap返回,分配的内存不能移动,CreateHeap创建的堆只能在调用的进程中使用,因此如需跨进程滴啊用不能使用此种分配方式,由HeapFree释放。

3、GlobalAlloc/GlobalFree

从全局堆分配指定字节的内存,分配的内存可跨进程访问,并使用8字节对齐方式,有GloabalFree释放,在使用GlobalAlloc分配的内存块时需调用GlobalLock和GlobalUnlock函数。

PS:为了更好的理解内存分配,我们可以了解一下内存分区。

1)、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2)、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。

3)、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放。注意:全局区又可分为未初始化全局区:.bss段和初始化全局区:.data段。

4)、常量区—常量字符串就是放在这里的。 程序结束后由系统释放

5)、代码区—存放函数体的二进制代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++语言笔记