记录一些c/c++基础的东西!
1.报错:读取字符串的字符时出错
原因为数据未初始化,问题发生在这行代码
char *p;
指针要初始化的,置为NULL。
2.0x7A1FA006 (msvcr120d.dll) (Project1.exe 中)处有未经处理的异常: 0xC0000005: 写入位置 0x000BCB78 时发生访问冲突?
未解决!
3.数组名是地址,结构体名是什么?
结构体名可不是地址,而是类似于类名,不占存储空间。
4.char指针类型也可以通过下标访问
char *str = "123";
cout << str[0];
cout<<*str;//指向第一个字符
如果想获得第二个字符,可以用*str[1]吗,不行!
*str[1]执行流程为*(str[1]),str[1]是个数据,不是地址,不能用*。
(*str)[1]也不行,因为下标要求数组或指针类型。
正确做法是 cout<<*(str+n);
5.定义一个char s[10];但未初始化,默认会赋值”烫烫“
s[1]='a';//这个s数组不是以'\0'结束的,而是”烫“
6.结构体初始化
typedef struct
{
int a;
char king[];
} KING;
KING b={1};//{}内类型与结构体内类型匹配的初始化为该值,不匹配初始化为空串。
7.空指针不是说指针指向的位置值为空,而是说指针本身的值为 0x00000000 {???},即不指向任何地址。
8.char *str; str="abc";把常量区的字符串"abc"的首地址赋值给了变量str,*str代表a
9.判断字符串指针所指向字符串大小,应该用strlen而不是sizeof,sizeof计算的是指针本身的大小。
char str1[7];
char str2[7] = {1,1,1,1,1,1};
char *pstr= "12434";
cout << sizeof(str1) << " sizeof str1" << endl;
cout << strlen(str1) << " strlen str1" << endl;
cout << sizeof(str2) <<" sizeof str2"<< endl;
cout << strlen(str2) << " strlen str2" << endl;
cout << sizeof(pstr) << " sizeof pstr" << endl;
cout << strlen(pstr) << " strlen pstr" << endl;
结果:
str1未初始化,strlen(str1)值不一定,因为sizeof是遇到终止符才停止。
sizeof(str2)值为7,但是sizeof(pstr)值为4(32位)
10.c++为什么结构体数组超出范围不报错?
数组超出范围,也许可以正常运行,也许不能,具备不确定性,这取决于超出范围的地址的具体情况。c++也许根本没有数组,有的是像数组的数据流,也没有边界检查这样的功能(为了效率?)。
Vector向量容器是具体边界检查功能,可以分别通过.at()或[]访问元素来选择绑定检查或不选择绑定检查。
11.非常量引用
12.10进制和16进制与运算得到几进制
在内存中的体现是16进制。
int iOutPut;
iOutPut = szSrc[0];
为什么iOutPut的值是-92,而不是164?
‘?’的ascii码为十进制63,为何a4会显示为-92?二者不等价。
如果将a4看作补码,正好表示的是-92;
右侧显示的是左侧的值所对应的ascii码字符,如果不在范围内就显示为?;
根据观测到规律,如果左侧值大于127,那么编译器就会将其当作负数的补码来看?
不是,不管是正数还是负数在计算机中都是以补码形式存在,只是正数补码和原码都相同。算术运算,减法相当于加一个负数,故采用补码形式,此外还有其他的原因(硬件电路)。
SzSrc是int类型,类型转换后就是164
首先char类型是用一个字节来表示的,表示的数值范围是-128~127,所以0xFF按照有符号数的法则,最高bit位表示正负号:为0表示正,为1表示负.后面的7个bit位才表示数值,不过这个数值也不是直接表示的,而是取的对应数值的补码,对于正数原码和补码相同,而负数则是取反加1
解决方法:
char a = 0x9A;
int num = (int)(unsigned int)a;
- @和¥等符号在c++中的含义
$、@、|、^、~等特殊字符在c或c++中有没有用,在哪里?
|、^ 和 ~ 分别用作按位或、异或和补码
@ 在 C 中一般是无效的;它不用于任何事情。它被 Objective-C 用于各种目的,但那完全是另一回事。
$ 也是无效的,但许多实现允许它出现在标识符中,就像字母一样。 (例如,在这些实现中,如果您愿意,可以将变量或函数命名为 $$$。)尽管如此,它也没有任何特殊含义。
13.C、C++和JAVA等程序语言中,函数参数三个点“...”的意思和用法
三个点代表参数不确定的情况。
例如printf()函数,其函数原型为:
int printf( const char* format, ...);
实际使用的时候,参数的个数是可以变的。比如:
printf("%s",s);
printf("the number is %d ,string is:%s", i, s);
14.无法将参数2 从“char *”转换为“unsigned c
unsigned char *message = reinterpret_cast<unsigned char *>(argv[1]);
15 打印相关
const char *str="Hello world";
cout << hex << &str << endl; //输出的是str指针变量本身的地址(1)
cout << hex << (void *)str << endl; //输出的是str指针指向的值(地址,2)
cout << str <<endl; //输出的是字符串str
16.浮点数转16进制
不能直接用ascii码表示啊
用ascii码表示和转为二进制,是两种不同的。前者用于显示,后者用于编码、传输等。
17.error C4116: 一元负运算符应用于无符号类型,结果仍为无符号类型
error C4146是C++编译器的一个错误代码,表示一元负运算符应用于无符号类型,结果仍为无符号类型。这是因为一元负运算符(即负号)只能应用于有符号类型的操作数,而无符号类型不能被作为负数来处理。
32位,编译器(VS2013)在看到int n = -2147483648;的时候,首先判断2147483648 > INT_MAX,知道int装不下,于是决定使用 unsigned int。结果就是对无符号数使用负运算符。
18.error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MTd_StaticDebug”
运行库设置问题;几个工程的运行库设置不一样会导致该问题。
项目属性->配置属性->C/C++->代码生成->运行库
都设置一样就行了多线程调试(/MTd)
19.头文件中的一个接口,其对应的动态库中没有该接口,会报错吗
虽然没有用到,但是会报错
20.c++getline读取txt时第一行最前面会多出几个字符问题
21.继承
1.类实例(即类对象)不能直接访问类的 private成员和protected成员,但是能直接访问类的public成员。
2.另外无论哪种继承方式,子类都不能直接访问父类的 private成员;但是能直接访问父类的 protected成员和public成员(注意:是子类,而不是类实例),并且能通过父类的protected成员函数和public成员函数间接访问父类的private成员;这句话强调了类与类之间通过继承方式的访问规则,而非类与实例之间的访问规则。
子类继承不能继承父类构造、析构函数。实例化时先执行父类构造、析构时相反。
22.不能实例化抽象类
不能实例化抽象类”编译错误,主要基本是子类继承于抽象类,然后有某个抽象函数没有实现导致的。
23.内联函数无法加断点
对于内联函数,编译器会去掉函数调用,直接将函数代码在调用的位置展开,所以在该函数名上就无法设置断点。使用kprobe或者systemtap也就不能使用函数名探测这样的函数。
内联优化从目标文件中去掉了该函数的入口点,符号表中也没有该函数的名称。
24.c++ void 函数
在C程序中如果在声明函数的时候如果没有任何参数那么需要将参数定义为void以此来限定此函数不可传递任何参数,如果不进行限定让参数表默认为空其意义是可以传递任何参数,这个问题的由来实际上是由于要兼容早期的K&C标准造成的。K&C 在声明函数时参数表为空,也就是说函数声明时的函数原型签名信息不包含参数信息,如果要有明确的定义空参数的行为那么就要自己去处理它。以下是C代码
//空参数表代表可以传递任意的参数, void fun(); fun(1);//正常编译 fun(1,2,3);//正常编译 //参数表定义为void才是表示不能传递任何参数 void noargfun(void); noargfun(1);//编译错误,有的编译器仅仅是警告 |
在C++中定义函数时是否有必要对无参数的函数列表定义void参数呢?答案是No。C++标准规定如果没有对参数列表进行定义那么就表示函数不能传递任何参数,这从语义上来讲更符合人的思维方式。以下是C++代码
//空参数表的意义是不可以传递任何参数 void fun();//void fun(void)含义相同 fun(1);//编译错误 fun(1,2,3);//编译错误 |
当然如果指定义void那么不管在C还是C++都表示不可以传递任何参数
25.fileseek函数
调整文件指针到新的位置,如果操作成功,则返回新的文件位置,如果操作失败,则函数返回-1。
int __fastcall FileSeek(int Handle,int Offset,int Origin);
26.typedef和#define的区别
在C语言中,typedef和define都是用于定义新类型或符号常量的关键字,但它们有一些不同之处。
typedef用于定义新类型,而define用于定义符号常量或函数宏。
typedef可以为已有的数据类型定义一个新的别名,以增强代码的可读性和可维护性。例如:typedef int Length;,这里将int类型定义为Length类型的别名。我们可以使用Length来代替int类型。
define用于定义符号常量或函数宏,并且可以进行字符串替换。例如:#define PI 3.1415926,这里将PI定义为3.1415926的符号常量,可以在程序中使用PI来代替3.1415926。
typedef定义的新类型具有类型检查功能,而define定义的符号常量和函数宏没有类型检查功能。
typedef定义的新类型是编译器能够识别的类型,具有类型检查功能,可以帮助程序员避免类型错误。例如,如果我们定义了typedef int Length;,则编译器会将Length视为int类型,可以在编译时检查类型错误。
define定义的符号常量和函数宏只是简单的字符串替换,没有类型检查功能。例如,如果我们定义了#define PI 3.1415926,则编译器不会对PI的数据类型进行检查。在程序中,如果我们错误地将PI赋值给一个char型变量,编译器也不会发出任何警告信息。
在作用域方面typedef:
如果放在所有函数之外,它的作用域就是从它定义开始直到文件尾;
如果放在某个函数内,定义域就是从定义开始直到该函数结尾;
#define:
不管是在某个函数内,还是在所有函数之外,作用域都是从定义开始直到整个文件结尾。
如:
typedef …//此处开始到文件结尾
#define …//此处开始到文件结尾
int negate(int num)
{
…
typedef …//此处开始到该函数结束。注意,该函数内,此定义前,也不能用
#define …//此处开始到文件结尾
…
}
typedef …//此处开始到文件结尾
#define …//此处开始到文件结尾
void show()
{
typedef …//此处开始到该函数结束。
#define …//此处开始到文件结尾
}
总结:
(1) 不管是typedef还是define,都不能在定义之前使用;
(2) typedef受函数范围影响,而define不受;
(3) 不管是typedef还是define,其作用域都不会扩展到别的文件,即使是同一个程序的不同文件,也不能互相使用。
define定义的符号常量和函数宏只在定义它们的文件或范围内有效,如果需要在多个文件中使用,需要在每个文件中重新定义。
Typedef定义别名的,在定义指针类型时二者有区别。
typedef char* tpcahr;
#define pchar char*
MyClass obj;
int arg = 42;
pchar a, b;
tpcahr a1, b1;
a是一个指针,b是一个字符串;但a1和b1都是指针;宏定义只是字符串替换不是真正的类型。
27.Expression:"Standard C++Libraries Invalid Argument"&&0
28.c++如何判断文件末尾
29.不允许使用抽象类类型的对象?
包含纯虚函数的类成为抽象类,这个问题是因为你把抽象类实例化了,抽象类是类中包含一个或多个纯虚函数,这是被C++禁止的。
那怎么办呢??
---建议不要实例化抽象类,而是定义定该类指针,该指针可以指向子类,形成多态。
30.如何快速退出正在sleep的线程
信号量?
把一个大的休眠分割成多次休眠并不断监测一个变量的值,这是一种实现。
31.0x76F7BB3C (ntdll.dll)处的第一机会异常: 0xC0000005: 读取位置 0x223A324D 时发生访问冲突
可能是地址越界
32.Expression:vector iterators incompatible
33.Windows下创建dump文件的方式
1.1 任务管理器 在程序崩溃后,先不关闭程序,在任务管理器中找到该程序对应的进程。右键—>创建转储文件。 此时会在默认的目录下创建出一个dump文件。 可以看出,此种方法只适用于程序崩溃但没有立即自行退出的情况。倘若程序故障后自行退出,则此方法就难以应用。不过,我们可以在注册表中添加如下信息已确保系统在程序崩溃后自行保存一个dump文件: 在注册表中找到
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\WindowsError Reporting\LocalDumps
添加项如下图:
其中DumpType代表的含义是:
0 = Create a custom dump
1 = Mini dump
2 = Full dump
如此一来,一旦程序崩溃,系统会在C:\CrashDump下生成一个dump文件。
1.2WinDbg抓取
程序运行崩溃后,先不关闭程序,将WinDbg附加到改进程上。
执行命令:.dump –ma Test.dmp ,则会产生一个Test.dmp的转储文件。
34.未定义标识符socklen_t
windows下VS报错:
未定义标识符socklen_t
解决方案:
方法一:将socklen_t替换成int
方法二:使用宏定义,在文件前面加上#define socklen_t int
35.Char 数组{}内可组合多个字符串,如{“d” “ds”}
36.ntohl函数
ntohl()指的是ntohl函数,是将一个无符号长整形数从网络字节顺序转换为主机字节顺序, ntohl()返回一个以主机字节顺序表达的数。
Htons 将一个无符号短整型的主机数值转换为网络字节顺序,即大尾顺序(big-endian)。
网络序和主机序:
-
网络序(Network Byte Order):网络序是指一种统一的数据存储顺序,通常采用大端序(Big-Endian)方式进行存储。在网络通信中,数据的传输需要保持统一的存储顺序,以确保不同系统之间能够正确解释数据。
-
主机序(Host Byte Order):主机序则是指特定计算机系统的数据存储顺序,可能采用大端序或小端序(Little-Endian)方式。在处理数据时,需要考虑当前主机系统的存储顺序,以确保数据的正确解释和处理。
在网络编程中,通常需要将主机序转换为网络序或反之,以确保数据在不同系统之间能够正确传输和解释。常用的函数如htonl()、htons()、ntohl()、ntohs()等可以用来进行网络序和主机序之间的转换
37.数组和指针区别
1. 数组只能在静态存储区被创建(全局数组),或在栈上创建(临时数组);数组名对应一块内存,其地址和容量在生命周期内保持不变,只有内容可改变。(虽然容量是固定的,但是访问超出容量的元素不一定报错,c++没有这样的检测机制)指针可以随时指向任意内存的内存块,特征是“可变”。
2.复制方面:数组名无法直接进行比较,想要将数组a的值复制给数组b,使用b=a会产生编译错误,应该用标准库函数strcpy进行复制。想要判断数组a和b的内容是否相同,使用if(a == b)会产生编译错误,应该使用标准库函数strcmp进行比较。
指针p = a不会将数组a复制到p,而是将a的首地址给p,指针复制需要申请一片大小与目的数组相等的内存,使用strcpy对指针名和数组名进行复制。指针比较,使用strcmp比较两个指针名就可。
3.内存容量不同:数组的字节数sizeof()为其类型字节数和长度的乘积。指针的字节数sizeof()为一个指针的字节数。
4. c/c++语言无法获取到指针所指的内存容量,除非在申请内存的时候记住它。当数组作为函数的参数进行传递时,数组将自动退化为同类型的指针,所以传入数组做参数时一般需要将其长度也作为参数传入,传入的数组想要查看其sizeof时值为4(32系统)
38.C# cannot be marshaled as an unmanaged structure;no meaningful size or offset can be computed
不能作为非托管结构进行封送处理;无法计算有意义的大小或偏移量
正常来说,指明布局即可,即[StructLayoutAttribute(LayoutKind.Sequential)]。但有时候即使指明了也报错,可能是结构体内还有结构体的原因。
不是,真正原因是一个结构体成员定义成了这样,
创建的struct或是class都是属于复杂类型的。(纠正一下,如果成员又有复杂类型的,而所占字节,在运行时,会有所变量,在这使用Marhsal.SizeOf也是无效的,只能对非托管资源的一个统计)
如果不对其内部的一些成员布局设置,直接sizeof()或是Marshal.SizeOf(object), Marshal.SizeOf(Type)是会报这个异常的。
在System.Runtime.InteropServices.Marshal.SizeOf(),MSDN介绍是,总是在运行时计算结构化数据类型的大小。
拓展:解析网络协议如果使用依次读取字节的方式效率太低,可以直接通过结构体映射的方式来转换数据。但是需要注意结构体数据顺序排列并对齐,依次定义每一个属性的长度即可,需要注意定义的数据类型的大小要与UnmanagedType类型定义的大小一直否则会报 “不能作为非托管结构进行封送处理;无法计算有意义的大小或偏移量”
39.声明与定义
定义必须指明参数类型,声明则不必,声明依赖调用者提供正确的参数。
40.求值顺序
- a||b,如果a成立,则不计算b,其他类似运算同理。从运算角度讲,如何用最简单方式达成目的是很关键的。
- y[i]=x[i++];书曰不合理?因为无法保证i在自加前就对y[i]取值?虽然我觉得合理
41. 类A<类B>什么含义?
模板类!
模板类是一种泛型技术,即与数据类型无关的通用程序设计技术。可以使我们设计出独立于数据类型的程序。模板类本身不占空间,当编译器执行到模板参数的调用时,当在程序中赋予具体的数据类型后并调用时则占用空间。
函数模板与模板声明间不能有任何语句,注释可以有。
模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
使用模板时必须确定出通用数据类型T,并且能够推导出一致的类型。
42.ifdef __cplusplus
在C++编译器中,已经内置了__cplusplus这个宏定义,所以在使用C++编译器编译其它语言(比如C语言)时,用这样的方式,可以让编译器把extern “C” 代码块中的内容按照C语言的方式进行编译。如果不加extern “C”限制按照C语言的方式进行编译,那么C++编译器在编译C语言函数时可能就会找不到链接路径而报错。
43.__declspec(dllexport)和__declspec(dllimport)
__declspec(dllexport) 预处理器符用来指示函数是导出的。__declspec(dllimport)指示函数等是导入的。
为什么有这么一对,实际上DLL 和客户端应用程序可以使用相同的头文件,那么到底到底是生成客户端应用程序呢还是DLL,就需要特殊的预处理符号来指明。
此外,如果DLL中无静态变量,不加__declspec(dllimport)也可以正常调用,但若有静态成员,则必须使用__declspec(dllimport)。
示例:
#ifdef _EXPORTING
#define API_DECLSPEC __declspec(dllexport)
#else
#define API_DECLSPEC __declspec(dllimport)
#endif
在DllDlg工程里添加预处理器:_EXPORTING。这等于告诉大家:定义了这个预处理器的就是把函数导出,不定义这个预处理器的就是把函数导入。
加不加__declspec(dllimport)的区别?
- 生成的二进制代码稍有不同
- a、 不加__declspec(dllimport)时,在使用dll中的函数时,编译器并不能区别这是个普通函数,还是从其它dll里导入的函数,所以其生 成的代码如下:
call 地址1
地址1:jmp 实际函数地址
b、有 __declspec(dllimport)时,编译器知道这是要从外部dll导入的函数,从而在生成的exe的输入表里留有该项,以便在运行 exe,PE载入器加载exe时对输入地址表IAT进行填写,这样生成的代码如下:call dword ptr[输入表里哪项对应的内存地址] (注意:现在就不需要jmp stub了)省去中间间接调用。
44.未定义标识符_T?
字符串前面加L表示該字符串是Unicode字符串。
_T是一個宏,若是項目使用了Unicode字符集(定義了UNICODE宏),則自動在字符串前面加上L,不然字符串不變。所以,Visual
C++裏邊定義字符串的時候,用_T來保證兼容性。VC支持ascii和unicode兩種字符類型,用_T能夠保證從ascii編碼類型轉換到unicode編碼類型的時候,程序不須要修改。
字符集改成未设置。
45.错误C2227:“-> looseHealth”的左侧必须指向类/结构/联合/泛型类型
编译器在使用looseHealth时并不知道它是什么。 稍后在源模块中定义该功能。 是时候学习如何制作单独的.cpp和.h文件,以及将函数体移出类定义了。
46.未定义标识符
常见的头文件未导入及工程配置,还有是命名空间的问题。
47.用户回调期间遇到未经处理的异常
一定是有地方数组或者指针越界使用,或者重复释放
48.C++ deprecated?
指示声明有此属性的名字或实体被弃用,即允许但因故不鼓励使用。
[[deprecated]]
[[deprecated( 字符字面量 )]]
49.宏中#作用
#:功能是将其后面的宏参数进行字符串化操作,简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。
##:连接符号由两个井号组成,其功能是在带参数的宏定义中将两个子串联接起来,从而形成一个新的子串。但它不可以是第一个或者最后一个子串。
凡是宏定义里有用#或##的地方宏参数是不会再展开,例如_STRI(INT_MAX)中的INT_MAX就不会被展开为2147483647。
50.无法解析外部符号
未实现CTest就会出现这样问题,什么原因?
声明了函数,未实现就会出现这样的问题。
(2)没把.lib文件导入进来,静态库指明路径啊!
51.0x%X是什么意思
以16进制的形式输出
52.结构体未能生成默认构造函数,c4510错误
Const的问题
const HPR_INT32 iCiphertext2Len
const 变量必须初始化
53.error C2061: 语法错误: 标识符“
没有导入那个结构体,定义在其它文件。
或者没有导入相应的头文件。
54.c4430:缺少类型说明符 - 假定为 int。注意: C++ 不支持默认
有对应的头文件,也能跳转到定义处,但就是会报这样的错误。
命名空间的问题,可能是!
加了依然报错,是因为还没有把该命名空间对应的头文件引入进来。
55.fatal error C1004: 发现意外的文件尾
这个错误通常是由于在源文件中漏写了某些括号或者分号,导致编译器在处理到文件末尾时发现没有遇到预期的符号。
56. c2733:不允许重载函数的第二个 C 链接
57.变量必须初始化吗
像int a;不会报错,但是int *a;会报错的,因为a随机值没什么关系,但a 是地址的话,不能随机,必须初始化。
58.定义,声明的语句之后是否需要加分号“?
类的后面必须跟一个分号结尾!
在C语言汇中,分号(semicolon)是终结符号(terminator),用来终结声明(declaration)或单个语句(statement)。(主要是用来帮助编译器解析源代码的)
就问题而言,对前者来讲是声明,需要加分号;对后者来讲是定义,非声明非语句,不需要加分号。
语句、定义不需要分号结尾,声明需要分号结尾;
语句、定义不需要分号结尾,声明需要分号结尾;
语句、定义不需要分号结尾,声明需要分号结尾;
语句:if、for、while都是statement,所以{ }本身是语句的一部分
定义:void main( ) { }
声明:结构体定义是Declaration,自然需要分号结尾
59.#ifdef OS_WINDOWS 不起作用
显示某个成员未定义,但右键可跳转到定义处,程序编译不过。Main cpp导入该头文件后,虽然显示未定义,但可编译并运行,奇怪!
真正原因,头文件没有导入依赖库(之前在cpp中进行了导入)
60.C++类中的线程处理函数必须为static静态?
pthread_create需要一个函数指针,而不是指向成员函数的指针。这些是C ++中非常不同的类型,因为成员函数指针包含一个隐式的this指针。在实践中,静态成员函数等效于非成员函数,设某函数原型为LRESULT ThreadProc(LPVOID pv);若为非静态成员函数,编译时自动展开为 ThreadProc(pClass-> this, pv);与线程函数调用不相符。所以必须使用全局函数或类静态成员函数。
静态函数无法访问直接非静态成员,所以传入对象本身this,从而通过this间接访问成员。
61.fgets函数
# include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
从 stream 流中读取 size 个字符存储到字符指针变量 s 所指向的内存空间。它的返回值是一个指针,指向字符串中第一个字符的地址。
指定的流中读取数据,每次读取一行。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
62.sscanf函数
和scanf类似,都是用于输入的,后者以键盘为输入源,前者以固定字符串为输入源。
#include <stdio.h>
int sscanf(const char *str, const char *format, ...);
str:待解析的字符串;format:字符串格式描述;其后是一序列数目不定的指针参数,存储解析后的数据。
示例:
int year, month, day;
int converted = sscanf("20191103", "%04d%02d%02d", &year, &month, &day);
printf("converted=%d, year=%d, month=%d, day=%d/n", converted, year, month, day);
63.vs code代码整段右移或者左移
Tab 整体右移
Shift+Tab 整体左移
64.string.find查找逻辑,如果有两个相同的,返回哪个?
Substr第二个参数不是终点!!!!而是移动的距离!
65.debug模式,运行时完全正常,但是一调试就出现对话框,显示出错信息:“无法找到“XXX.exe”的调试信息,或者调试信息不匹配。未使用调试信息生成二进制文件。
首先打开菜单 项目->项目属性页
1选择 配置属性->链接器->调试->生成调试信息 改为 是
2选择 配置属性->C/C++ ->常规->调试信息格式 改为 用于“编辑并继续”的程序数据库(/ZI)
3选择 配置属性->C/C++ ->优化->优化 改为 禁用(/Od)
66.程序添加命令行参数
形式:https://192.0.0.140/a/b/Tools
int main(int argc, char** argv)
int main(int argc, char* argv[])
argc(第一个形参)必须是整型变量,标识该控制台命令调用中接收到的参数个数,注意,包括该命令程序名字itself。
argv( 第二个形参)必须是指向字符串的指针数组,用于保存argc个参数的具体数据。注意数组起始索引为0开始,到argc-1结束。即:argv[0]为命令行中可执行程序名本身,argv[1]为命令行中第二个参数的内容,依次类推。
配置:
(1)在VS中设置时右键项目->属性->调试->命令参数,在命令参数中添加所需参数,字符串之间用空格分开即可。如果是.txt文件,要放在当前目录下(.cpp所在目录)【实质为exe生成目录位置】,不然找不到。
(2)或者:假如你的程序是hello.exe,如果在命令行运行该程序,(首先应该在命令行下用 cd 命令进入到 hello.exe 文件所在目录) 运行命令为hello.exe data.txt
argv数组中的第一个单元指向的字符串总是可执行程序的名字,以后的单元指向的字符串依次是程序调用时的参数。
67.内存池和线程池
68.c和c++引用的区别
在C语言中,没有引用的概念。变量之间的传递通常是通过指针来实现的。指针是一个存储内存地址的变量,通过操作指针可以间接地操作存储在该内存地址上的值。在函数参数传递时,可以使用指针来传递参数,从而实现对原始变量的修改。
而在C++语言中,引用是一种特殊的变量类型,它相当于给已存在的变量起了一个别名。可以将引用看作是已存在变量的另一个名称,对引用的操作实际上就是对原始变量的操作。在函数参数传递时,可以使用引用作为参数,从而直接修改原始变量的值。
引用相较于指针更加安全和方便,因为引用需要明确绑定到一个已存在的对象上,并且无法修改其绑定对象。而指针可以为空或者指向无效内存地址,还可以通过指针操作来改变指针所指向的对象。
另外需要注意的是,在C语言中调用C++函数时,如果函数参数中有引用类型,需要将其改写为指针类型进行传递。因为C语言不支持引用类型。
69.varint编码是什么
Varint是一种使用一个或多个字节序列化整数的方法,会把整数编码为变长字节。
对于32位整型数据经过Varint编码后需要1~5个字节,小的数字使用1个byte,大的数字使用5个bytes。
64位整型数据编码后占用1~10个字节。在实际场景中小数字的使用率远远多于大数字,因此通过Varint编码对于大部分场景都可以起到很好的压缩效果。
70.LoadLibrary加载Dll失败GetLastError错误码为126
它们都是因为“找不到”而出现加载错误,但是错误码2是找不到指定的“文件”,错误码126是找不到指定的“模块”。,加载有依赖的DLL时要注意依赖DLL的位置
71.空指针可以取地址?
空指针是说指针存的值为NULL,但这个本身所处位置是有个地址的,所以能取地址
所以看到的值是指向的值,而不是其本身值。
72.类的成员函数作为回调函数 显示参数不匹配
可能是因为类的成员函数有一个隐含的额外参数——指向类实例的指针(通常称为 this 指针)。