C++八股文

1 变量的声明和定义有什么区别

变量的定义为变量分配地址和存储空间, 变量的声明不分配地址。一个变量可以在多个地方声明, 但是只在一个地方定义。 加入extern 修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义。
说明:很多时候一个变量,只是声明不分配内存空间,直到具体使用时才初始化,分配内存空间, 如外部变量。
int main()
{
extern int A;
//这是个声明而不是定义,声明A是一个已经定义了的外部变量
//注意:声明外部变量时可以把变量类型去掉如:extern A;
dosth(); //执行函数
}
int A; //是定义,定义了A为整型的外部变量

2 简述#ifdef、#else、#endif和#ifndef的作用

利用#ifdef、#endif将某程序功能模块包括进去,以向特定用户提供该功能。在不需要时用户可轻易将其屏蔽。
#ifdef MATH
#include “math.c”
#endif
在子程序前加上标记,以便于追踪和调试。
#ifdef DEBUG
printf (“Indebugging…!”);
#endif
应对硬件的限制。由于一些具体应用环境的硬件不一样,限于条件,本地缺乏这种设备,只能绕过硬件,直接写出预期结果。
注意:虽然不用条件编译命令而直接用if语句也能达到要求,但那样做目标程序长(因为所有语句都编译),运行时间长(因为在程序运行时间对if语句进行测试)。而采用条件编译,可以减少被编译的语句,从而减少目标程序的长度,减少运行时间。

3 写出int 、bool、 float 、指针变量与 “零值”比较的if 语句

//int与零值比较
if ( n == 0 )
if ( n != 0 )

//bool与零值比较
if (flag) // 表示flag为真
if (!flag) // 表示flag为假

//float与零值比较
const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON) //其中EPSINON是允许的误差(即精度)。

//指针变量与零值比较
if (p == NULL)
if (p != NULL)

4 结构体可以直接赋值吗

声明时可以直接初始化,同一结构体的不同对象之间也可以直接赋值,但是当结构体中含有指针“成员”时一定要小心。
注意:当有多个指针指向同一段内存时,某个指针释放这段内存可能会导致其他指针的非法操作。因此在释放前一定要确保其他指针不再使用这段内存空间。

5 sizeof 和strlen 的区别

sizeof是一个操作符,strlen是库函数。
sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为‘\0’的字符串作参数。
编译器在编译时就计算出了sizeof的结果,而strlen函数必须在运行时才能计算出来。并且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。
数组做sizeof的参数不退化,传递给strlen就退化为指针了

6 C 语言的关键字 static 和 C++ 的关键字 static 有什么区别

在 C 中 static 用来修饰局部静态变量和外部静态变量、函数。而 C++中除了上述功能外,还用来定义类的成员变量和函数。即静态成员和静态成员函数。
注意:编程时 static 的记忆性,和全局性的特点可以让在不同时期调用的函数进行通信,传递信息,而 C++的静态成员则可以在多个对象实例间进行通信,传递信息。

7 C 语言的 malloc 和 C++ 中的 new 有什么区别

new 、delete 是操作符,可以重载,只能在C++ 中使用。
malloc、free 是函数,可以覆盖,C、C++ 中都可以使用。
new 可以调用对象的构造函数,对应的delete 调用相应的析构函数。
malloc 仅仅分配内存,free 仅仅回收内存,并不执行构造和析构函数
new 、delete 返回的是某种数据类型指针,malloc、free 返回的是void 指针。
注意:malloc 申请的内存空间要用free 释放,而new 申请的内存空间要用delete 释放,不要混用。

8 写一个 “标准”宏MIN

#define min(a,b)((a)<=(b)?(a):(b))

9 ++i和i++的区别

++i先自增1,再返回,i++先返回i,再自增1

10 volatile有什么作用

状态寄存器一类的并行设备硬件寄存器。
一个中断服务子程序会访问到的非自动变量。
多线程间被几个任务共享的变量。
注意:虽然volatile在嵌入式方面应用比较多,但是在PC软件的多线程中,volatile修饰的临界变量也是非常实用的。

11 一个参数可以既是const又是volatile吗

