c/c++常见面试题

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

变量的定义为变量分配地址和内存空间,变量的声明不分配地址。一个变量可以在多个地方声明,但是只在一个地方定义。加入 extern 修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义。
说明:很多时候一个变量,只是声明不分配内存空间,知道具体使用时才初始化,分配内存空间,如外部变量。

int main()
{
	extern int A;
	//这是个声明而不是定义,声明A是一个已经定义了的外部变量
	//注意:声明外部变量时可以把变量类型去掉如:extern A;
	dosth();//执行函数
}
int A;//是定义,定义了A为整型的外部变量

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

  • 利用#ifdef、#endif将某程序功能模块包括进去,以向特定用户提供该功能。在不需要时用户可轻易将其屏蔽。
    c/c++常见面试题_第1张图片
  • 在子程序前加上标记,以便于追踪和调试。
    c/c++常见面试题_第2张图片
  • 应对硬件的限制。由于一些具体应用环境的硬件不一样,限于条件,本地缺乏这种设备,只能绕过硬件,直接写出预期结果。

注意:虽然不用条件编译命令而直接用if语句也能达到要求,但那样做目标程序长(因为所有语句都编译),运行时间长(因为在程序运行时间对if语句进行测试)。而采用条件编译,可以减少被编译的语句,从而减少目标程序的长度,减少运行时间。

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

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

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

//float与零值比较
const float EPSION = 0.00001;
if((x>=-EPSION)&&(x<=EPSION))//其中EPSION时允许的误差

//指针变量与零值比较
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 
using namespace std;
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()
{
    cout<<sizeof(s1);
	cout << sizeof(s2);
	cout << sizeof(s3);
	return 0;
}

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

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

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

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

  • 从静态存储区域分配
    内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快、不容易出错,因为有系统会善后。例如全局变量,static变量、常量字符串等。
  • 从栈上分配
    在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。大小为2M.
  • 从堆上分配
    即动态内存分配。程序在运行的时候用malloc和new申请任意大小的内存,程序员自己负责在何时用free和delete释放内存。动态内存的生存期由程序员决定,使用非常灵活。如果在堆上分配了空间,就有责任回收他,否则运行的程序会出现内存泄露,另外频繁的分配和释放不同大小的堆空间将会产生”堆内碎块“。

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

17、简述strcpy、sprintf、memcpy的区别

  • 操作对象不同,sprcpy的两个操作对象均为字符串,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引用
  • 指针在使用中可以指向其他对象,但是引用只能是一个对象的引用,不能被改变;
  • 指针可以有多级指针,而引用止于一级;
  • 指针和引用使用++运算符的意义不一样;
  • 如果返回动态内存分配的对象或者内存,必须使用指针,引用可能会引起内存泄漏。

你可能感兴趣的:(运营商面试,c语言,c++,开发语言)