c++题目

1 以下函数中,和其他函数不属于一类的是_____。

fread
gets
getchar
pread
getline
scanf
1. size_t   fread (   void   *  buffer    size_t   size    size_t   count    FILE   *  stream  ) ;  从一个文件流  stream  中读数据到  buffer( buffer ) ,最多读取count个元素,每个元素size字节,如果调用成功返回实际读取到的元素个数,如果不成功或读到文件末尾返回 0。
2.  gets(char  *  buffer  ):  从stdin流中读取  字符串  ,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer  指针  所指向的字符  数组  中。换行符不作为读取串的内容,读取的换行符被转换为‘\0’空字符,并由此来结束字符串。
3.int   getchar():  #define getchar() getc(stdin),  返回类型为int型,返回值为用户输入的ASCⅡ码,出错返回-1。
4.  ssize_t pread(int   fd  , void *  buf  , size_t  count  , off_t  offset  );    文件描述符   fd  读数据到  buffer,从  读取地址(=文件开始+offset)  最多读取count个元素,  执行后,  文件偏移  指针不变。返回成功读取数据的字节数;失败,返回-1;
5.  ssize_t getline(char **lineptr, size_t *n, FILE *stream);   lineptr:  ;    文件流  stream  读数据到  lineptr(  如果是NULL,则有系统帮助malloc,请在使用完成后free释放,  如果是由系统malloc的指针,n请填0      直到以下情况发生会导致生成的此字符串结束。1)到文件结束,2)遇到函数的定界符,3)输入达到最大限度。    执行后,  文件偏移  指针不变。返回成功读取数据的字节数;失败,返回-1;
6.scanf
显然  pread的文件描述符不一样
pread是系统调用,其他事IO函数
2 以下函数中,和其他函数不属于一类的是____。
read
pread
write
pwrite
fseek
lseek
fseek是函数,其他都是系统调用
问题描述
1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma pack(2)
class BU
{
     int number;
     union UBffer
     {
         char buffer[13];
         int number;
     }ubuf;
     void foo(){}
     typedef char *(*f)( void *);
     enum {hdd,ssd,blueray}disk;
}bu;
sizeof(bu)的值是()

#pragma pack(2)
class BU
{
    int number; // 4
    union UBffer
    {
        char buffer[13]; // 13
        int number; // 4
    }ubuf; // union的大小取决于它所有的成员中,占用空间最大的一个成员的大小,并且需要内存对齐,这里因为#pragma pack(2),所以union的大小为14,如果不写#pragma pack(2),那么union大小为16【因为与sizeof(int)=4对齐】
    void foo(){} //0
    typedef char*(*f)(void*); //0
    enum{hdd,ssd,blueray}disk; // 4
}bu;

因此sizeof(union) = 4+14 +0 +0 +4 = 22
union:当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union);
它有以下特点:
    (1)它是一个结构;
    (2)它的所有成员相对于基地址的偏移量都为0;
    (3)此结构空间要大到足够容纳最"宽"的成员;
    (4)其对齐方式要适合其中所有的成员
综上:
    而分配给union的实际大小不仅要满足是对齐大小的整数倍,同时要满足实际大小不能小于最大成员的大小。
    本题目中
    注意第一行,#pragma pack(2)
    首先考虑没有这句话时,我们在类、结构或者union补齐字节的时候,找它们的成员数据中找字节最大的那个数去衡量如何对齐,假设为z;
    但是有了这句话以后,对齐方式是取 pack(n)中n和z的最小值去对齐;
    可见本题中对齐字节数为2;
    之后往下看 int number; 占4个字节
    接下来考虑union大小
    union UBffer
    {
        char buffer[13]; // 13
        int number; // 4
    }ubuf; buffer 是13个字节,number 是4个字节,取最大的 为13,注意还要字节对齐,对齐字节数为2,所以Union大小为14,既满足buffer的对齐 也满足number的对齐。
    void foo(){} 不占
    typedef char*(*f)(void*); 不占
    enum{hdd,ssd,blueray}disk; 4个字节

      综上,总大小为14+4+0+0  +4=22
答案错了,vs2012 x64下编译结果为22,选  E;
int =4
union=13+1=14
enum=4(内存中当成int来存储)
4+14+4=22
f只是一个定义,不是实际上的指针,没有占字节
但是如果我加入一个Int*,即:
class BU
{
int number;
union UBffer
{
char buffer[13];
int number;
}ubuf;
void foo(){}
typedef char*(*f)(void*);
enum{hdd,ssd,blueray}disk;
int *a;
}bu;
sizoef(bu)=30,int型指针占8个字节