可以,用const和volatile同时修饰变量,表示这个变量在程序内部是只读的,不能改变的,只在程序外部条件变化下改变,并且编译器不会优化这个变量。每次使用这个变量时,都要小心地去内存读取这个变量的值,而不是去寄存器读取它的备份。
注意:在此一定要注意const的意思,const只是不允许程序中的代码改变某一变量,其在编译期发挥作用,它并没有实际地禁止某段内存的读写特性。

12 a 和&a 有什么区别

&a:其含义就是“变量a的地址”。
*a:用在不同的地方,含义也不一样。
在声明语句中,*a只说明a是一个指针变量,如int *a;
在其他语句中,*a前面没有操作数且a是一个指针时,*a代表指针a指向的地址内存放的数据,如b=*a;
*a前面有操作数且a是一个普通变量时,a代表乘以a,如c=ba。

13 用C 编写一个死循环程序

while(1)
{ }
注意:很多种途径都可实现同一种功能,但是不同的方法时间和空间占用度不同,特别是对于嵌入 式软件,处理器速度比较慢,存储空间较小,所以时间和空间优势是选择各种方法的首要考虑条件。

14 结构体内存对齐问题

请写出以下代码的输出结果:

#include<stdio.h>
struct S1
{
   
    int i:8;
    char j:4;
    int a:4;
    double b;
};

struct S2
{
   
    int i:8;
    char j:4;
    double b;
    int a:4;
};

struct S3
{
   
    int i;
    char j;
    double b;
    int a;
};

