广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C和C++的区别详解
  • 743
分享到

C和C++的区别详解

2024-04-02 19:04:59 743人浏览 独家记忆
摘要

目录通过程序来介绍1.iOStream文件2.头文件名的区别C语言c++3.名称空间namespace封装性4.使用cout进行C++的输出指针和数组名的区别反汇编查看区别结论解引用

通过程序来介绍


//c++ program
#include<iostream>
using 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++的特性之一,简单理解为:可以将自己的产品封装起来。

示例

封装性

示例:

首先定义一个头文件

在这里插入图片描述

在里面写上我们自己编的东西:


#pragma once
namespace AA
{
	typedef int INT;
	typename char CHAR;
};

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

在这里插入图片描述

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

正确做法:


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

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

运行结果:

在这里插入图片描述

4.使用cout进行C++的输出

上面的程序有这条C++语句:


	cout << "This is a C++ program." << endl;

<<符号表示该语句将把这个字符串发送给cout,该符号指出了信息流动路径。 cout是一个预定义的对象。

从概念上看,输出是一个流,即从程序流出的一系列字符。cout对象表示这种流,其属性是在iostream文件中定义的。
cout的对象属性包括一个插入运算符(<<),它可以将其右侧的信息插入到流中。

图示

在这里插入图片描述

指针和数组名的区别

程序示例:


#include<iostream>
using 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。

运行结果都是地址

在这里插入图片描述

反汇编查看区别

cout << p << endl;


	cout << p << endl;
008F52AF  mov         esi,esp  
008F52B1  push        offset std::endl<char,std::char_traits<char> > (08F103Ch)  
008F52B6  mov         edi,esp  
008F52B8  mov         eax,dWord ptr [p]  
008F52BB  push        eax 

cout << arr << endl;


	cout << arr << endl;
008F52DE  mov         esi,esp  
008F52E0  push        offset std::endl<char,std::char_traits<char> > (08F103Ch)  
008F52E5  mov         edi,esp  
008F52E7  lea         eax,[arr]  
008F52EA  push        eax

区别

在这里插入图片描述

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

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

结论

指针是变量;

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

解引用

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

可以来探索原理

程序示例


#include<iostream>
using namespace std;
int main(void)
{
	int a = 10;
	int* p = &a;
	*p = 20;
	return 0;
}

反汇编代码:


	int a = 10;
000D18FF  mov         dword ptr [a],0Ah  
	int* p = &a;
000D1906  lea         eax,[a]  
000D1909  mov         dword ptr [p],eax  
	*p = 20;
000D190C  mov         eax,dword ptr [p]  
000D190F  mov         dword ptr [eax],14h  

对于*p = 20

先从p的内存中取四个字节,即变量a的地址放入寄存器,再将20给到寄存器所存的的四字节中。完成对变量a的改变。

所以解引用的意思就是从地址中把值取出来,这里是去p的地址里取出所存的变量a的地址。

程序示例2:


#include<iostream>
using namespace std;
int main(void)
{
	int a = 10, b = 20;
	int* p = &a;
	b = *p;
	return 0;
}

反汇编代码:


	int a = 10, b = 20;
000818FF  mov         dword ptr [a],0Ah  
00081906  mov         dword ptr [b],14h  
	int* p = &a;
0008190D  lea         eax,[a]  
00081910  mov         dword ptr [p],eax  
	b = *p;
00081913  mov         eax,dword ptr [p]  
00081916  mov         ecx,dword ptr [eax]  
00081918  mov         dword ptr [b],ecx  

对于 b = *p;

1.先去p里取出四字节放入寄存器

2.再从寄存器eax取出四字节放入寄存器ecx再把ecx

3.的内容放入到变量b的四字节中。

也可以看出:解引用这一步其实是去地址里取值的。

这样也可以得出:用一个变量赋值给另一个变量,其实也是在解引用

示例:


#include<iostream>
using namespace std;
int main(void)
{
	int a = 10;
	int b;
	b = a;
	return 0;
}