枚举类型的sizeof值都是4;
enum只是定义了一个常量集合,里面没有“元素”,而枚举类型是当做 int来存储的
1.number,int类型,自身对齐是4,指定对齐是2,所以有效对齐是2,起始地址须是2的整数倍,放在[0-3];
2.ubuf,联合体,自身对齐是其成员自身对齐的最大值,数组看数组成员类型,所以这里的ubuf的自身对齐是4,指定对齐是2,所以有效对齐是2,这就决定了ubuf的起始地址须是2的整数倍,而且ubuf的总大小须是2的整数倍,所以放在[4,17],  (联合体的大小是其成员大小的最大值)
3.disk,枚举类型,自身对齐是4,指定对齐是2,所以有效对齐是2,这就要求disk的起始地址须是2的整数倍,而且disk的总大小须是2的整数倍,所以放在[18,21]。(枚举类型的大小是4字节)
最后,bu的自身对齐是4,指定对齐是2,所有有效对齐是2,这就要求bu的大小须是2的整数倍,所以是
22. (抛砖引玉,如有错误,欢迎指正!)
int * pint = 0; 
pint += 6; 
cout << pint << endl;
以上程序的运行结果是:
指向地址零加6,int是4位地址,值为24
关于c++的inline关键字,以下说法正确的是()
使用inline关键字的函数会被编译器在调用处展开
头文件中可以包含inline函数的声明
可以在同一个项目的不同源文件内定义函数名相同但实现不同的inline函数
定义在Class声明内的成员函数默认是inline函数
优先使用Class声明内定义的inline函数
优先使用Class实现的内inline函数的实现

A 项错误,因为使用 inline 关键字的函数只是用户希望它成为内联函数,但编译器有权忽略这个请求,比如:若此函数体太大,则不会把它作为内联函数展开的。

B 项错误,头文件中不仅要包含 inline 函数的声明,而且必须包含定义,且在定义时必须加上 inline 。【关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用】

C 项错误, inline 函数可以定义在源文件中,但多个源文件中的同名 inline 函数的实现必须相同。一般把 inline 函数的定义放在头文件中更加合适。

D 项正确,类内的成员函数,默认都是 inline 的。【定义在类声明之中的成员函数将自动地成为内联函数】

EF 项无意思,不管是 class 声明中定义的 inline 函数,还是 class 实现中定义的 inline 函数,不存在优先不优先的问题,因为 class 的成员函数都是 inline 的,加了关键字 inline 也没什么特殊的。


内联函数:

Tip: 只有当函数只有 10 行甚至更少时才将其定义为内联函数.

定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用.
优点: 当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数, 鼓励使用内联.
缺点: 滥用内联将导致程序变慢. 内联可能使目标代码量或增或减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的增加代码大小. 现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快。
结论: 一个较为合理的经验准则是, 不要内联超过 10 行的函数. 谨慎对待析构函数, 析构函数往往比其表面看起来要更长, 因为有隐含的成员和基类析构函数被调用!
另一个实用的经验准则: 内联那些包含循环或 switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或 switch 语句从不被执行).
有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数.(递归调用堆栈的展开并不像循环那么简单, 比如递归层数在编译时可能是未知的, 大多数编译器都不支持内联递归函数). 虚函数内联的主要原因则是想把它的函数体放在类定义内, 为了图个方便, 抑或是当作文档描述其行为, 比如精短的存取函数.

-inl.h文件:


Tip: 复杂的内联函数的定义, 应放在后缀名为 -inl.h 的头文件中.


内联函数的定义必须放在头文件中, 编译器才能在调用点内联展开定义. 然而, 实现代码理论上应该放在 .cc 文件中, 我们不希望 .h 文件中有太多实现代码, 除非在可读性和性能上有明显优势.

