做网站销售东西 需要什么资质,如何制作app软件编程,android开发 wordpress,网站建设流程讯息最近会放出cpp成神之路的所有总结#xff0c;大家感兴趣的可以收藏一波。 历史文章#xff1a;
超硬核#xff01;十万字c题#xff0c;让你秒杀老师和面试官 位运算
若一个数m满足 m 2^n;那么k%mk(m-1)
为什么内存对齐
平台原因(移植原因)不是所有的硬件平台都能… 最近会放出cpp成神之路的所有总结大家感兴趣的可以收藏一波。 历史文章
超硬核十万字c题让你秒杀老师和面试官 位运算
若一个数m满足 m 2^n;那么k%mk(m-1)
为什么内存对齐
平台原因(移植原因)不是所有的硬件平台都能访问任意地址上的任意数据的某些硬件平台只能在某些地址处取某些特定类型的数据否则抛出硬件异
2、性能原因
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于为了访问未对齐的内存处理器需要作两次内存访问而对齐的内存访问仅需要一次访问。
函数调用过程栈的变化返回值和参数变量哪个先入栈
1、调用者函数把被调函数所需要的参数按照与被调函数的形参顺序相反的顺序压入栈中,即:从右向左依次把被调函数所需要的参数压入栈; 2、调用者函数使用call指令调用被调函数,并把call指令的下一条指令的地址当成返回地址压入栈中(这个压栈操作隐含在call指令中); 3、在被调函数中,被调函数会先保存调用者函数的栈底地址(push ebp),然后再保存调用者函数的栈顶地址,即:当前被调函数的栈底地址(mov ebp,esp); 4、在被调函数中,从ebp的位置处开始存放被调函数中的局部变量和临时变量,并且这些变量的地址按照定义时的顺序依次减小,即:这些变量的地址是按照栈的延伸方向排列的,先定义的变量先入栈,后定义的变量后入栈;
怎样判断两个浮点数是否相等
对两个浮点数判断大小和是否相等不能直接用来判断会出错明明相等的两个数比较反而是不相等对于两个浮点数比较只能通过相减并与预先设定的精度比较记得要取绝对值浮点数与0的比较也应该注意。与浮点数的表示方式有关。
宏定义一个取两个数中较大值的功能
#define MAXx,y((xy?)x:y)
define、const、typedef、inline使用方法
const与#define的区别
const定义的常量是变量带类型而#define定义的只是个常数不带类型define只在预处理阶段起作用简单的文本替换而const在编译、链接过程中起作用define只是简单的字符串替换没有类型检查。而const是有数据类型的是要进行判断的可以避免一些低级错误define预处理后占用代码段空间const占用数据段空间const不能重定义而define可以通过#undef取消某个符号的定义进行重定义define独特功能比如可以用来防止文件重复引用。
#define和别名typedef的区别
执行时间不同typedef在编译阶段有效typedef有类型检查的功能#define是宏定义发生在预处理阶段不进行类型检查功能差异typedef用来定义类型的别名定义与平台无关的数据类型与struct的结合使用等。#define不只是可以为类型取别名还可以定义常量、变量、编译开关等。作用域不同#define没有作用域的限制只要是之前预定义过的宏在以后的程序中都可以使用。而typedef有自己的作用域。
define与inline的区别
#define是关键字inline是函数宏定义在预处理阶段进行文本替换inline函数在编译阶段进行替换inline函数有类型检查相比宏定义比较安全
printf实现原理
在C/C中对函数参数的扫描是从后向前的。C/C的函数参数是通过压入堆栈的方式来给函数传参数的堆栈是一种先进后出的数据结构最先压入的参数最后出来在计算机的内存中数据有2块一块是堆一块是栈函数参数及局部变量在这里而栈是从内存的高地址向低地址生长的控制生长的就是堆栈指针了最先压入的参数是在最上面就是说在所有参数的最后面最后压入的参数在最下面结构上看起来是第一个所以最后压入的参数总是能够被函数找到因为它就在堆栈指针的上方。printf的第一个被找到的参数就是那个字符指针就是被双引号括起来的那一部分函数通过判断字符串里控制参数的个数来判断参数个数及数据类型通过这些就可算出数据需要的堆栈指针的偏移量了下面给出printf(%d,%d,a,b);其中a、b都是int型的的汇编代码.
#include 的顺序以及尖叫括号和双引号的区别
表示编译器只在系统默认目录或尖括号内的工作目录下搜索头文件并不去用户的工作目录下寻找所以一般尖括号用于包含标准库文件
表示编译器先在用户的工作目录下搜索头文件如果搜索不到则到系统默认目录下去寻找所以双引号一般用于包含用户自己编写的头文件。
lambda函数
利用lambda表达式可以编写内嵌的匿名函数用以替换独立函数或者函数对象每当你定义一个lambda表达式后编译器会自动生成一个匿名类这个类当然重载了()运算符我们称为闭包类型closure type。那么在运行时这个lambda表达式就会返回一个匿名的闭包实例其实一个右值。所以我们上面的lambda表达式的结果就是一个个闭包。闭包的一个强大之处是其可以通过传值或者引用的方式捕捉其封装作用域内的变量前面的方括号就是用来定义捕捉模式以及变量我们又将其称为lambda捕捉块。lambda表达式的语法定义如下[capture] parameters mutable -return-type {statement};lambda必须使用尾置返回来指定返回类型可以忽略参数列表和返回值但必须永远包含捕获列表和函数体
hello world 程序开始到打印到屏幕上的全过程?
1.用户告诉操作系统执行HelloWorld程序通过键盘输入等
2操作系统找到helloworld程序的相关信息检查其类型是否是可执行文件并通过程序首部信息确定代码和数据在可执行文件中的位置并计算出对应的磁盘块地址。
3操作系统创建一个新进程将HelloWorld可执行文件映射到该进程结构表示由该进程执行helloworld程序。
4操作系统为helloworld程序设置cpu上下文环境并跳到程序开始处。
5执行helloworld程序的第一条指令发生缺页异常
6操作系统分配一页物理内存并将代码从磁盘读入内存然后继续执行helloworld程序
7helloword程序执行puts函数系统调用在显示器上写一字符串
8操作系统找到要将字符串送往的显示设备通常设备是由一个进程控制的所以操作系统将要写的字符串送给该进程
9操作系统控制设备的进程告诉设备的窗口系统它要显示该字符串窗口系统确定这是一个合法的操作然后将字符串转换成像素将像素写入设备的存储映像区
10视频硬件将像素转换成显示器可接收和一组控制数据信号
11显示器解释信号激发液晶屏
12OK我们在屏幕上看到了HelloWorld
模板类和模板函数的区别是什么
函数模板的实例化是由编译程序在处理函数调用时自动完成的而类模板的实例化必须由程序员在程序中显式地指定。即函数模板允许隐式调用和显式调用而类模板只能显示调用。在使用时类模板必须加T而函数模板不必
为什么模板类一般都是放在一个h文件中
模板定义很特殊。由template…处理的任何东西都意味着编译器在当时不为它分配存储空间它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处有一机制能去掉指定模板的多重定义。所以为了容易使用几乎总是在头文件中放置全部的模板声明和定义。在分离式编译的环境下编译器编译某一个.cpp文件时并不知道另一个.cpp文件的存在也不会去查找当遇到未决符号时它会寄希望于连接器。这种模式在没有模板的情况下运行良好但遇到模板时就傻眼了因为模板仅在需要的时候才会实例化出来所以当编译器只看到模板的声明时它不能实例化该模板只能创建一个具有外部连接的符号并期待连接器能够将符号的地址决议出来。然而当实现该模板的.cpp文件中没有用到模板的实例时编译器懒得去实例化所以整个工程的.obj中就找不到一行模板实例的二进制代码于是连接器也黔驴技穷了。
C中类成员的访问权限和继承权限问题。
三种访问权限
public:用该关键字修饰的成员表示公有成员该成员不仅可以在类内可以被 访问在类外也是可以被访问的是类对外提供的可访问接口 private:用该关键字修饰的成员表示私有成员该成员仅在类内可以被访问在类体外是隐藏状态 protected:用该关键字修饰的成员表示保护成员保护成员在类体外同样是隐藏状态但是对于该类的派生类来说相当于公有成员在派生类中可以被访问。
三种继承方式
若继承方式是public基类成员在派生类中的访问权限保持不变也就是说基类中的成员访问权限在派生类中仍然保持原来的访问权限 若继承方式是private基类所有成员在派生类中的访问权限都会变为私有(private)权限若继承方式是protected基类的共有成员和保护成员在派生类中的访问权限都会变为保护(protected)权限私有成员在派生类中的访问权限仍然是私有(private)权限。
cout和printf有什么区别
cout是一个函数cout后可以跟不同的类型是因为cout已存在针对各种类型数据的重载所以会自动识别数据的类型。输出过程会首先将输出字符放入缓冲区然后输出到屏幕。
cout是有缓冲输出: cout abc endl; 或cout abc\n ;cout flush; 这两个才是一样的. endl相当于输出回车后再强迫缓冲输出。 flush立即强迫缓冲输出。 printf是无缓冲输出。有输出时立即输出
重载运算符
我们只能重载已有的运算符而无权发明新的运算符对于一个重载的运算符其优先级和结合律与内置类型一致才可以不能改变运算符操作数个数. sizeof typeid **不能重载两种重载方式成员运算符和非成员运算符成员运算符比非成员运算符少一个参数下标运算符、箭头运算符必须是成员运算符引入运算符重载是为了实现类的多态性当重载的运算符是成员函数时this绑定到左侧运算符对象。成员运算符函数的参数数量比运算符对象的数量少一个至少含有一个类类型的参数从参数的个数推断到底定义的是哪种运算符当运算符既是一元运算符又是二元运算符-*下标运算符必须是成员函数下标运算符通常以所访问元素的引用作为返回值同时最好定义下标运算符的常量版本和非常量版本箭头运算符必须是类的成员解引用通常也是类的成员重载的箭头运算符必须返回类的指针
函数重载函数匹配原则
名字查找确定候选函数寻找最佳匹配
定义和声明的区别
如果是指变量的声明和定义 从编译原理上来说声明是仅仅告诉编译器有个某类型的变量会被使用但是编译器并不会为它分配任何内存。而定义就是分配了内存。如果是指函数的声明和定义 声明一般在头文件里对编译器说这里我有一个函数叫function() 让编译器知道这个函数的存在。 定义一般在源文件里具体就是函数的实现过程 写明函数体。
C类型转换有四种
static_cast能进行基础类型之间的转换也是最常看到的类型转换。它主要有如下几种用法
1 . 用于类层次结构中父类和子类之间指针或引用的转换。进行上行转换把子类的指针或引用转换成父类表示是安全的
2 . 进行下行转换把父类指针或引用转换成子类指针或引用时由于没有动态类型检查所以是不安全的
3 . 用于基本数据类型之间的转换如把int转换成char把int转换成enum。这种转换的安全性也要开发人员来保证。
4 . 把void指针转换成目标类型的指针不安全
5 . 把任何类型的表达式转换成void类型。
const_cast运算符用来修改类型的const或volatile属性。除了去掉const 或volatile修饰之外 type_id和expression得到的类型是一样的。但需要特别注意的是const_cast不是用于去除变量的常量性而是去除指向常数对象的指针或引用的常量性其去除常量性的对象必须为指针或引用。reinterpret_cast它可以把一个指针转换成一个整数也可以把一个整数转换成一个指针先把一个指针转换成一个整数在把该整数转换成原类型的指针还可以得到原先的指针值。dynamic_cast 主要用在继承体系中的安全向下转型。它能安全地将指向基类的指针转型为指向子类的指针或引用并获知转型动作成功是否。转型失败会返回null转型对象为指针时或抛出异常bad_cast转型对象为引用时。 dynamic_cast 会动用运行时信息RTTI来进行类型安全检查因此 dynamic_cast 存在一定的效率损失。当使用dynamic_cast时该类型必须含有虚函数这是因为dynamic_cast使用了存储在VTABLE中的信息来判断实际的类型RTTI运行时类型识别用于判断类型。typeid表达式的形式是typeid(e)typeid操作的结果是一个常量对象的引用该对象的类型是type_info或type_info的派生。
全局变量和static变量的区别
1、全局变量外部变量的说明之前再冠以static就构成了静态的全局变量。全局变量本身就是静态存储方式静态全局变量当然也是静态存储方式。
这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序当一个源程序由多个原文件组成时非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域即只在定义该变量的源文件内有效在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域限于一个源文件内只能为该源文件内的函数公用因此可以避免在其他源文件中引起错误。static全局变量与普通的全局变量的区别是static全局变量只初始化一次防止在其他文件单元被引用。
2.static函数与普通函数有什么区别 static函数与普通的函数作用域不同。尽在本文件中。只在当前源文件中使用的函数应该说明为内部函数static内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数应该在一个头文件中说明要使用这些函数的源文件要包含这个头文件。 static函数与普通函数最主要区别是static函数在内存中只有一份普通静态函数在每个被调用中维持一份拷贝程序的局部变量存在于堆栈中全局变量存在于静态区中动态申请数据存在于堆
静态成员与普通成员的区别
生命周期
静态成员变量从类被加载开始到类被卸载一直存在
普通成员变量只有在类创建对象后才开始存在对象结束它的生命期结束
共享方式
静态成员变量是全类共享普通成员变量是每个对象单独享用的
定义位置
普通成员变量存储在栈或堆中而静态成员变量存储在静态全局区
初始化位置
普通成员变量在类中初始化静态成员变量在类外初始化
默认实参
可以使用静态成员变量作为默认实参 说一下理解 ifdef endif
一般情况下源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译也就是对一部分内容指定编译的条件这就是“条件编译”。有时希望当满足某条件时对一组语句进行编译而当条件不满足时则编译另一组语句。 条件编译命令最常见的形式为
#ifdef 标识符 程序段1 #else 程序段2 #endif
它的作用是当标识符已经被定义过(一般是用#define命令定义)则对程序段1进行编译否则编译程序段2。 其中#else部分也可以没有即 #ifdef 程序段1 #denif
在一个大的软件工程里面可能会有多个文件同时包含一个头文件当这些文件编译链接成一个可执行文件上时就会出现大量“重定义”错误。在头文件中使用#define、#ifndef、#ifdef、#endif能避免头文件重定义。
隐式转换如何消除隐式转换
C的基本类型中并非完全的对立部分数据类型之间是可以进行隐式转换的。所谓隐式转换是指不需要用户干预编译器私下进行的类型转换行为。很多时候用户可能都不知道进行了哪些转换 C面向对象的多态特性就是通过父类的类型实现对子类的封装。通过隐式转换你可以直接将一个子类的对象使用父类的类型进行返回。在比如数值和布尔类型的转换整数和浮点数的转换等。某些方面来说隐式转换给C程序开发者带来了不小的便捷。C是一门强类型语言类型的检查是非常严格的。基本数据类型 基本数据类型的转换以取值范围的作为转换基础保证精度不丢失。隐式转换发生在从小-大的转换中。比如从char转换为int。从int-long。自定义对象 子类对象可以隐式的转换为父类对象。C中提供了explicit关键字在构造函数声明的时候加上explicit关键字能够禁止隐式转换。如果构造函数只接受一个参数则它实际上定义了转换为此类类型的隐式转换机制。可以通过将构造函数声明为explicit加以制止隐式类型转换关键字explicit只对一个实参的构造函数有效需要多个实参的构造函数不能用于执行隐式转换所以无需将这些构造函数指定为explicit。