此文章主要在于积累c++可能用到的小知识点,来源有自己总结,也有网上现成的成果感谢他们的分享。好记性不如烂笔头。(会不定期更新)
1.C++中的Sleep() 函数
标准库中无该函数
但在某些编译系统中有,在有些系统库中有,要根据你那边的环境而定。
如:linux中有,unsigned int sleep(unsigned intseconds),传入挂起时间,成功返回0,不成功则返回余下的秒数。
windows系统中有Sleep函数(注意大写),void Sleep(DWORD dwMilliseconds);提供挂起的毫秒数。
2.c++ unsigned char * 转 char*
最好的建议是使用memcpy,memcpy是给定来源和目标后,拷贝指定大小n的内存数据,而不管拷贝的内容是什么(不仅限于字符)
memcpy的原型为void *memcpy(void *dest, const void* src,size_t size);
另外:strcpy是拷贝字符串,以\0为标志结束(即一旦遇到数据值为0的内存地址拷贝过程即停止)
strcpy的原型为
char *strcpy(char *dest, const char *src)
3.switch()case里不能初始化变量的问题
如switch(msg){
case 0:
int i=0;
i+=3;
break;
default:
}这样的语句会报“XXXX不能初始化变量...”
要改成如下代码就不会报错了
switch(msg){
case 0:
{
int i=0;
i+=3;
}
break;
}
4.打开文件对话框
OPENFILENAME ofn;
TCHAR szFile[256];
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME); //此结构体大小,以字节为单位
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFile;//用来保存载入文件的路径和文件名
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile); //用来对应载入文件名的最大长度,一般为lpstrFile赋值数组的长度
ofn.lpstrFilter = TEXT("zs Files(.zs)\0*.zs;\0"); //在对话框选中选择择文件的过滤文件类型
ofn.nFilterIndex = 1; //文件过滤器的索引值(在不设置自定义过滤器的条件下)
ofn.lpstrFileTitle = NULL; //
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
//位标记的设置。当对话框返回时,根据设置的位标记指出用户的输入,如OFN_CREATEPROMPT表示当用户输入了一个不存在的文件时,对话框返回时提示是否 要新建这个文件
if (GetOpenFileName(&ofn))
{
......
}
5.打开保存文件对话框
OPENFILENAME ofn = { 0 };
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = GetForegroundWindow();
ofn.lpstrFilter = TEXT("Text Files (.txt)\0*.txt;\0");//要保存的文件后缀
ofn.lpstrInitialDir = NULL;//默认的文件路径
ofn.lpstrFile = szBuffer;//存放文件的缓冲区
ofn.lpstrDefExt = _T("txt");
ofn.nMaxFile = 256;
ofn.nFilterIndex = 0;
ofn.lpstrTitle = _T(""); //对话框的标题
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;//标志如果是多选要加上OFN_ALLOWMULTISELECT
BOOL bSel = GetSaveFileName(&ofn);
if (bSel){
......
}
6.c++ 在编程socket通信调用bind函数时,
bind函数的定义总是显示为#include<functional>并非#include<winsock2.h>导致绑定失败,为什么?
答:在调用bind函数时要用::bind()
::bind()就是调用的#include<winsock2.h>中的bind函数,::在这里的作用是表示后面的函数是API函数,非所在类的成员函数。
7.如何解决"应用程序无法正常启动0xc000007b"?
答:百度搜索DirectX修复工具(最好为增强版)软件为绿色免费版不用担心注册问题。
打开软件点击检测并修复。DirectX修复工具会检测丢失的dll文件并进行修复。
8.应用程序主窗体关闭后,程序不退出,在进程管理器中仍然能看到其在运行,怎么处理?
答:一般主窗体关闭后程序不退出(有死进程)有两种情况:
(1)有隐藏的窗体没close掉。
(2)程序里有线程,while死循环,没有退出;
设置为后台线程,则窗体关闭,线程也跟着关闭
9.C++中struct与class有何区别?
答:C++ 中保留了C语言的 struct 关键字,并且加以扩充。在C语言中,struct 只能包含成员变量,不能包含成员函数。而在C++中,struct 类似于 class,既可以包含成员变量,又可以包含成员函数。
C++中的 struct 和 class 基本是通用的,唯有几个细节不同:
- 使用 class 时,类中的成员默认都是 private 属性的;而使用 struct 时,结构体中的成员默认都是 public 属性的。
- class 继承默认是 private 继承,而 struct 继承默认是 public 继承。
- class 可以使用模板,而 struct 不能。
答:在C++中,我们可以使用静态成员变量来实现多个对象共享数据的目标。静态成员变量是一种特殊的成员变量,它被关键字static
修饰。
(1)static 成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。反过来说,没有在类外初始化的 static 成员变量不能使用。
static 成员变量既可以通过对象来访问,也可以通过类来访问。请看下面的例子:
- //通过类类访问 static 成员变量
- Student::m_total = 10;
- //通过对象来访问 static 成员变量
- Student stu("小明", 15, 92.5f);
- stu.m_total = 20;
- //通过对象指针来访问 static 成员变量
- Student *pstu = new Student("李华", 16, 96);
- pstu -> m_total = 20;
(2)注意:static 成员变量不占用对象的内存,而是在所有对象之外开辟内存,即使不创建对象也可以访问
几点说明
1) 一个类中可以有一个或多个静态成员变量,所有的对象都共享这些静态成员变量,都可以引用它。
2) static 成员变量和普通 static 变量一样,都在内存分区中的全局数据区分配内存,到程序结束时才释放。这就意味着,static 成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。
3) 静态成员变量必须初始化,而且只能在类体外进行。例如:
int Student::m_total = 10;
初始化时可以赋初值,也可以不赋值。如果不赋值,那么会被默认初始化为 0。全局数据区的变量都有默认的初始值 0,而动态数据区(堆区、栈区)变量的默认值是不确定的,一般认为是垃圾值。4) 静态成员变量既可以通过对象名访问,也可以通过类名访问,但要遵循 private、protected 和 public 关键字的访问权限限制。当通过对象名访问时,对于不同的对象,访问的是同一份内存。
11.静态成员函数
答:静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
和静态成员变量类似,静态成员函数在声明时要加 static,在定义时不能加 static。
静态成员函数可以通过类来调用(一般都是这样做),也可以通过对象来调用。
12.STL排序问题
答:排序的几种方法
(1)添加头文件#include<functional>,functional提供了一堆基于模板的比较函数对象。它们是(看名字就知道意思了):equal_to<Type>、not_equal_to<Type>、greater<Type>、greater_equal<Type>、less<Type>、less_equal<Type>。
排序中一般用less<Type>和greater<Type>。升序:sort<begin,end,less<Type>());降序:sort<begin,end,greater<Type>());
1)自己编写一个比较函数来实现,接着调用三个参数的sort:sort(begin,end,compare)就成了。对于list容器,这个方法也适用,把compare作为sort的参数就可以了,即:sort(compare).
2)自己编写compare函数:
bool compare(int a,int b)
{
return a<b; //升序排列,如果改为return a>b,则为降序
}
sort(begin,end,compare)
3)更进一步,让这种操作更加能适应变化。也就是说,能给比较函数一个参数,用来指示是按升序还是按降序排,这回轮到函数对象出场了。
为了描述方便,我先定义一个枚举类型EnumComp用来表示升序和降序。很简单:
enum Enumcomp{ASC,DESC};
然后开始用一个类来描述这个函数对象。它会根据它的参数来决定是采用“<”还是“>”。
class compare
{
private:
Enumcomp comp;
public:
compare(Enumcomp c):comp(c) {};
bool operator () (int num1,int num2)
{
switch(comp)
{
case ASC:
return num1<num2;
case DESC:
return num1>num2;
}
}
};
接下来使用 sort(begin,end,compare(ASC)实现升序,sort(begin,end,compare(DESC)实现降序。
4)迭代器排序
升序:sort(v.begin(),v.end());
降序:sort(v.rbegin(),v.rend());
(2)数组排序
qsort():
原型:
_CRTIMP void __cdecl qsort (void*, size_t, size_t,int (*)(const void*, const void*));
解释: qsort ( 数组名 ,元素个数,元素占用的空间(sizeof),比较函数)
比较函数是一个自己写的函数 遵循 int com(const void *a,const void *b) 的格式。
当a b关系为 > < = 时,分别返回正值 负值 零 (或者相反)。
使用a b 时要强制转换类型,从void * 转换回应有的类型后,进行操作。
数组下标从零开始,个数为N, 下标0-(n-1)。
实例:
int compare(const void *a,const void *b)
{
return *(int*)b-*(int*)a; //降序:*(int*)b-*(int*)a // 升序:*(int*)a - *(int*)b
}
{
int a[20] = { 2, 4, 1, 23, 5, 76, 0, 43, 24, 65 }, i;
for (i = 0; i < 20; i++)
cout << a[i] << endl;
qsort((void *)a, 20, sizeof(int), compareArr);
for (i = 0; i < 20; i++)
cout << a[i] << endl;
}