面试中常见的 C 语言与 C++ 区别的问题
来源:公众号(c语言与cpp编程)
C和C++的区别
- C语言是一种结构化语言,其偏重于数据结构和算法,属于过程性语言
- 虽然在语法上C++完全兼容C语言,但是两者还是有很多不同之处。下面将详细讲解C和C++不同之处的常见考题
关键字static在C和C++区别
C和C++中都有关键字static关键字,那么static关键字在C和C++中的使用有什么区别?请简述之。
分析问题:在C中,用static修饰的变量或函数,主要用来说明这个变量或函数只能在本文件代码块中访问,而文件外部的代码无权访问。并且static修饰的变量存放在段存储区。主要有以下两种用途。
1. 定义局部静态变量
- 局部静态变量存储在静态存储区,在程序运行期间都不会释放,只在声明时进行初始化,而且只能初始化一次,如果没有初始化,其自动初始化为0或空字符。具有局部变量的“记忆性”和生存周期“全局性”特点。
- 局部变量的“记忆性”是指在两次函数调用时,第二次调用开始时,变量能够保持上一次调用结束数的值。如下例:
#include <stdio.h>
//20200505 公众号:C语言与CPP编程
void staticShow()
{
static int a=10;
printf("a=%dn",a);
a += 10;
}
int main()
{
for(int i=0;i<4;i++)
{
staticShow();
}
return 0;
}
利用生存周期的“全局性”,可以改善函数返回指针的问题,局部变量的问题在于当函数退出时其生存周期结束。而利用static修饰的局部变量却可以延长其生存期。如下所示:
#include <stdio.h>
#include <string.h>
//20200505 公众号:C语言与CPP编程
char *p = NULL;
char *helloToStr(char *b)
{
static char a[50];
a[0]='H';
a[1]='E';
a[2]='L';
a[3]='L';
a[4]='O';
strcpy(a+5,b);
p=a;
return a;
};
int main(void)
{
printf("%sn",helloToStr("yang"));
strcpy(p+5,"song");
printf("%sn",p);
strcpy(p+5,"zhang");
printf("%sn",p);
strcpy(p+5,"wang");
printf("%sn",p);
return 0;
}
2.限定访问区域
被static修饰的变量、函数只能被同一文件内的代码段访问。在此static不再表示存储方式,而是限定作用范围。如下所示:
//Test1.cpp
static int a;
int b;
extern void fun1()
{
......
}
static void fun1()
{
......
}
//Test2.cpp
extern int a; //错误,a是static类型,无法在Test2.cpp文件中使用
extern int b; //使用Test1.cpp中定义的全局变量
extern void fun1(); //使用Test1.cpp中定义的函数
extern void fun2(); //错误,无法使用Test1.cpp文件中static函数
在C++中除了上述的两种常用方法外还有另外一种使用方法:定义静态成员变量和静态成员函数。静态成员变量或静态成员函数表示其不属于任何一个类实例,是类的所有类实例所共有的。如下所示:
#include <iostream.h>
#include <string.h>
class A
{
public:
static int a;
static int geta();
int b;
int getb();
};
int A::a=100;
int A::geta()
{
return a;
}
int A::getb()
{
return b;
}
int main(void)
{
A m,n;
m.b=90;
cout<<m.geta()<<endl;
cout<<m.getb()<<endl;
cout<<m.a<<endl;
n.a=33;
n.b=44;
cout<<m.geta()<<endl;
cout<<m.getb()<<endl;
cout<<m.a<<endl;
return 0;
}
答案
在C中static用来修饰局部静态变量和外部静态变量、函数。而C++中除了上述功能外,还用来定义类的成员变量和函数,即静态成员和静态成员函数。
注意:编程时static的记忆性和全局性的特点可以使在不同时期调用的函数进行通信,传递信息,而C++的静态成员则可以在多个对象实例间进行通信,传递信息。
结构体在C语言和C++的区别
分析问题:在C中,结构体是一种简单的复合型数据,由若干个基本类型数据或复合类型数据组合而成。而在C++结构体中,还可以声明函数。如下所示:
#include <iostream.h>
struct A
{
public:
int a;
int gata()
{
return a;
}
};
int main(void)
{
m.a=50;
cout<<m.gata()<<endl;
return 0;
}
输出结果:50
但是这种用法看起来有点不伦不类,这是C到C++过渡的遗留问题
答案
- C语言的结构体是不能有函数成员的,而C++的类可以有。
- C语言结构体中数据成员是没有private、public和protected访问限定的。而C++的类的成员有这些访问限定(在C++中结构体的成员也是有访问权限设定的,但是类成员的默认访问属性是private,而结构体的默认访问属性是public)。
- C语言的结构体是没有继承关系的,而C++的类却有丰富的继承关系。
说明:虽然C的结构体和C++的类有很大的相似度,但是类是实现面向对象的基础。而结构体只可以简单地理解为类的前身。
C中malloc和C++的new区别
分析问题:malloc、free与new、delete都是用来动态申请内存和释放内存的。不同点如下:
- malloc、free是标准库函数,new、delete则是运算符。malloc、free在C、C++中都可使用,而new、delete只属于C++。
- malloc要指定申请内存的大小,其申请的只是一段内存空间。而new不必指定申请内存的大小,建立的是一个对象。
- new、delete在申请非内部数据类型的对象时,对象在创建的同时会自动执行构造函数,在消亡时会自动执行析构函数,这不在编译器的控制之内,所以malloc、free无法实现。
- new返回的是某种数据类型的指针,而malloc返回的是void型指针。
- 由于new、delete是运算符,可以重载,不需要头文件的支持,而malloc、free是库函数,可以覆盖,并且要包含相应的头文件。
答案
- new、delete是操作符,可以重载,只能在C++中使用。
- malloc、free是函数,可以覆盖,C、C++中都可以使用。
- new可以调用对象的构造函数,对应的delete调用相应的析构函数。
- malloc仅仅分配内存,free仅仅回收内存,并不执行构造和析构函数。
- new、delete返回的是某种数据类型指针,malloc、free返回的是void指针。
注意:malloc申请的内存空间要用free释放,而new申请的内存空间要用delete释放,不能混用。因为两者实现的机理不同。
C++引用和C的指针有何区别
分析问题:引用就是变量或对象的别名,它不是值,不占据存储空间,其只有声明没有定义。在C++中引用主要用于函数的形参和函数返回值。
1、作为函数的参数
当函数的返回值多于一个时,可以使用指针实现。如下所示:
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int main(void)
{
int a=10,b=5;
cout<<"Before change:"<< a<<""<<b<<endl;
swap(&a,&b);
cout<<"After change:"<< a<<""<<b<<endl;
return 0;
}
输出结果:
Before change: 10 55
After change: 55 10
虽然上述代码实现了多个返回值的功能,但是函数的语法相对传值方式比较麻烦。在函数中使用指针所指对象的数值时,必须在指针前加上,如上例中的的swap函数频繁使用了“a”、“*b”,如此不仅书写麻烦,还不利于阅读,并且容易产生错误。在函数调用时也容易产生误解,如上述代码main函数中swap(&a, &b),看起来好像是交换了两个变量的地址似的。而用引用实现swap函数,如下所示:
void swap(int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
int main(void)
{
int a=10,b=5;
cout<<"Before change:"<< a<<""<<b<<endl;
swap(a,b);
cout<<"After change:"<< a<<""<<b<<endl;
return 0;
}
可以看出用引用实现swap函数比指针实现要简洁,调用也显得更加合乎情理。
2、引用作为函数的返回值
在大多数情况下可以被指针替代,但是遇到构造函数和操作符重载函数的“形式自然”的问题时,是不能被指针替代的。指针和引用功能相似,但是在操作时却有很多不同的地方,如指针的操作符是“*”和“->”,而引用常用的操作符是“.”。在使用时还要注意以下几点:
- 指针可不初始化且初始化的时候,可以指向一个地址,也可以为空。引用必须初始化且只能初始化为另一个变量,如下:
int a=1024;
int *p=&a;
int &b=a;
引用之间的赋值和指针之间的赋值不同。指针赋值如下:
int a=1,b=2;
int *p1=&a, *p2=&b;
这时执行p1=p2;后,p1原来指向的对象v1的值并没有改变,而p1被赋值为p2所指向的对象,如下图:
引用赋值如下:
int a=1,b=2;
int &v1=a, &v2=b;
这时执行r1= r2;改变的是v1,将r 2指向的对象的值赋值给v1,而不是引用r1本身。赋值之后,两个引用还是指向各自的原来对象,如图下图。
3.指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变。如下所示:
答案
指针和引用主要有以下区别:
- 引用必须被初始化,但是不分配存储空间。指针不声明时初始化,在初始化的时候需要分配存储空间。
- 引用初始化以后不能被改变,指针可以改变所指的对象。
- 不存在指向空值的引用,但是存在指向空值的指针。
注意:引用作为函数参数时,会引发一定的问题,因为让引用作为参数,目的就是想改变这个引用所指向地址的内容,而函数调用时传入的是实参,看不出函数的参数是正常变量,还是引用,因此可能会引发错误。所以使用时一定要小心谨慎。
- Android组件化搭建
- ECMAScript 6 入门简介
- RxJava2 实战知识梳理(2) - 计算一段时间内数据的平均值
- 用了Docker,妈妈再也不担心我的软件安装了 - 基础篇
- 适配器模式(Adapter)
- 敞开的地狱之门:Kerberos协议的滥用
- CY7C68013A的一点总结
- RxJava2 实战(1) - 后台执行耗时操作,实时通知 UI 更新
- AutoIt木马又一发:暗藏神秘照片
- css3动画从入门到精通
- ReactJs和React Native的那些事
- Linux学习-文件排序和FASTA文件操作
- Bash漏洞再次演进:缓冲区溢出导致远程任意命令执行
- Pandas,让Python像R一样处理数据,但快
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 为什么机器学习应用交易那么难(中)
- 消息队列的消费幂等性如何保证
- js中数组Array.reduce方法介绍及使用场景
- 推荐一套基于go开发的文档管理系统
- 如何通过容器搭建稳定可靠的私有网盘(NextCloud)
- Flutter实现倒计时功能
- Excelize 2.3.0 发布, Go 语言 Excel 基础库
- 网站渗透攻防Web篇之SQL注入攻击高级篇
- 网站渗透攻防Web篇之SQL注入攻击中级篇
- Go 语言学习之 method
- 网站渗透攻防Web篇之SQL注入攻击初级篇
- VBA解析复合文档05——读取数据流
- C++核心准则E.25:如果不能抛出异常,模仿RAII方式进行资源管理
- VBA解析复合文档06——改写数据流
- PyTorch5:torch.nn总览&torch.nn.Module