C和C++的区别详解

目录

  • 通过程序来介绍
    • 1.iostream文件
    • 2.头文件名的区别
      • C语言
      • C++
    • 3.名称空间namespace
      • 封装性
    • 4.使用cout进行C++的输出
    • 指针和数组名的区别
      • 反汇编查看区别
        • 结论
          • 解引用
            • 结论
        • const的区别
          • C语言中为常变量
            • C++中的const
              • 声明时const位置不同的区别
                • const修饰形参
                  • 引用的原理
              • 引用变量
                • 常问问题
                • 动态申请空间的区别
                  • C语言
                    • C++
                    • 面向过程和面向对象
                      • C语言
                        • C++
                        • 总结

                          通过程序来介绍
                          //c++ program#includeusing namespace std; int main(void){ cout << "This is a c++ program." << endl; return 0; }


                          1.iostream文件
                          iostream中的io指的是输入(进入程序的信息)和输出(从程序中发送出去的信息)。

                          并且c++的输入、输出方案涉及iostream文件中的多个定义。比如用来输出信息的cout就在其中。

                          2.头文件名的区别

                          C语言 C语言的传统是头文件使用扩展名 h,将其作为一种通过名称标识文件类型的简单方式。例如 math.h支持一些数学函数。

                          C++ C++头文件没有扩展名。
                          有些C头文件被转换成C++头文件,这些文件被重新命名,去掉了扩展名h,并在文件名称前面加上前缀c(表示来自C语言)

                          3.名称空间namespace
                          如果使用的是iostream,而不是iostream.h,则应使用名称空间编译指令来使iostream中的定义对程序可用,即
                          using namespace std;

                          有了这句using编译指令,才能使用cout、cin等,或者用第二种方式:
                          using std::cout; using std::cin; using std::endl;

                          名称空间是C++的特性之一,简单理解为:可以将自己的产品封装起来。

                          示例

                          封装性 示例:

                          首先定义一个头文件

                          C和C++的区别详解
                          文章图片

                          在里面写上我们自己编的东西:
                          #pragma oncenamespace AA{ typedef int INT; typename char CHAR; };

                          然后在cpp文件中引入该头文件,但我们却无法使用之前写好的东西。

                          C和C++的区别详解
                          文章图片

                          INT a会报错,因为我们只引入了头文件,没有使用里面的名称空间。

                          正确做法:
                          //c++ program#include#include"AA.h"using namespace std; using namespace AA; //using AA::INT; int main(void){ INT a = 10; cout << a << endl; return 0; }

                          需要第六行的该名称空间才可以使用其中的产品。或者可以用第七行这种写法来确定自己只需要哪个产品。

                          运行结果:

                          C和C++的区别详解
                          文章图片


                          4.使用cout进行C++的输出
                          上面的程序有这条C++语句:
                          cout << "This is a C++ program." << endl;

                          <<符号表示该语句将把这个字符串发送给cout,该符号指出了信息流动路径。 cout是一个预定义的对象。
                          从概念上看,输出是一个流,即从程序流出的一系列字符。cout对象表示这种流,其属性是在iostream文件中定义的。
                          cout的对象属性包括一个插入运算符(<<),它可以将其右侧的信息插入到流中。
                          图示

                          C和C++的区别详解
                          文章图片


                          指针和数组名的区别 程序示例:
                          #includeusing namespace std; int main(void){ int a = 10; int* p = &a; int arr[] = { 0,1,2,3,4 }; cout << p << endl; cout << arr << endl; return 0; }

                          这里定义了一个指针p和一个数组arr。
                          运行结果都是地址

                          C和C++的区别详解
                          文章图片


                          反汇编查看区别
                          cout << p << endl;
                          cout << p << endl; 008F52AFmovesi,esp008F52B1pushoffset std::endl > (08F103Ch)008F52B6movedi,esp008F52B8moveax,dword ptr [p]008F52BBpusheax

                          cout << arr << endl;
                          cout << arr << endl; 008F52DEmovesi,esp008F52E0pushoffset std::endl > (08F103Ch)008F52E5movedi,esp008F52E7leaeax,[arr]008F52EApusheax

                          区别
                          C和C++的区别详解
                          文章图片

                          在输出指针时,需要先从p里面取出四字节,再放到寄存器里push;

                          在输出arr时,直接把arr放到寄存器里再push。

                          结论
                          指针是变量;

                          数组名是一个地址——常量。

                          解引用
                          在C语言中学到,对指针解引用后得到的值就是它寸的地址对应的变量值。

                          可以来探索原理

                          程序示例
                          #includeusing namespace std; int main(void){ int a = 10; int* p = &a; *p = 20; return 0; }

                          反汇编代码:
                          int a = 10; 000D18FFmovdword ptr [a],0Ah int* p = &a; 000D1906leaeax,[a]000D1909movdword ptr [p],eax *p = 20; 000D190Cmoveax,dword ptr [p]000D190Fmovdword ptr [eax],14h

                          对于*p = 20

                          先从p的内存中取四个字节,即变量a的地址放入寄存器,再将20给到寄存器所存的的四字节中。完成对变量a的改变。
                          所以解引用的意思就是从地址中把值取出来,这里是去p的地址里取出所存的变量a的地址。
                          程序示例2:
                          #includeusing namespace std; int main(void){ int a = 10, b = 20; int* p = &a; b = *p; return 0; }

                          反汇编代码:
                          int a = 10, b = 20; 000818FFmovdword ptr [a],0Ah00081906movdword ptr [b],14h int* p = &a; 0008190Dleaeax,[a]00081910movdword ptr [p],eax b = *p; 00081913moveax,dword ptr [p]00081916movecx,dword ptr [eax]00081918movdword ptr [b],ecx

                          对于 b = *p;
                          1.先去p里取出四字节放入寄存器
                          2.再从寄存器eax取出四字节放入寄存器ecx再把ecx
                          3.的内容放入到变量b的四字节中。
                          也可以看出:解引用这一步其实是去地址里取值的。
                          这样也可以得出:用一个变量赋值给另一个变量,其实也是在解引用。

                          示例:
                          #includeusing namespace std; int main(void){ int a = 10; int b; b = a; return 0; }

                          反汇编:
                          int a = 10; 002D18F5movdword ptr [a],0Ah int b; b = a; 002D18FCmoveax,dword ptr [a]002D18FFmovdword ptr [b],eax

                          对于 b = a;

                          也是从a地址里取出四字节放到寄存器,再通过寄存器给入b。

                          结论 解引用:到地址里去取值。

                          const的区别
                          C语言中为常变量
                          示例:
                          //const#includeint main(void){ const int a = 10; int b = 100; //常量赋值 b = a; //常变量赋值 return 0; }

                          两次赋值的区别:
                          const int a = 10; 00311825movdword ptr [a],0Ah int b = 100; 0031182Cmovdword ptr [b],64h b = a; 00311833moveax,dword ptr [a]00311836movdword ptr [b],eax

                          常量赋值时,是直接把值给到b的四字节中;

                          用const修饰的a赋值时,还是需要从a里取出四字节再赋给b。
                          所以C语言中const修饰的变量叫做常变量——不能作为左值。
                          甚至可以用指针改变它的值:
                          #includeint main(void){ const int a = 10; int b = 100; b = a; int* p = &a; *p = 20; return 0; }

                          a的变化:const修饰的变量a居然能被改变

                          【C和C++的区别详解】C和C++的区别详解
                          文章图片


                          C++中的const
                          在C++中,const修饰的变量就是常量,和常量性质一样:

                          在编译期间直接将常量的值替换到常量的使用点。
                          示例:
                          int main(void){ const int a = 10; int b, c; b = 16; c = a; return 0; }

                          反汇编代码:
                          const int a = 10; 00B917F5movdword ptr [a],0Ah int b, c; b = 16; 00B917FCmovdword ptr [b],10h c = a; 00B91803movdword ptr [c],0Ah

                          可以看出,对b赋值常量是直接赋值;

                          对c赋值const修饰的变量a,同样是用常量赋值的。所以:
                          在C++中, const修饰的变量和常量性质一样,都是在编译期将常量值替换到常量的使用点。
                          另外

                          1.而且const修饰的变量必须初始化,同样因为编译期间就会替换为常量,不初始化,后面也没有机会再对其赋值。

                          2.如果用变量对const修饰的变量赋值,则会使其退化成常变量。

                          声明时const位置不同的区别
                          示例:

                          const可在不同位置修饰变量
                          int main(void){ int a = 10; int* p1 = &a; const int* p2 = &a; int const* p3 = &a; int* const p4 = &a; int* q1 = &a; const int* q2 = &a; int const* q3 = &a; int* const q4 = &a; return 0; }

                          要注意的是:

                          const与离他最近的类型结合,是该变量的类型,除了最近的类型,剩下的就是const修饰的内容。
                          const修饰的内容是不可作为左值。
                          根据上面的原理,来判断以下内容:
                          p1 = q1; p1 = q2; p1 = q3; p1 = q4; p2 = q1; p2 = q2; p2 = q3; p2 = q4; p3 = q1; p3 = q2; p3 = q3; p3 = q4; p4 = q1; p4 = q2; p4 = q3; p4 = q4;

                          p1是普通指针。
                          对于

                          const int* p2和int const* p3

                          const修饰的类型是离他最近的类型,即int,剩下的为const所修饰的内容,所以它们两个所修饰的内容为 *p2 、*p3。
                          对于int* const p4

                          const修饰的类型为int*,那修饰的内容就是p4。
                          下面的四个q同理。
                          可以推出错误的是:
                          p1 = q2; p1 = q3; p4 = q1; p4 = q2; p4 = q3; p4 = q4;

                          因为 *q2 和 *q3不能改变,所以把 q2/q3赋值给普通指针时,会造成普通指针来改变其中内容的后果,即 泄露常量地址给非常量指针 ,所以不能这样赋值。
                          p4为const修饰的内容,不能被改变。

                          const修饰形参
                          这里主要说能否形成函数重载的问题

                          程序示例:
                          int fun(int a){ return a; }int fun(const int a){ return a; }

                          编译器并没有报错,但编译无法通过,原因如下

                          C和C++的区别详解
                          文章图片

                          结论:如果const修饰的内容不包括指针,则不参与类型问题。

                          引用变量 之前C语言学到,&符号用来指示变量的地址。

                          C++给该符号赋予了另一个含义,将其用来声明引用。
                          示例,若我想用 A作为变量 a的别名,可以这样用:
                          #includeusing namespace std; int main(void){ int a = 10; int& A = a; A = 20; cout << a << endl; cout << A << endl; return 0; }

                          运行示例:

                          C和C++的区别详解
                          文章图片

                          通过A可以改变a的值,这就是引用。A相当于a的别名,就和鲁迅和周树人一样。。。

                          引用的原理 示例:
                          int a = 10; int& A = a; int* p = &a;

                          反汇编代码:
                          int& A = a; 00ED5326leaeax,[a]00ED5329movdword ptr [A],eax int* p = &a; 00ED532Cleaeax,[a]00ED532Fmovdword ptr [p],eax

                          可以看出:引用的实现居然和指针是一样的。

                          所以引用的底层是一个指针。
                          结论:在使用到引用的地方,编译期会自动替换成底层指针的解引用。

                          常问问题
                          1.引用为什么必须初始化?
                          2.引用为什么一经过初始化,就无法改变引用的方向?
                          答:因为只有在初始化的时候能给它赋值,其他使用到它的地方都替换成了底层指针

                          无法改变底层指针的指向,所以无法改变引用的方向。
                          3.不能将const限定的变量赋给普通引用变量:
                          原因是将常量的地址赋给了普通指针。
                          const int a = 10; int& b = a; //错误

                          4.当引用一个不可以取地址的量的时候,使用常引用。
                          会生成一个临时量,然后常引用临时量,临时量都有常属性。

                          示例:
                          int& a = 10; //错误const int& a = 10; //正确


                          动态申请空间的区别

                          C语言
                          使用malloc和free

                          示例:
                          int main(void){ //申请一维数组与释放 int* arr = (int*)malloc(sizeof(int) * 10); if (arr == NULL)return -1; free(arr); //申请二维数组与释放 int** brr = (int**)malloc(sizeof(int*) * 10); if (brr == NULL)return -1; for (int i = 0; i < 10; ++i) {free(brr[i]); } return 0; }



                          C++
                          int main(void){ //申请int类型变量 int* p = new int; *p = 10; delete p; //申请int类型数组 int* arr = new int[10]; arr[0] = 10; delete[]arr; //申请二维数组 int** brr = new int* [5]; for (int i = 0; i < 5; ++i) {brr[i] = new int[10]; } for (int i = 0; i < 5; ++i) {delete[]brr[i]; } return 0; }

                          new后面跟的类型就表示申请的大小。

                          面向过程和面向对象 C语言
                          面向过程语言
                          示例
                          void echo(){ if (flag == 0) {printf("printf screen\n"); } else if (flag == 1) {printf("printf file\n"); }}void Set_flag_file(){ flag = 1; }void Set_flag_screen(){ flag = 0; }

                          对于这个打印函数,可以通过改变flag的值来控制其打印的结果。

                          但如果改变flag,也会改变其他地方调用的打印函数的结果。

                          所以C语言没有封装性。
                          C++
                          面向对象语言
                          class Note{public: Note() {flag = 0; } void echo() {if (flag == 0){printf("printf screen\n"); }else if (flag == 1){printf("printf file\n"); } } void Set_flag_file() {flag = 1; } void Set_flag_screen() {flag = 0; }private: int flag; };

                          使用示例:
                          int main(void){ Note n; n.echo(); n.Set_flag_file(); n.echo(); return 0; }

                          运行结果:

                          C和C++的区别详解
                          文章图片

                          C语言作为面向过程语言,如果示例中的flag做出改变,会影响全局的改变。

                          C++作为半面向对象语言,具有封装性,若想改变示例中想打印的值,只会影响到这个模块。

                          总结 本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

                            推荐阅读