乐趣区

关于c++:面试中常见的-C-语言与-C-区别的问题

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 是库函数,能够笼罩,并且要蕴含相应的头文件。

答案

  1. new、delete 是操作符,能够重载,只能在 C ++ 中应用。
  2. malloc、free 是函数,能够笼罩,C、C++ 中都能够应用。
  3. new 能够调用对象的构造函数,对应的 delete 调用相应的析构函数。
  4. malloc 仅仅分配内存,free 仅仅回收内存,并不执行结构和析构函数。
  5. 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、援用作为函数的返回值

在大多数状况下能够被指针代替,然而遇到构造函数和操作符重载函数的“模式天然”的问题时,是不能被指针代替的。指针和援用性能类似,然而在操作时却有很多不同的中央,如指针的操作符是“*”和“->”,而援用罕用的操作符是“.”。在应用时还要留神以下几点:

  1. 指针可不初始化且初始化的时候,能够指向一个地址,也能够为空。援用必须初始化且只能初始化为另一个变量,如下:

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 自身。赋值之后,两个援用还是指向各自的原来对象,如图下图。

援用间赋值

  1. 指针能够被从新赋值以指向另一个不同的对象。然而援用则总是指向在初始化时被指定的对象,当前不能扭转。如下所示:

int a=1;

int b=2;

int &v1=a; //v1 援用 a

string *pi = &a; //pi 指向 a

v1=b; //v1 仍旧援用 a,然而 a 当初的值是 2;

pi=&b; //pi 指向 b,a 没有扭转

答案

指针和援用次要有以下区别:

  • 援用必须被初始化,然而不调配存储空间。指针不申明时初始化,在初始化的时候须要调配存储空间。
  • 援用初始化当前不能被扭转,指针能够扭转所指的对象。
  • 不存在指向空值的援用,然而存在指向空值的指针。

留神:援用作为函数参数时,会引发肯定的问题,因为让援用作为参数,目标就是想扭转这个援用所指向地址的内容,而函数调用时传入的是实参,看不出函数的参数是失常变量,还是援用,因而可能会引发谬误。所以应用时肯定要小心谨慎。

退出移动版