反汇编:


	int a = 10;
002D18F5  mov         dword ptr [a],0Ah  
	int b;
	b = a;
002D18FC  mov         eax,dword ptr [a]  
002D18FF  mov         dword ptr [b],eax  

对于 b = a;

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

结论

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

const的区别

C语言中为常变量

示例:


//const
#include<stdio.h>
int main(void)
{
	const int a = 10;
	int b = 100; //常量赋值
	b = a; //常变量赋值
	return 0;
}

两次赋值的区别:


	const int a = 10;
00311825  mov         dword ptr [a],0Ah  
	int b = 100;
0031182C  mov         dword ptr [b],64h  
	b = a;
00311833  mov         eax,dword ptr [a]  
00311836  mov         dword ptr [b],eax 

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

用const修饰的a赋值时,还是需要从a里取出四字节再赋给b。

所以C语言中const修饰的变量叫做常变量——不能作为左值。

甚至可以用指针改变它的值:


#include<stdio.h>
int main(void)
{
	const int a = 10;
	int b = 100;
	b = a;
	int* p = &a;
	*p = 20;
	return 0;
}

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

在这里插入图片描述

C++中的const

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

在编译期间直接将常量的值替换到常量的使用点。

示例:


int main(void)
{
	const int a = 10;
	int b, c;
	b = 16;
	c = a;
	return 0;
}

反汇编代码:


	const int a = 10;
00B917F5  mov         dword ptr [a],0Ah  
	int b, c;
	b = 16;
00B917FC  mov         dword ptr [b],10h  
	c = a;
00B91803  mov         dword 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;
}

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

在这里插入图片描述

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

引用变量

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

C++给该符号赋予了另一个含义,将其用来声明引用。

示例,若我想用 A作为变量 a的别名,可以这样用:


#include<iostream>
using namespace std;
int main(void)
{
	int a = 10;
	int& A = a;
	A = 20;
	cout << a << endl;
	cout << A << endl;
	return 0;
}

运行示例:

在这里插入图片描述

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

引用的原理

示例:


int a = 10;
	int& A = a;
	int* p = &a;

反汇编代码:


	int& A = a;
00ED5326  lea         eax,[a]  
00ED5329  mov         dword ptr [A],eax  
	int* p = &a;
00ED532C  lea         eax,[a]  
00ED532F  mov         dword 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语言作为面向过程语言,如果示例中的flag做出改变,会影响全局的改变。

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

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: C和C++的区别详解

