共计 4470 个字符,预计需要花费 12 分钟才能阅读完成。
C 和 C ++ 的区别
- C 语言是一种结构化语言,其偏重于数据结构和算法,属于过程性语言
- 尽管在语法上 C ++ 齐全兼容 C 语言,然而两者还是有很多不同之处。上面将具体解说 C 和 C ++ 不同之处的常见考题
关键字 static 在 C 和 C ++ 区别
C 和 C ++ 中都有关键字 static 关键字,那么 static 关键字在 C 和 C ++ 中的应用有什么区别?请简述之。
剖析问题:在 C 中,用 static 润饰的变量或函数,次要用来阐明这个变量或函数只能在本文件代码块中拜访,而文件内部的代码无权拜访。并且 static 润饰的变量寄存在段存储区。次要有以下两种用处。
- 定义部分动态变量
- 部分动态变量存储在动态存储区,在程序运行期间都不会开释,只在申明时进行初始化,而且只能初始化一次,如果没有初始化,其主动初始化为 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 自身。赋值之后,两个援用还是指向各自的原来对象,如图下图。
援用间赋值
- 指针能够被从新赋值以指向另一个不同的对象。然而援用则总是指向在初始化时被指定的对象,当前不能扭转。如下所示:
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 没有扭转
答案
指针和援用次要有以下区别:
- 援用必须被初始化,然而不调配存储空间。指针不申明时初始化,在初始化的时候须要调配存储空间。
- 援用初始化当前不能被扭转,指针能够扭转所指的对象。
- 不存在指向空值的援用,然而存在指向空值的指针。
留神:援用作为函数参数时,会引发肯定的问题,因为让援用作为参数,目标就是想扭转这个援用所指向地址的内容,而函数调用时传入的是实参,看不出函数的参数是失常变量,还是援用,因而可能会引发谬误。所以应用时肯定要小心谨慎。