牛客 C++刷题day6

1:关于类的一些解释

一、空类的大小

  C++中空类的大小是1,这是因为空类也可以被实例化,为了确保每一个实例在内存中都有一个独一无二的地址,编译器往往隐含给一个空类加一个字节。

二、类中的成员函数与非虚成员函数

  类中的非虚成员函数不占用空间,虚函数表占用四个字节,只要有虚函数(无论有几个)都只占用四个字节。成员函数还是以一般的函数一样的存在。a.fun()是通过fun(a.this)来调用的。所谓成员函数只是在名义上是类里的。其实成员函数的大小不在类的对象里面,同一个类的多个对象共享函数代码。而我们访问类的成员函数是通过类里面的一个指针实现,而这个指针指向的是一个table,table里面记录的各个成员函数的地址(当然不同的编译可能略有不同的实现)。所以我们访问成员函数是间接获得地址的。所以这样也就增加了一定的时间开销,这也就是为什么我们提倡把一些简短的,调用频率高的函数声明为inline形式(内联函数)。

三、派生类与基类

  派生类继承基类的所有成员(包括私有数据成员),派生类的大小是在基类的大小的基础上再增加自己数据成员的空间。

四、虚表与类数据成员

  虚函数表首先存入内存中,然后是数据成员。

五、类的与结构体

  类的对齐规则与结构体基本一致,即取数据成员本身的对其数与编译器默认对齐数之间取小的那个数作为实际对齐数。

六、类的数据成员

  类的数据成员按其声明顺序加入内存,(与其访问权限无关,即无论public,private,protected的数据成员,只看其声明顺序)

七、static 数据成员不占用类的空间,对其派生类亦是如此。

2:二维数组

二维数组必须指定列的数量,行的数量可以不指定,二维数组的初始化方式有以下几种:
⑴ 分行进行初始化
int a[2][3]={{1,2,3},{4,5,6}};
在{ }内部再用{ }把各行分开,第一对{ }中的初值1,2,3是0行的3个元素的初值。第二对{ }中的初值4,5,6是1行的3个元素的初值。相当于执行如下语句:
int a[2][3];
a[0][0]=1;a[0][1]=2;a[0][2]=3;a[1][0]=4;a[1][1]=5;a[1][2]=6;
注意,初始化的数据个数不能超过数组元素的个数,否则出错。
⑵ 不分行的初始化
int a[2][3]={ 1,2,3,4,5,6};
把{ }中的数据依次赋给a数组各元素(按行赋值)。即a[0][0]=1; a[0][1]=2;a[0][2]=3;a[1][0]=4;a[1][1]=5;a[1][2]=6;
⑶ 为部分数组元素初始化
static int a[2][3]={{1,2},{4}};
第一行只有2个初值,按顺序分别赋给a[0][0]和a[0][1];第二行的初值4赋给a[1][0]。由于存储类型是static,故其它数组元素的初值为0。注:某些C语言系统(如:Turbo C)中,存储类型不是static的变量或数组的初值也是0。
static int a[2][3]={ 1,2};
只有2个初值,即a[0][0]=1,a[0][1]=2,其余数组元素的初值均为0。
⑷ 可以省略第一维的定义,但不能省略第二维的定义。系统根据初始化的数据个数和第2维的长度可以确定第一维的长度。
int a[ ][3]={ 1,2,3,4,5,6};
a数组的第一维的定义被省略,初始化数据共6个,第二维的长度为3,即每行3个数,所以a数组的第一维是2。
一般,省略第一维的定义时,第一维的大小按如下规则确定:
初值个数能被第二维整除,所得的商就是第一维的大小;若不能整除,则第一维的大小为商再加1。例如,int a[ ][3]={ 1,2,3,4};等价于:int a[2][3]={ 1,2,3,4};
若分行初始化,也可以省略第一维的定义。下列的数组定义中有两对{ },已经表示a数组有两行。
static int a[ ][3]={{1,2},{4}};
3:++p和p++的区别
假设这样的一个例子:
1
2
3
int p = -1;
int y = 0;
y = p++ + ++P;
先分析一下它的汇编代码(没有优化):
1
2
3
4
5
6
7
8
9
10
subl    $40, %esp              ; 分配40字节  
movl    $1, -16(%ebp)          ; 存储 p 
movl    $0, -12(%ebp)          ; 存储 y  
movl    -16(%ebp), %eax        ; 这3步执行 p++  
leal    1(%eax), %edx  
movl    %edx, -16(%ebp)  
addl    $1, -16(%ebp)          ; 这2步执行 ++p 
movl    -16(%ebp), %edx  
addl    %eax, %edx             ; 相加操作  
movl    %edx, -12(%ebp)        ; 结果写回 y  
可以看出p++需要3步,++p需要2步,而且修改p的值是不一样的,看出++p的效率比p++的高。
4:输出字符串的格式说明
m.ns 输出占m列,但只取字符串中左端n个字符。这n个字符输出在m列的右侧,左补空格。这个跟其他输出类似
5:几种常见调用约定:

问题解析:本题要求选出像printf一样支持变长参数的函数调用约定。

1.什么是函数调用约定?

答:当一个函数被调用时,函数的参数会被传递给被调用的函数,同时函数的返回值会被返回给调用函数。函数的调用约定就是用来描述参数(返回值)是怎么传递并且由谁来平衡堆栈的。

2.常见的函数调用约定有哪些?

答:__stdcall,__cdecl,__fastcall,__thiscall,__nakedcall,__pascal

     按参数的传递顺序对这些约定可划分为:
           a).从右到左依次入栈:__stdcall,__cdecl,__thiscall
           b).从左到右依次入栈:__pascal,__fastcall

3.支持变长的函数调用约定有哪些?

答:__cdecl,带有变长参数的函数必须是cdecl调用约定,由函数的调用者来清除栈,参数入栈的顺序是从右到左 

 6:多个内存操作函数的说明

1. malloc,calloc,realloc,free属于C函数库,而new/delete则是C++函数库;
2. 多个-alloc的比较:
    alloc:唯一在栈上申请内存的,无需释放;
    malloc:在堆上申请内存,最常用;
    calloc:malloc+初始化为0;
    realloc:将原本申请的内存区域扩容,参数size大小即为扩容后大小,因此此函数要求size大小必须大于ptr内存大小。
 

转载于:https://www.cnblogs.com/Tonarinototoro/p/11489010.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值