前言:最近发现很多面试题都会问到c++和c的不同;总结一下,发现遗漏的知识点还是挺多的;比如c语言中,const关键字是个冒牌货;c++中struct和class异同;学校网络不好,Firefox浏览器卡出去好几次,还有一次写了一个小时给我吞了;心态有点奔溃;
目录
C是C++的子集,c++编译器可以兼容绝大部分c程序;
设计思想上:C++是面向对象的语言,而C是面向过程的结构化编程语言
语法上:
C++具有封装、继承和多态三种特性
C++相比C,增加多许多类型安全的功能,比如强制类型转换、
C++支持范式编程,比如模板类、函数模板等。
C++更侧重于类的设计。
工作上:C适合要求代码体积小的,效率高的场合,如嵌入式;而C++适合更上层的,复杂的场景,如服务器开发;
优点:
(1)可读性强,语法灵活,数据结构丰富 ,编译效率高。
(2)直接访问物理地址,对硬件进行操作。
(3)出色的可移植性,在多种不同体系结构的软/硬件平台上运行。
缺点:
(1) 主要是数据的封装性 ,这一点使得C在数据的安全性上有很大缺陷,这也是C和C++的一大区别。
(2) C语言的语法限制不太严格,对变量的类型约束不严格,对数组下标越界不作检查,尤其是C语言对指针的使用。影响程序的安全性,
(3) C语言的简洁性与其丰富的运算符相结合,使其可能会编写出极难理解的代码。
1)封装:将客观事物封装成抽象的类,并且设计者可以对类的成员进行访问控制权限控制.
1:可以做到数据的隐藏,保护数据安全;
2:封装可以修改类的内部,实现而不用修改调用了该类的用户的代码.同时封装还有利于代码的方便复用;
2)继承:
a.继承具有这样一种功能,它可以使用现有类的所有功能;并且可以在不重新编写原有类的情况下对类的功能进行扩展.继承的过程是一般到特殊的过程,即是它们是is-a的关系;基类或父类是一般,而子类或派生类是基类的特殊表现;要实现继承可以通过继承和组合来实现;
b.广义上的继承分成三大类:
1.实现继承:使用基类的属性和方法而无需额外编码的能力;
2.接口继承:接口继承是指仅使用基类的属性和方法的名称,而具体的实现子类必须自己完成的能力;
3.可视继承:子窗体(类)使用父窗体(类)的外观和实现代码的能力;
3)多态:
a.多态的实现分成两种,
1:编译时的多态,主要是通过函数重载和运算符重载来实现的,是通过静态联编实现的;
2:是运行时多态,主要是通过函数覆盖来实现的,它需要满足3个条件:基类函数必须是虚函数,并且基类的指针或引用指向子类的时候,当子类中对原有的虚函数进行重新定义之后形成一个更加严格的重载版本的时候,就会形成 多态;它是通过动态联编实现的;
b.运行时的多态可以让基类的指针或引用指向不同的对象的时候表现出来不同的特性;
c++标准库:是不带.h。而是写#include<vector>
新版的c:不带有.h,例如#include <cstdio>;旧版的c:带有".h";
<>和""的区别:
<>:直接从编译器指定的路径处搜索;
"":首先从程序当前的目录搜索,然后从编译器指定的路径搜索;
c99以前一共有32个关键字;其中中数据类型关键字(12个)控制语句关键字(12个)存储类型关键字(4个)其他关键字(4个);
break | case | char | const | continue | do | ||
double | else | enum | extern | for | goto | if | |
int | long | register | return | short | signed | sizeof | static |
struct | switch | typedef | union | unsigned | volatile |
1999年,ISO推出了C99标准,该标准新增了5个C语言关键字:
inline | restrict | _Bool | _Complex | _Imaginary |
2011年,ISO发布C语言的新标准C11,该标准新增了7个C语言关键字:
_Alignas | _Alignof | _Atomic | _Static_assert | _Noreturn | _Thread_local | _Generic |
C++:
ISO C++98/03关键字共63个: 其中红色标注为C语言中的32个关键字。C++11中有73个关键字,新增加的10个为:alignas、alignof、char16_t、char32_t、constexpr、decltype、noexpect、nullptr、static_assert、thread_local;
其中:
export 因为实现支持太少,编译效率低下,取消原有意义(仍是关键字,但使用它的程序是错误的),改为保留给未来标准使用。
以下为关键字的解释,忘了的赶快看:
(1) char:声明字符型变量或函数
(2) double:声明双精度变量或函数
(3) enum:声明美剧类型
(4) float:声明浮点型变量或函数
(5) int:声明整型变量或函数
(6) long:声明长整型变量或函数
(7) short:声明短整型变量或函数
(8) signed:声明有符号类型变量或函数
(9) struct:声明结构体变量或函数
(10) union:声明联合数据类型
(11) unsigned:声明无符号类型变量或函数
(12) void:声明函数无返回值或无参数,声明无类型指针
控制语句关键字(12个)
循环语句
(1) for:一种循环语
(2) do:循环语句的循环体
(3) while:循环语句的循环条件
(4) break:跳出当前循环
(5) continue:结束当前循环,开始下一轮循环
条件语句
(1) if:条件语句
(2) else:条件语句否定分支
(3) goto:无条件跳转语句
开关语句
(1) switch:用于开关语句
(2) case:开关语句分支
(3) default:开关语句中的“其他”分支
返回语句
(1)return:子程序返回语句
存储类型关键字(4个)
(1) auto:声明自动变量 一般不使用
(2) extern:声明变量是在其他文件正声明(也可以看做是引用变量)
(3) register:声明寄存器变量
(4) static:声明静态变量
其他关键字(4个)
(1) const:声明只读变量
(2) sizeof:计算数据类型长度
(3) typedef:用于给数据类型取别名
(4) volatile:说明变量在程序执行中可被隐含的改变
1、asm
_asm是一个语句的分隔符。不能单独出现,必须接汇编指令。一组被大括号包含的指令或一对空括号。
例:
_asm
{
mov al,2
mov dx,0xD007
out al,dx
}
也可以在每个汇编指令前加_asm
_asm mov al,2
_asm mov dx,0xD007
_asm out al,dx
2、auto
auto关键字会根据初始值自动推断变量的数据类型。不是每个编译器都支持auto。
例:
auto x = 7; //使用整数7对变量x进行初始化,可推断x为int型。
auto y=1.234; //使用浮点数1.234对变量y进行初始化,可推断y为double型。
3、*_cast
即 const_cast、dynamic_cast、reinterpret_cast、static_cast。
C++类型风格来性转换。const_cast删除const变量的属性,方便赋值;dynamic_cast用于将一个父类对象的指针转换为子类对象的指针或引用;reinterpret_cast将一种类型转换为另一种不同的类型;static_cast用于静态转换,任何转换都可以用它,但他不能用于两个不相关的类型转换。
4、bool、true、false
bool即为布尔类型,属于基本类型中的整数类型,取值为真和假。true和false是具有布尔类型的字面量,为右值,即表示真和假。
注:字面量:用于表达源代码中一个固定值的表示法。
5、break、cotinue、goto
break用于跳出for、while循环或switch语句。continue用于调到一个循环的起始位置。goto用于无条件跳转到函数内得标号处。一般情况不建议使用goto,风险较大。
6、switch、case、default
switch分支语句的起始,根据switch条件跳转到case标号或defalut标记的分支上。
7、catch、throw、try
用于异常处理。try指定try块的起始,try块后的catch可以捕获异常。异常由throw抛出。throw在函数中还表示动态异常规范。
8、char、wchar_t
表示字符型和宽字符型这些整数类型(属于基本类型),但一般只专用于表示字符。char(和signed char、unsigned char一起)事实上定义了字节的大小。char表示单字节字符,wchar_t表示多字节字符。
9、const、volatile
const和volatile是类型修饰符,语法类似,用于变量或函数参数声明,也可以限制非静态成员函数。const表示只读类型(指定类型安全性,保护对象不被意外修改),volatile指定被修饰的对象类型的读操作是副作用(因此读取不能被随便优化合并,适合映射I/O寄存器等)。
volatile:
a、当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中,以后再取变量值时,就直接从寄存器中取值。
b、优化器在用到volatile变量时必须每次都小心地重新读取这个变量的值,而不是使用保存到寄存器里的备份。
c、volatile适用于多线程应用中被几个任务共享的变量。
10、struct、class、union
用于类型声明。class是一般的类类型。struct在C++中是特殊的类类型,声明中仅默认隐式的成员和基类访问限定与class不同(struct是public,class是private)。union是联合体类型。满足特定条件类类型——POD struct或POD union可以和C语言中的struct和union对应兼容。
注:POD类型(Plain Old Data),plain---代表普通类型,old---代表可以与C语言兼容。
11、new、delete
new、delete属于操作符,可以被重载。new表示向内存申请一段新的空间,申请失败会抛出异常。new会先调用operator new函数,再在operator new函数里调用malloc函数分配空间,然后再调构造函数。delete不仅会清理资源,还会释放空间。delete县调用析构函数,其次调用operator delete函数,最后在operator delete函数里面调用free函数。malloc申请内存失败会返回空。free只是清理了资源,并没有释放空间。
12、do、for、while
循环语句的组成部分,C和C++都支持这3种循环。
13、数值类型,如 int、double、float、short、long、signed、unsigned
signed和unsigned作为前缀修饰整数类型,分别表示有符号和无符号。signed和unsigned修饰char类型,构成unsigned char和signed char,和char都不是相同的类型;不可修饰wchar_t、char16_t和char32_t。其它整数类型的signed省略或不省略,含义不变。signed或unsigned可单独作为类型,相当于signed int和unsigned int。
double和float专用于浮点数,double表示双精度,精度不小于float表示的浮点数。long double则是C++11指定的精度不小于double的浮点数。
14、if和else
条件语句的组成部分。if表示条件,之后else表示否定分支。
15、enum
构成枚举类型名的关键字。
16、explicit
该关键字的作用就是避免自定义类型隐式转换为类类型。
17、export
使用该关键字可实现模板函数的外部调用。对模板类型,可以在头文件中声明模板类和模板函数;在代码文件中,使用关键字export来定义具体的模板类对象和模板函数;然后在其他用户代码文件中,包含声明头文件后,就可以使用该这些对象和函数。
18、extern
当出现extern “C”时,表示 extern “C”之后的代码按照C语言的规则去编译;当extern修饰变量或函数时,表示其具有外部链接属性,即其既可以在本模块中使用也可以在其他模块中使用。
19、friend
友元。使其不受访问权限控制的限制。例如,在1个类中,私有变量外部是不能直接访问的。可是假如另外1个类或函数要访问本类的1个私有变量时,可以把这个函数或类声明为本类的友元函数或友元类。这样他们就可以直接访问本类的私有变量。
20、inline
内联函数,在编译时将所调用的函数代码直接嵌入到主调函数中。各个编译器的实现方式可能不同。
21、mutable
mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。
22、namespace
C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。命名空间除了系统定义的名字空间之外,还可以自己定义,定义命名空间用关键字“namespace”,使用命名空间时用符号“::”指定。
23、operator
和操作符连用,指定一个重载了的操作符函数,比如,operator+。
24、public、protected、private
这三个都为权限修饰符。public为公有的,访问不受限制;protected为保护的,只能在本类和友元中访问;private为私有的,只能在本类、派生类和友元中访问。
25、register
提示编译器尽可能把变量存入到CPU内部寄存器中。
26、return
return表示从被调函数返回到主调函数继续执行,返回时可附带一个返回值,由return后面的参数指定。return通常是必要的,因为函数调用的时候计算结果通常是通过返回值带出的。如果函数执行不需要返回计算结果,也经常需要返回一个状态码来表示函数执行的顺利与否(-1和0就是最常用的状态码),主调函数可以通过返回值判断被调函数的执行情况.
27、static
可修饰变量(静态全局变量,静态局部变量),也可以修饰函数和类中的成员函数。static修饰的变量的周期为整个函数的生命周期。具有静态生存期的变量,只在函数第一次调用时进行初始化,在没有显示初始化的情况下,系统把他们初始化微0.
28、sizeof
返回类型名或表达式具有的类型对应的大小。
29、template
声明一个模板,模板函数,模板类等。模板的特化。
30、this
每个类成员函数都隐含了一个this指针,用来指向类本身。this指针一般可以省略。但在赋值运算符重载的时候要显示使用。静态成员函数没有this指针。
31、typedef
typedef声明,为现有数据类型创建一个新的名字。便于程序的阅读和编写。
32、virtual
声明虚基类,虚函数。虚函数=0时,则为纯虚函数,纯虚函数所在的类称为抽象类。
33、typeid
typeid是一个操作符,返回结果为标准库种类型的引用。
34、typename
typename关键字告诉编译器把一个特殊的名字解释为一个类型。
35、using
(1)、在当前文件引入命名空间,例using namespace std;
(2)、在子类中使用,using声明引入基类成员名称。
36、void
特殊的"空"类型,指定函数无返回值或无参数。
1alignas
alignof用于获取取指定表达式指定的(类似sizeof,可以直接是类型名)的对齐(alignment)。alignas用于声明时指定对齐类似于现有的类型。和sizeof类似,两者的操作数都不被求值。
2constexpr
类似const但更强大,修饰函数或对象,表示函数结果或对象是编译时决定的常量,以便优化。(const不能修饰一般的函数,也不一定指定声明的对象能编译期的常量表达式,更可能只是只读对象。而在C语言中,const完全只能指定只读对象。)
3char16_t 和 char32_t
二者分别表示16位字符型和32位字符型,类似char和wchar_t,也是一般只专用于表示字符的整数类型,char16_t和char32_t是C++11新增的,以克服wchar_t在不同平台上无法保证确定宽度的缺点。
用于编译时推断类型。此外参与函数声明的另一种语法:指定返回auto,同时decltype引导trailing-return-type指定实际应该返回类型。decltype的操作数也不被求值。
字面量nullptr是具有std::nullptr_t类型的右值,是空指针常量。C++98/03中表示空指针常量的NULL或0都会在重载中引起混淆,而纯库的解决方案在这里也遇到困难,所以有必要加入新的关键字来专门表示空指针。
7noexcept
实践表明动态异常规范会影响运行时性能。新增的noexcept表示静态异常规范,只指定函数(模版)是否有异常抛出,这里noexcept即noexcept(true),表示没有异常抛出。除了异常规范,noexcept可以作用于一个表达式来判断是否有异常,这对于模版代码非常有用。
用于编译时的静态断言:若指定的表达式为false则编译失败。
10static_assert、thread_local。
auto
C++11标准和C++98/03标准的auto是不同的。C++98/03标准中,auto表示自动储存类型 ;C++11标准中,auto表示由编译器静态判断其应有的类型
register优化c语言代码的变量;
register int a;
printf("&a=%d",&a);c语言不通过,c语言register不能访问地址
printf("&a=%d",&a);c++通过;c++编译器对register优化;
1const语法:
唯一难点:const修饰的指针,还是指针所指的内存空间;
const做参数时用法一样;
2.c语言中,const是冒牌货
c++中,const是真正的常量;
const int a=1;
int *p=(int *)&a;
*p=10000;
printf("a=%d ,*p=%d",a,*p);
结果:
c:a=10000 ,*p=10000;
c++中,a=1,*p=10000;
原因:c++扫描const时,编译器分配内存,变量a有个对应表,对应的1不会发生改变,而指针*p变化为10000;
3const和#define区别:
相同:
c++中const常量类似于宏定义:
不同:
const常量是又编译器处理,提供类型检查和作用;
宏定义是由处理器处理,单纯的文本替换;
C语言中的struct与C++中的struct的区别表现在以下3个方面:
(1) C语言的struct不能有函数成员,而C++的struct可以有。
(2) C语言的struct中数据成员没有private、public和protected访问权限的设定,而C++ 的struct的成员有访问权限设定。
(3) C语言的struct是没有继承关系的,而C++的struct却有丰富的继承关系。
c语言中struct和union的区别:
struct (结构体)与union (联合体)是C语言中两种不同的数据结构,两者都是常见的复合结构,其区别主要表现在以下两个方面:
(1) 不同:联合体中所有成员共用一块地址空间,即联合体只存放了一个被选中的成员;而结构体中所有成员占用空间是累加的,其所有成员都存在,不同成员会存放在不同的地址。
(2) 因此联合体的不同成员赋值,将会对它的其他成员重写,原来成员的值就不存在了; 而对结构体的不同成员赋值是互不影响的。
(3)而在c语言中枚举本质就是整型,枚举变量可以用任意的整型复制;
而c++中枚举变量,只能用被枚举出来的的元素初始化;
而c++中,class和struct的区别:
具体而言,在C++中,class和struct做类型定义时只有两点区别:
(1) 默认继承权限不同。class继承默认是private继承,而struct继承默认是public继承;
(2) class还用于定义模板参数,就像typename,但关键字struct不用于定义模板参数。
2.8增强
int a=10,b=20;
c语言:(a<b?a:b)=30;结果:错误;
c++中:(a<b?a:b)=30;结果: a=30;
原因:
1.c语言返回变量的值,c++返回变量的本身;
c语言的三目运算符是表达式,结果是一个数,放在寄存器,不能做左值;
c++的三目运算符是返回一个内存空间,表达式返回的是:变量的本身;
2注意三目运算符返回值,如果 有一个常量则不能作为左值使用;
如: (a<b?1:b)=30;
3那么c语言如何实现左值的赋值:
当左值的条件,需要内存空间,c++编译器帮助我们取了一个地址而已;
*( a<b ?&a : &b)=30;
4 三元表达式“?:”问号后面的两个操作数必须为同一类型
(true?1:"1") 错误;
1.引用是一个别名:
int a;
int& b=a;
我们可以认为是一个人,有一个真名,一个外号,以后不管是喊他a还是b,都是叫他这个人。
2.引用的初始化
和指针不同,引用变量的值不可改变。引用作为真实对象的别名,必须进行初始化,除非满足下列条件之一:
(1) 引用变量被声明为外部的,它可以在任何地方初始化
(2) 引用变量作为类的成员,在构造函数里对它进行初始化
(3) 引用变量作为函数声明的形参,在函数调用时,用调用者的实参来进行初始化
3.作为函数形参的引用
引用常常被用作函数的形参。以引用代替拷贝作为形参的优点:
引用避免了传递大型数据结构带来的额外开销
引用无须象指针那样需要使用*和->等运算符
4.以引用方式调用
当函数把引用作为参数传递给另一个函数时,被调用函数将直接对参数在调用者中的拷贝进行操作,而不是产生一个局部的拷贝(传递变量本身是这样的)。这就称为以引用方式调用。把参数的值传递到被调用函数内部的拷贝中则称为以传值方式调用。
5.以引用作为返回值
6.引用和指针的区别:
1.指针有自己的一块空间,而引用只是一个别名;
2.使用sizeof看一个指针的大小是4,而引用则是被引用对象的大小;
3.指针可以被初始化为NULL,而引用必须被初始化且必须是一个已有对象 的引用;
4.作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接对引 用的修改都会改变引用所指向的对象;
5.可以有const指针,但是没有const引用;
6.指针在使用中可以指向其它对象,但是引用只能是一个对象的引用,不能 被改变;
7.指针可以有多级指针(**p),而引用至于一级;
8.指针和引用使用++运算符的意义不一样;
9.如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄露。
C++语言中,允许变量定义语句在程序中的任何地方,只要在是使用它之前就可以;而C语言中,必须要在函数开头部分(c11已经修改,同c++);
而且C++允许重复定义变量,C语言也是做不到这一点的。
请看下面的程序:( for循环中定义int i,在除vc6.0以外的编译器被允许)
c语言中:fun (){return 10;}; foo(i){return i;};可以通过;但其实时非常危险的做法!
c++中:函数返回值类型和参数,必须有参数;
使用强制类型转换的最大好处就是:禁止编译器对你故意去做的事发出警告。但是,利用强制类型转换说明使得编译器的类型检查机制失效,这不是明智的选择。通常,是不提倡进行强制类型转换的。除非不可避免,如要调用malloc()函数时要用的void型指针转换成指定类型指针。
C++中四种类型转换是:static_cast, dynamic_cast, const_cast, reinterpret_cast
1、const_cast
用于将const变量转为非const
2、static_cast
用于各种隐式转换,比如非const转const,void*转指针等, static_cast能用于多态向上转化,如果向下转能成功但是不安全,结果未知;
3、dynamic_cast
用于动态类型转换。只能用于含有虚函数的类,用于类层次间的向上和向下转化。只能转指针或引用。向下转化时,如果是非法的对于指针返回NULL,对于引用抛异常。要深入了解内部转换的原理。
向上转换:指的是子类向基类的转换
向下转换:指的是基类向子类的转换
它通过判断在执行到该语句的时候变量的运行时类型和要转换的类型是否相同来判断是否能够进行向下转换。
4、reinterpret_cast
几乎什么都可以转,比如将int转指针,可能会出问题,尽量少用;
5、为什么不使用C的强制转换?
C的强制转换表面上看起来功能强大什么都能转,但是转化不够明确,不能进行错误检查,容易出错。
6 C++是不是类型安全的?
不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。
英文意思:char 是字符, string 是字符串。
C中:只有 char 关键字,没有 string类。字符和字符串都要声明为char型。声明为 char型的量按 ASCII 值存放,处理为整数。因此定义字符串时,都是字符数组,或者是指针字符。可用strcpy,strcat,strlen 之类的函数对它加工处理。
C++中:char 是关键字 ,string 是 class(类),不是关键字,用的时候,需要调用<string>;
在C++中,允许有相同的函数名,不过它们的参数类型不能完全相同,这样这些函数就可以相互区别开来。而这在C语言中是不允许的。
1、参数个数不同
2.参数格式不同
1、无名的函数形参
声明函数时可以包含一个或多个用不到的形式参数。这种情况多出现在用一个通用的函数指针调用多个函数的场合,其中有些函数不需要函数指针声明中的所有参数。看下面的例子:
尽管这样的用法是正确的,但大多数C和C++的编译器都会给出一个警告,说参数y在程序中没有被用到。为了避免这样的警告,C++允许声明一个无名形参,以告诉编译器存在该参数,且调用者需要为其传递一个实际参数,但是函数不会用到这个参数。下面给出使用了无名参数的C++函数代码:
2、函数的默认参数
C++函数的原型中可以声明一个或多个带有默认值的参数。如果调用函数时,省略了相应的实际参数,那么编译器就会把默认值作为实际参数。可以这样来声明具有默认参数的C++函数原型:
上面例子中,第一次调用show()函数时,让编译器自动提供函数原型中指定的所有默认参数,第二次调用提供了第一个参数,而让编译器提供剩下的两个,第三次调用则提供了前面两个参数,编译器只需提供最后一个,最后一个调用则给出了所有三个参数,没有用到默认参数。
在C语言中,输入输出是使用语句scanf()和printf()来实现的,而C++中是使用类来实现的。
cin,cout,endl对象,他们本身并不是C++语言的组成部分。虽然他们已经是ANSI标准C++中被定义,但是他们不是语言的内在组成部分。在C++中不提供内在的输入输出运算符,这与其他语言是不同的。输入和输出是通过C++类来实现的,cin和cout是这些类的实例,他们是在C++语言的外部实现。
在C++语言中,有了一种新的注释方法,就是‘//’,在该行//后的所有说明都被编译器认为是注释,这种注释不能换行。C++中仍然保留了传统C语言的注释风格/*……*/。
C++也可采用格式化输出的方法:
从上面也可以看出,dec,oct,hex也不可作为变量的标识符在程序中出现。
异常处理:C++中的try/catch/throw异常处理机制取代了标准C中的setjmp()和longjmp()函数。
1)一般一个c/c++程序编译的时候内存布局如下(地址从低到高的顺序)
a.代码区:存放程序的二进制代码.
b.常量区:这个区和代码区的距离很近,主要存放一些非局部常量值和字符串字面值,一般不允许修改,程序结束由系统释放;
具有常属性并且初始化的全局和静态变量也放在这个区.
c.数据区:赋过初值的且不具有常属性的静态和全局变量在数据区.它和BSS段统称为静态区;程序结束后由系统释放;
d.BSS段:没有初始化的静态和全局变量;进程一旦被加载这个区所有的数据都被清0;
e.堆区: 动态分配的内存;由程序员分配和释放,程序结束的时候如果没有释放,则由OS回收;
f.栈区: 由编译器自动分配和释放,不使用的时候会自动的释放.主要用来存放非静态的局部变量,函数的参数和返回值,
临时变量等.
g.命令行参数和环境变量区;
下面是对应一段经典的代码:
结果:
a.从静态存储区域分配:
内存在程序编译时已经分配好,这块内存在程序的整个运行期间都存在.
速度快,不容易出错.因为由系统会善后.
b.在栈上分配内存:
在执行函数的时候,函数内非静态局部变量的存储单元都是在栈上创建,函数执行
结束的时候这些存储单元自动被释放.栈内存分配内置于处理器的指令集中,效率
很高但是分配的内容有限.
c.从堆中分配内存:
即是动态分配内存.程序在运行的时候使用malloc/new申请任意大小的内存,程序员
自己负责在何时用free/delete释放内存.动态内存的生存期由程序员决定,使用非常的
灵活.如果在堆上分配了内存,就有责任去回收它,否则运行程序会出现内存泄漏,另外
频繁的分配和释放不同大小的堆空间将会产生堆内碎片.不易管理;
a.管理方式不同:栈是由编译器自动分配和释放,使用方便;而对于堆来说,
分配和释放都必须由程序员来手动完成,不易管理,容易
造成内存泄漏和内存碎片.
b.可用内存空间不同:对于栈来说,它可用的内存空间比较小;而对于堆来说它可以使用的空间比栈要大的多.
c.能否产生碎片不同:由于栈采用的是后进先出的机制,所以栈空间没有内存碎片的产生;
而对于堆来说,由于频繁的使用new/delete势必会造成内存空间分配的不连续,从而
造成大量的碎片,使程序的效率降低.
d.生长方向不同: 对于堆来说,它一般是向上的;即是向着地址增加的方向增长;对于栈来说,它一般是向下的,
即向着地址减小的方向增长.
e.分配的方式不同:对于堆来说,它只能是动态分配的;而对于栈来说,它分为静态分配和动态分配;
静态分配由编译器来进行管理,而动态分配的栈和堆也是不一样的,动态分配的
栈由编译器进行释放,无需我们程序员来释放.
f.分配的效率不同:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:为栈分配专门的寄存器.
压栈和出栈都由专门的指令进行.因此它的效率会很高;
而堆则是由c/c++库函数实现的,机制是非常的负责的;例如要分配一块内存的时候,库
函数会利用特定的算法在堆内存中搜索可用大小的内存空间;如果没有足够大的内存
空间,就会调用系统功能去增加数据段的内存空间.这样才能得到足够大的可用的内存
空间,因此堆内存的分配的效率比栈要低得多.
a.new/delete是运算符,只能在C++中使用,它可以重载;mallloc/free是C的标准库函数,在C/C++中都可以使用.
b.对于非内部的数据类型的对象而言,光用malloc/free是无法满足动态对象的要求的.对象在创建的时候需要
执行构造函数,对象在消亡之前需要执行析构函数.而molloc/free是库函数而不是运算符,不在编译器的控制
范围之内,编译器不能将执行构造函数和析构函数的任务强加给malloc/free.因此C++需要一个能够完成动态
分配内存和初始化的new,以及一个能够完成清理和释放内存的运算符delete.
c.new的返回值是指定类型的指针,可以自动的计算所需要分配的内存大小.而malloc的返回值是一个void类型
的指针,我们在使用的时候要进行强制类型转换,并且分配的大小也要程序员手动的计算.
d.new/delete完全覆盖了malloc/free的功能,只所以还要保留malloc/free,是因为我们的C++程序有时要调用用C编写的
而C中又没有new/delete,只能使用malloc/free.
参考的博客有:
1.https://www.cnblogs.com/ITziyuan/p/9487760.html
2.https://www.cnblogs.com/yasanlun/p/3838531.html
整理不易, 加油!
这章我们将研究Struts的验证框架。Struts的核心中的验证框架,可在执行action方法之前,帮助应用程序运行规则执行验证。客户端验证通常使用Javascript实现,但是不能仅仅依赖于客户端验证。实践表明,应该在应用程序框架的所有级别引入验证。接下来让我们看一下给Struts项目添加验证的两种方法。我们举一个Employee的例子,employee的名字和年龄将使用一个简单的页面捕获,我们...
一自动化软件测试不是银弹计算机科学巨匠Fred Brooks,在1986年发表了他的著名论文《No Silver Bullet: Essence and Accidents of Software Engineering》。文章列举了人们对于软件工程技术发展的一些期望,并与现实进行了对比。其论点归纳如下:没有一种单纯的技术或管理上的进步,能够独立地承诺在10年内大幅度地提高软件的生产率、可靠性和简
二叉树图解网址:Visualgo-二叉树这里是二叉树的图示:
Java连接 MySQL 需要驱动包,最新版下载地址为:http://dev.mysql.com/downloads/connector/j/,解压后得到jar库文件,然后在对应的项目中导入该库文件。 IDEA导入jar过程:新建文件夹(名称任意,这里使用Lib),导入mysql-connector-java-*.*.**-bin.jar如下图右键点击jar文件,然后点击Add as Li...
python ConfigParser模块讲解功能介绍在程序中使用配置文件来灵活的配置一些参数是一件很常见的事情,在官方发布的库中就有一个库就是专门做这件事情的。那就是:ConfigParser。该模块的作用 就是使用模块中的RawConfigParser()、ConfigParser()、 SafeConfigParser()这三个方法(三者择其一),创建一个对象使用对象的方法对指定的配置文件做增删改查 操作。ConfigParser 是用来读取配置文件的包。配置文件的格式如下:中括号“[ ]”内
报错信息: File "/。。。7/site-packages/sklearn/metrics/classification.py", line 1059, in f1_score sample_weight=sample_weight) File "/。。。/site-packages/sklearn/metrics/classification.py", line 1182, in fbeta_score sample_weight=sample_weight) File ...
概述 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写
有一天,你到水果店去买橙子,当然要挑选最甜、最熟的。你是根据橙子的重量来付钱的,而不是根据橙子的甜度或者成熟度,虽然水果店有时候会把好的橙子挑出一堆单独涨价,但是这里没这么做。你妈妈曾经告诉你,橙子要挑深橙色的,颜色有点发红的,这样的橙子最甜,不要挑那些浅黄色甚至发青的,那些还没熟透。这样你就有了一点经验,虽然这点经验是别人直接教给你的,但你也可以在...
推荐一个好用的免费开源的笔记本软件CherryTree 我是一个好奇心很强的人,对未知的事物总有一种想要追根究底的冲动。多年以来,我学了很多东西,也学的很杂,积累了很多领域的知识。但不得不承认,人的记忆力很有限,学的越多忘的就越多。很久以前我就在想,怎么样把自己学过的知识有效的组织并储存起来,在忘记的时候可以快速地检索出来。我也曾考虑过自己去开发这样一个软件,只是一直没有时间(也许是...
hive注释中文乱码use hive;alter table COLUMNS_V2 modify column COMMENT varchar(256) character set utf8;alter table TABLE_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8;alter table P...
使用Eclipse调试J2ME程序 Eclipse是开发J2ME程序时使用的主要的开发工具之一,而调试程序的能力也是一个程序员必须具备的能力。本文假设Eclipse和EclipseMe已经安装,下面系统介绍一下调试的相关内容: 1、 环境设置 在安装好Eclipse和EclipseMe以后,如果需要调试J2ME程序,还需要设置以后才可以使用。设置方法如下: 打开“Window”-&gt...
运行错误:RuntimeError: An attempt has been made to start a new process before the current process has finished its bootstrapping phase. This probably means that you are not usin...