int main()
{
   
    printf("%d\n",sizeof(S1));  // 输出8
    printf("%d\n",sizeof(S1);  // 输出12
    printf("%d\n",sizeof(Test3));  // 输出8
    return 0;
}

sizeof(S1)=16
sizeof(S2)=24
sizeof(S3)=32
说明:结构体作为一种复合数据类型,其构成元素既可以是基本数据类型的变量,也可以是一些复合型类型数据。对此,编译器会自动进行成员变量的对齐以提高运算效率。默认情况下,按自然对齐条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同,向结构体成员中size最大的成员对齐。
许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,而这个k则被称为该数据类型的对齐模数。

15 全局变量和局部变量有什么区别?实怎么实现的?操作系统和编译器是怎么知道的?

全局变量是整个程序都可访问的变量,谁都可以访问,生存期在整个程序从运行到结束(在程序结束时所占内存释放);
而局部变量存在于模块(子程序,函数)中,只有所在模块可以访问,其他模块不可直接访问,模块结束(函数调用完毕),局部变量消失,所占据的内存释放。
操作系统和编译器,可能是通过内存分配的位置来知道的,全局变量分配在全局数据段并且在程序开始运行的时候被加载.局部变量则分配在堆栈里面。

16 简述C、C++程序编译的内存分配情况

从静态存储区域分配:
内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快、不容易出错, 因为有系统会善后。例如全局变量,static 变量,常量字符串等。

在栈上分配:
在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释 放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。大小为2M。

从堆上分配:
即动态内存分配。程序在运行的时候用 malloc 或new 申请任意大小的内存,程序员自己负责在何 时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活。如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,另外频繁地分配和释放不同大小的堆空间将会产生 堆内碎块。

一个C、C++程序编译时内存分为5 大存储区:堆区、栈区、全局区、文字常量区、程序代码区。

17 简述strcpy、sprintf 与memcpy 的区别

操作对象不同,strcpy 的两个操作对象均为字符串,sprintf 的操作源对象可以是多种数据类型, 目的操作对象是字符串,memcpy 的两个对象就是两个任意可操作的内存地址,并不限于何种数据类型。
执行效率不同,memcpy 最高,strcpy 次之,sprintf 的效率最低。
实现功能不同,strcpy 主要实现字符串变量间的拷贝,sprintf 主要实现其他数据类型格式到字 符串的转化,memcpy 主要是内存块间的拷贝。
注意:strcpy、sprintf 与memcpy 都可以实现拷贝的功能,但是针对的对象不同,根据实际需求,来 选择合适的函数实现拷贝功能。

18 请解析((void ()( ) )0)( )的含义

void (0)( ) :是一个返回值为void,参数为空的函数指针0。
(void (
)( ))0:把0转变成一个返回值为void,参数为空的函数指针。
(void ()( ))0:在上句的基础上加表示整个是一个返回值为void,无参数,并且起始地址为0的函数的名字。
(
(void (*)( ))0)( ):这就是上句的函数名所对应的函数的调用。

19 C语言的指针和引用和c++的有什么区别?

指针有自己的一块空间,而引用只是一个别名;
使用sizeof看一个指针的大小是4,而引用则是被引用对象的大小;
作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接对引 用的修改都会改变引用所指向的对象;
可以有const指针,但是没有const引用;
指针在使用中可以指向其它对象,但是引用只能是一个对象的引用,不能 被改变;
指针可以有多级指针(**p),而引用止于一级;
指针和引用使用++运算符的意义不一样;
如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄露。

20 typedef 和define 有什么区别
用法不同:typedef 用来定义一种数据类型的别名,增强程序的可读性。define 主要用来定义 常量,以及书写复杂使用频繁的宏。
执行时间不同:typedef 是编译过程的一部分,有类型检查的功能。define 是宏定义,是预编译的部分,其发生在编译之前,只是简单的进行字符串的替换,不进行类型的检查。
作用域不同:typedef 有作用域限定。define 不受作用域约束,只要是在define 声明后的引用 都是正确的。
对指针的操作不同:typedef 和define 定义的指针时有很大的区别。
注意:typedef 定义是语句,因为句尾要加上分号。而define 不是语句,千万不能在句尾加分号。

21 指针常量与常量指针区别

指针常量是指定义了一个指针,这个指针的值只能在定义时初始化,其他地方不能改变。常量指针 是指定义了一个指针,这个指针指向一个只读的对象,不能通过常量指针来改变这个对象的值。 指针常量强调的是指针的不可改变性,而常量指针强调的是指针对其所指对象的不可改变性。

注意:无论是指针常量还是常量指针,其最大的用途就是作为函数的形式参数,保证实参在被调用 函数中的不可改变特性。

22 简述队列和栈的异同

队列和栈都是线性存储结构,但是两者的插入和删除数据的操作不同,队列是“先进先出”,栈是 “后进先出”。

注意:区别栈区和堆区。堆区的存取是“顺序随意”,而栈区是“后进先出”。栈由编译器自动分 配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。堆一般由程序员 分配释放, 若程序员不释放,程序结束时可能由OS 回收。分配方式类似于链表。 它与本题中的堆和栈是两回事。堆栈只是一种数据结构,而堆区和栈区是程序的不同内存存储区域。

23 设置地址为0x67a9 的整型变量的值为0xaa66
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa66;
注意:这道题就是强制类型转换的典型例子,无论在什么平台地址长度和整型数据的长度是一样的, 即一个整型数据可以强制转换成地址指针类型,只要有意义即可。

24 编码实现字符串转化为数字
编码实现函数atoi(),设计一个程序,把一个字符串转化为一个整型数值。例如数字:“5486321 ”, 转化成字符:5486321。

int myAtoi(const char * str) 
{
   int num = 0; //保存转换后的数值 
   int isNegative = 0; //记录字符串中是否有负号 

   int n =0; 
   char *p = str; 
   if(p == NULL) //判断指针的合法性 
   { 
      return -1; 
   } 
   while(*p++ != '\0') //计算数字符串度 
   { 
      n++; 
   } 
   p = str; 
   if(p[0] == '-') //判断数组是否有负号 
   { 
      isNegative = 1; 
   } 

   char temp = '0'; 
   for(int i = 0 ; i < n; i++) 
   { 
      char temp = *p++; 
       if(temp > '9' ||temp < '0') //滤除非数字字符 
      { 
         continue; 
      } 
      if(num !=0 || temp != '0') //滤除字符串开始的0 字符 
      { 
         temp -= 0x30; //将数字字符转换为数值 
          num += temp *int( pow(10 , n - 1 -i) ); 
       } 
   } 
   if(isNegative) //如果字符串中有负号,将数值取反 
   { 
       return (0 - num
  • 23
    点赞
  • 232
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值