如果内联函数的定义比较短小, 逻辑比较简单, 实现代码放在 .h 文件里没有任何问题. 比如, 存取函数的实现理所当然都应该放在类定义内. 出于编写者和调用者的方便, 较复杂的内联函数也可以放到 .h 文件中, 如果你觉得这样会使头文件显得笨重, 也可以把它萃取到单独的 -inl.h 中. 这样把实现和类定义分离开来, 当需要时包含对应的 -inl.h 即可。
如果只声明含有inline关键字,就没有内联的效果。 内联函数的定义必须放在头文件中, 编译器才能在调用点内联展开定义.   有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数.
内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline 函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够的。
C 当然 内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它,而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。
对于由两个文件compute.C和draw.C构成的程序来说,程序员不能定义这样的min()函数,它在compute.C中指一件事情,而在draw.C中指另外一件事情。如果两个定义不相同,程序将会有未定义的行为:

      为保证不会发生这样的事情,建议把inline函数的定义放到头文件中。在每个调用该inline函数的文件中包含该头文件。这种方法保证对每个inline函数只有一个定义,且程序员无需复制代码,并且不可能在程序的生命期中引起无意的不匹配的事情。

正确。  定义在类声明之中的成员函数将自动地成为内联函数,例如:
1
class A {    public :   void Foo( int x,  int y) { ... }    // 自动地成为内联函数   } 

EF 在每个调用该inline函数的文件中包含该头文件。这种方法保证对每个inline函数只有一个定义,且程序员无需复制代码,并且不可能在程序的生命期中引起无意的不匹配的事情。 最好只有一个定义!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>       
#include <vector>
using namespace std;
int main( void )
{
     vector< int >array;
     array.push_back(100);
     array.push_back(300);
     array.push_back(300);
     array.push_back(300);
     array.push_back(300);
     array.push_back(500);
     vector< int >::iterator itor;
     for (itor=array.begin();itor!=array.end();itor++)
     {
         if (*itor==300)
         {
             itor=array.erase(itor);
         }
     }
     for (itor=array.begin();itor!=array.end();itor++)
     {
             cout<<*itor<< "" ;
     }
   return 0;
}
下面这个代码输出的是()

vector::erase():从指定容器删除指定位置的元素或某段范围内的元素 
vector::erase()方法有两种重载形式 
如下: 
iterator erase(   iterator _Where); 
iterator erase(   iterator _First,   iterator _Last); 
如果是删除指定位置的元素时: 
返回值是一个迭代器,指向删除元素下一个元素; 

如果是删除某范围内的元素时:返回值也表示一个迭代器,指向最后一个删除元素的下一个元素;

在本题中,当 *itor==300成立时,删除第一个值为300的元素,同时itor指向下一个元素(即是第二个值为300的元素),
                            在for(;;itor++)执行itor,itor指向第三个值为300的元素,进入下一个循环
         进入循环满足*itor==300,重复上面的过程,执行完循环,itor执行值为500的元素。
所有整个过程中,只删除了2个值为300的元素。
----------------已有变量定义和函数调用语句,
1
2
int a= 25 ;
print_value(&a);
则下面函数的正确输出结果是______。
1
2
3
4
void print_value( int * x)
{
     printf(“%x\n”,++*x);
}

printf(“%x\n”,++*x); 先把x的值加上 1 16 进制输出  
1a

函数指针

-------定义一个函数指针,指向的函数有两个int形参并且返回一个函数指针,返回的指针指向一个有一个int形参且返回int的函数?
int (*(*F)(int, int))(int)
int (*F)(int, int)
int (*(*F)(int, int))
*(*F)(int, int)(int)
首先,一个函数指针,指向的函数有两个int形参,这个就是(*F)(int, int),这返回的是一个指针
返回一个函数指针,返回的指针指向一个有一个int形参且返回int的函数;把上面的结果当成一个指针,相当于再做一次上面的步骤,所以结果为:int (*(*F)(int, int))(int)
--------声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,参数是int*,正确的是()
(int *p[10])(int*)
int [10]*p(int *)
int (*(*p)[10])(int *)
int ((int *)[10])*p
以上选项都不正确
C.   首先题目说要声明一个数组指针,  一般我们想到的数组指针是 随便来一个 int(*p)[10],    然后又说每个元素是一个函数指针,那么我们随便来一个 函数指针  int (*pf)(int *) . 然后把(*p)[10]作为一个整体替代 pf     即   int(*(*p)[10]))(int *);    分析: 判断一个复杂式子看最高优先级的,*p是一个指针,然后(*p)外面是[],所以是数组指针, (*p)[10])描述完毕,然后再看外面int(*)(int *)很明显,这是一个函数指针,所以这个数组中每个元素是函数指针

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值