一、1byte = 8bit;1k = 1024byte;1M = 1024K;1G = 1024M;
二、
三、sizeof(struct)唯一原则就是按照计算机内存访问最快的方式对齐。各成员变量存放的 起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数;总的字节数一定是最大字节数的整数倍。
(1)数组名指代一种数据结构,这种数据结构就是数组;
例如:
1 2 |
|
输出结果为10,str指代数据结构char[10]。
(2)数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;
char str[10];
str++; //编译出错,提示str不是左值
(3)数组名作为函数形参时,沦为普通指针。
Windows NT 32位平台下,指针的长度(占用内存的大小)为4字节,故sizeof( str ) 、sizeof ( p ) 都为4。
(4)strlen():strlen计算字符串的长度,以' '为字符串结束标志,不包括
四、对象:面向对象是一种基于对象的、基于类的的软件开发思想。面向对象具有继承、封装、多态的特性。
五、static关键字:
1、隐藏:当同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。当然,加了static就具有了隐藏功能,只在该文件中可见。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏
2、static的第二个作用是保持变量内容的持久:共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。虽然这种用法不常见。如果作为static局部变量在函数内定义,它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。静态局部变量:通常,在函数体内定义一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会回收栈内存,局部变量也相应失效。但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了不再受函数的控制,给函数的维护带来不便。静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保存到下一次调用,直到下次赋新值。
3、static的第三个作用是默认初始化为0(static变量)
4、static的第四个作用:C++中的类成员声明static:static用在类中,被static修饰的变量属于类变量,对相于 public,protected,private 关键字的影响它和普通数据成员一样。sizeof 运算符不会计算静态成员变量,静态成员必须在类的外面初始化,静态数据成员初始化的格式如下:
<数据类型><类名>::<静态数据成员名>=<值> 如:int A::s = 0;在类声明之后
用静态数据成员时,采用如下格式 <类名>::<静态成员名>
在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。
静态变量啥时候初始化:C语言中其在代码执行之前初始化,属于编译期初始化。而C++中由于引入对象,对象生成必须调用构造函数,因此C++规定全局或局部静态对象当且仅当对象首次用到时进行构造
六、C++:构造函数和析构函数能否为虚函数?
简单回答是:构造函数不能为虚函数,而析构函数可以且常常是虚函数。
七、struct和union:结构体是将不同类型的数据组合成一个整体,是自定义类型。共同体(联合体)是不同类型的几个变量共同占用一段内存。
八、存储区域:在C++中,内存区分为5个区,分别是堆、栈、自由存储区、全局/静态变量存储区、常量存储区;在C中,C内存区分为堆、栈、全局/静态变量存储区、常量存储区;
九、malloc跟new:new的本质也是去调用malloc函数!!同理,delete的本质是去调用free()函数。1,申请内存所在位置:new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。那么自由存储区是否能够是堆(问题等价于new是否能在堆上动态分配内存),这取决于operator new 的实现细节。自由存储区不仅可以是堆,还可以是静态存储区(全局数据区),这都看operator new在哪里为对象分配内存。2、返回类型:new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。3、内存分配失败时的返回值:new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。
在使用C语言时,我们习惯在malloc分配内存后判断分配是否成功:
-
int *a = (int *)malloc ( sizeof (int ));
-
if(NULL == a)
-
{
-
...
-
}
-
else
-
{
-
...
-
}
使用new时判断是否申请内存成功:
-
try
-
{
-
int *a = new int();
-
}
-
catch (bad_alloc)
-
{
-
...
-
}
-
如果你想顺便了解下异常基础,可以看http://www.cnblogs.com/QG-whz/p/5136883.htmlC++ 异常机制分析。
4、是否需要指定内存大小 :使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。
-
class A{...}
-
A * ptr = new A;
-
A * ptr = (A *)malloc(sizeof(A)); //需要显式指定所需内存大小sizeof(A);
5、是否调用构造函数/析构函数:new/delete会调用对象的构造函数/析构函数以完成对象的构造/析构。而malloc则不会。6、对数组的处理:C++提供了new[]与delete[]来专门处理数组类型:A * ptr = new A[10];//分配10个A对象,使用new[]分配的内存必须使用delete[]进行释放:delete [] ptr;至于malloc,它并知道你在这块内存上要放的数组还是啥别的东西,反正它就给你一块原始的内存。7、内存不够重新分配内存:使用malloc分配的内存后,如果在使用过程中发现内存不足,可以使用realloc函数进行内存重新分配实现内存的扩充。realloc先判断当前的指针所指内存是否有足够的连续空间,如果有,原地扩大可分配的内存地址,并且返回原来的地址指针;如果空间不够,先按照新指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来的内存区域。new没有这样直观的配套设施来扩充内存。8、是否可以被重载:new/delete可以,malloc/free不
十、宏:
宏定义是C语言提供的一种预处理,又称为宏代换、宏替换,简称“宏”,用#define定义,如下:
#define Pi 3.1415926
写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个:#define MIN(A,B) ((A) <= (B) ? (A) : (B))
注意:谨慎地将宏定义中的“参数”和整个宏用用括弧括起来。末尾不加分号。
十一、虚函数:C++中的虚函数的作用主要是实现了多态的机制。那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性。我们只需在把基类的成员函数设为virtual,其派生类的相应的函数也会自动变为虚函数。指向基类的指针在操作它的多态类对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。
十二、手写string类:
-
class String
-
{
-
public:
-
String(const char *str = NULL); // 普通构造函数
-
String(const String &other); // 拷贝构造函数
-
~ String(void); // 析构函数
-
String & operator =(const String &other); // 赋值函数
-
private:
-
char *m_data; // 用于保存字符串
-
};
-
-
//普通构造函数
-
String::String(const char *str)
-
{
-
if(str==NULL)
-
{
-
m_data = new char[1]; // 得分点:对空字符串自动申请存放结束标志' '的空
-
//加分点:对m_data加NULL 判断
-
*m_data = ' ';
-
}
-
else
-
{
-
int length = strlen(str);
-
m_data = new char[length+1];
-
strcpy(m_data, str);
-
}
-
}
-
// String的析构函数
-
String::~String(void)
-
{
-
delete [] m_data; // 或delete m_data;
-
}
-
//拷贝构造函数
-
String::String(const String &other) // 得分点:输入参数为const型
-
{
-
int length = strlen(other.m_data);
-
m_data = new char[length+1];
-
strcpy(m_data, other.m_data);
-
}
-
//赋值函数
-
String & String::operator =(const String &other) // 得分点:输入参数为const型
-
{
-
if(this == &other) //得分点:检查自赋值
-
return *this;
-
delete [] m_data; //得分点:释放原有的内存资源
-
int length = strlen( other.m_data );
-
m_data = new char[length+1];
-
strcpy( m_data, other.m_data );
-
return *this; //得分点:返回本对象的引用
-
}
十二、const关键字作用:链接:https://www.nowcoder.com/questionTerminal/5c2f7a22343e40179bea3a3cdeace8fb
来源:牛客网
const关键字至少有下列n个作用:
(1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;
(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
(3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
(4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的 成员变量;
十三、虚函数:
为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数:
将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。
十四、#include
1,< >和" "区别:区别是若 #include "" 查找成功,则遮蔽 #include <> 所能找到的同名文件;否则再按照 #include <> 的方式查找文件。另外标准库头文件都放在 #include <> 所查找的位置。一般来说 #include <> 的查找位置是标准库头文件所在目录, #include "" 的查找位置是当前源文件所在目录。<>先去系统目录中找头文件,如果没有在到当前目录下找。所以像标准的头文件 stdio.h、stdlib.h等用这个方法。 而""首先在当前目录下寻找,如果找不到,再到系统目录中寻找。 这个用于include自定义的头文件,让系统优先使用当前目录中定义的。
2,带不带.h:带 .h 的头文件是旧标准的,如果想用新的标准的头文件就不要带 .h