本文链接: https://www.lsjlt.com/news/137607.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C和C++的区别详解
    目录通过程序来介绍1.iostream文件2.头文件名的区别C语言C++3.名称空间namespace封装性4.使用cout进行C++的输出指针和数组名的区别反汇编查看区别结论解引用...
    99+
    2022-11-12
  • C++和C中const的区别详解
    目录C中的constconst修饰局部变量const修饰全局变量const修饰的全局变量有外部链接属性const与指针C++中的constconst修饰普通全局变量const修饰普通...
    99+
    2022-11-12
  • 详解C++中typedef 和 #define 的区别
    1、执行上不同 关键字 typedef 在编译阶段有效,由于是在编译阶段,因此 typedef 有类型检查的功能。 #define 则是宏定义,发生在预处理阶段,也就是编译之前,它只...
    99+
    2022-11-12
  • C++中的struct和class的区别详解
    目录1. C++的struct和class的区别1.1 成员访问范围的差异structclass1.1 继承关系访问范围的差异struct : structstruct : clas...
    99+
    2022-11-13
    C++中的struct C++中的class struct和class的区别
  • C++中左值和右值的区别详解
    目录左值右值定义:特性左值引用, 右值引用总结左值右值定义: 左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式). ...
    99+
    2022-11-13
  • 如何理解C++和C#、Java的区别
    本篇文章给大家分享的是有关如何理解C++和C#、Java的区别,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。作为比C语言更简捷的语言,C++语言提供了更好的机制来增强程序的安全...
    99+
    2023-06-17
  • C#中struct与class的区别详解
    目录1.最大的区别2.struct成员无法被声明为protected。3.struct是隐式的sealed类4.struct中无法重载默认构造函数5.关于对象的初始化6.结构体没有析...
    99+
    2022-11-13
  • C语言形参和实参的区别详解
    目录形参和实参的定义形参和实参的作用形参和实参的传递方式传值调用指针调用形参和实参的默认值总结C语言是一种高级编程语言,其最重要的特点之一是它允许程序员使用函数来组织代码。函数是一组...
    99+
    2023-05-20
    C语言 形参 实参
  • C语言malloc与calloc区别详解
    目录区别用法malloc用法calloc用法区别 开门见山,malloc与calloc在内存分配时,前者分配一整块,后者分配n块,并且后者在分配时会将内存置为0,前者不会内存里是垃圾...
    99+
    2023-01-13
    C语言 malloc calloc C语言 malloc C语言 calloc
  • 解析C/C++值传递和址传递的区别
    C/C++的按值传递和按地址传递有明显不同,下面对他们作个区别: 按值传递:在调用函数中将原函数的值拷贝一份过去被调用的函数,在被调用函数中对该值的修改不会影响原函数的值。 按地址传...
    99+
    2022-11-12
  • C++中overload,override,overwrite的区别详细解析
    Overload(重载):在C++程序中,可以将语义、功能相似的几个函数用同一个名字表示,但参数或返回值不同(包括类型、顺序不同),即函数重载。(1)相同的范围(在同一个类中);(2...
    99+
    2022-11-15
    overload override overwrite
  • 详解C#中delegate/event/EventHandler/Action/Func的使用和区别
    目录1 委托2 事件-概念的引出3 事件-关于异常4 事件-关于异步5 委托-Func与Action1 委托 在.NET中定义“委...
    99+
    2023-05-14
    C# delegate C# event C# EventHandler C# Action C# Func
  • C语言中宏和函数的9个区别详解
    目录1.代码长度2.执行速度3.操作符优先级4.带有副作用的参数5.参数类型6.调试7.递归8.命名约定9.其他总结C语言中的宏和函数是非常相似的,它们都可以完成类似的功能。比如,想...
    99+
    2023-05-14
    C语言 函数区别 C语言 函数 C语言 C语言 函数
  • 详解C++ STL vector容量(capacity)和大小(size)的区别
    很多初学者分不清楚 vector 容器的容量(capacity)和大小(size)之间的区别,甚至有人认为它们表达的是一个意思。本节将对 vector 容量和大小各自的含义做一个详细...
    99+
    2022-11-12
  • C语言中break与continue的用法和区别详解
    目录前言一、循环体中两者的作用1.while循环2.for循环3.do while循环二、switch语句总结前言 本文将通过简单的实例来详细分析在C语言中break语句和conti...
    99+
    2022-11-12
  • 详解C语言中typedef和#define的用法与区别
    目录一、typedef的用法二、#define的用法三、typedef与#define的区别四、typedef的用途用途一用途二用途三用途四五、typedef的陷阱陷阱一陷阱二一、t...
    99+
    2022-11-13
  • C语言中.c和.h文件区别讲解
    C语言中.h和.c文件解析     简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程: ...
    99+
    2022-11-12
  • C++sleep()和usleep()的区别
    sleep() 和 usleep()主要区别前者单位为秒,后者为微妙(*1e6) C++ sleep() 和 usleep() 代码如下:设置一个时间参数,分别向sleep()和us...
    99+
    2023-03-09
    C++ sleep() usleep()
  • C++和C中const的区别是什么
    本篇内容介绍了“C++和C中const的区别是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!const,这个词字面意思为:常数。这就表示...
    99+
    2023-06-21
  • C++指针与引用的区别案例详解
    C++中指针和引用的区别 从概念上讲。指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。 而引用是...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作