网站首页 > 技术文章 正文
C语言与C++之间的区别
一、C++基于过程的程序设计
1、简单程序实例
example 1:
#include <iostream> using namespace std; int main() { int max(int x, int y);//函数的声明 int a,b,c; cin>>a>>b; c = max(a, b); cout<<"max = "<<c<<endl; return 0; } int max(int x, int y) { int z; if(x > y) z = x; else z = y; return z; }
main函数必须声明为int型,因为操作系统要求执行一个程序后必须向操作系统返回一个数值:如果程序正常执行,则向操作系统返回数值0;否则返回数值-1;
函数体是由”{}”括起来的;
cout是C++系统定义的对象名,称为输出流对象;cin为输入流对象(输入时两个数据间用一个或多个空格间隔,不能以逗号或其他符号间隔);
“#include < iostream >” 是C++的一个预处理指令,是一个包含指令,作用是把文件”iostream”中的内容包含到该命令所在的程序文件中,代替该指令;
“using namespace std“的意思是使用命名空间”std”,C++标准库中的类和函数是在命名空间std中声明的;
“//”代表从它开始到本行末尾之间的全部内容都作为注释,同时对于多行注释也可以用”/ …… /”来表示;
程序第5行是对max函数的声明,声明过后max函数可以写在main函数后面;
2、C++程序的实现过程
每一个程序单位由以下三部分组成:预处理指令、全局声明、函数
3、变量
3.1 变量基础
变量属于标识符。标识符指用来标识变量、函数、数组、类型等实体名字的有效字符序列;
变量名代表内存中的一个存储单元。当程序从变量中取值时,实际是通过变量名找到相应的内存单元,从其中读取数据;
变量具有两种属性:作用域(全局变量或局部变量)、存储期(静态存储期或动态存储期)
变量的命名规则:
只能由字母、数字、下划线3种字符组成;
第一个字符必须为字母或者下划线;
常变量又称为只读变量:
相当于在此变量的基础上加上一个限定:存储单元中的值不允许变化;
区别使用#define指令定义的符号常量和用const定义的常变量:
3.2 局部变量与全局变量
局部变量
在一个函数内部定义的变量,它只在本函数或复合语句范围内有效
形参也是局部变量
在函数原型声明中出现的参数名,只在原型声明中的括号范围内有效
全局变量
在函数外定义的变量是外部变量,称为全局变量,其有效范围为从定义变量的位置开始到本源文件结束
如果在一个函数中改变了全局变量的值,就能影响到其他函数,使其他函数中引用的同名变量也同时改变
建议不在必要时不要使用全局变量(占用存储单元、函数通用性降低)
3.3 变量的存储类别
静态存储方式
在程序运行期间,系统对变量分配固定的存储空间
静态存储区中存放全局变量
动态存储方式
在程序运行期间,系统对变量动态地分配存储空间
动态存储区中存放:函数形式参数、函数中定义的变量(未加static的局部变量)、函数调用时的现场保护和返回地址等
变量的存储类别
指数据在内存中的存储方式
包括自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)
自动变量:函数中的局部变量,如果不加static声明,编译系统动态分配存储空间
静态局部变量:函数中的局部变量的值在调用结束后不消失而保留原值,即其占用的存储单元不释放,下次调用该函数时,该变量保留上一次调用结束时的值。
虽然静态局部变量在函数调用后仍然存在,但其他函数不能引用它,在其他函数中不可见
静态局部变量是在编译时赋初值的(默认为0或空字符),而自动变量赋初值是在函数调用时进行
寄存器变量:需要时直接从寄存器中取出参与运算,不必到内存中存取
全局变量或外部变量:在函数外部定义的,作用域为从函数定义处开始到本程序文件末尾
extern只是对一个已定义的外部变量做声明,以拓展作用域
当使用static在定义外部变量时进行声明,则此外部变量只限于本文件引用,而不能被其他文件引用(静态外部变量)
3.4 变量的声明与定义
函数的声明是函数的原型,函数的定义时函数功能的确立
声明分为定义性声明(需要建立存储空间,eg:int a;)和引用性声明(不需要建立存储空间,eg:extern int a;)
广义来说声明包括定义,不过为了叙述方便,把建立存储空间的声明称为定义,而把不需要建立存储空间的声明称为声明
4、运算符
运算符种类
算数运算符:+、-、*、/、%、++、–
关系运算符:>、<、==、>=、<=、!=
逻辑运算符:&&、||、!
位运算符:<<(按位左移)、>>(按位右移)、&、|、^(按位异或)、~(按位取反)
赋值运算符:=及其拓展赋值运算符
条件运算符:?:
逗号运算符:,
指针运算符:*
引用运算符和地址运算符:&
求字节数运算符:sizeof
强制类型转换运算符
成员运算符:.
指向成员的运算符:->
下标运算符:[]
其他:函数调用运算符
运算符的优先级:!>算数运算符(带有”<”或”>”号的优先级大于”==”和”!=”)>关系运算符>&&和||>赋值运算符
进行运算时不同类型的数据需要转为同一类型,转换规则为如下所示。其中横向向左的箭头表示必定转换;纵向的箭头表示当运算对象为不同类型时的转换方向, 箭头的方向只表示数据类型级别的高低,由低向高转换。
A[char,short] ==> B(int) B --> C[unsigned] C --> D[long] D --> E[double] F[float] --> E
自增和自减运算符:++i(在使用i之前,先使i的值加1)、i++(在使用i之后,i的值加1)、–i(在使用i之前,先使i的值减1)、(在使用i之后,i的值减1)
赋值运算符:如果赋值运算符两侧类型不一致,但都是数值型或者字符型时,在赋值时自动进行类型转换
double赋值给float时,要注意数值范围不能溢出
字符型赋值给整形时,将字符的ASCII码赋给整形
将int,short或long型数据赋给一个char型变量,只将其低8位原封不动地送到char型变量(发生截断)
不同类型整型数据间的赋值归根到底就是一条:按存储单元中的存储形式直接传送
条件运算符(唯一一个三目运算符):
eg:max = (a>b)? a: b;
5 程序结构
5.1 选择结构
if()...else if()...else
多分支选择结构:switch() {case x: ...;case y: ...;default :...}
各个case和default出现的次序不影响执行结果
在执行switch语句时,根据switch表达式的值找到与之匹配的case子句,就从此case子句开始执行下去,不再进行判断,所以此时需要”break“语句来达到跳出的目的
多个case可以共用一组执行语句
5.2 循环结构
while(表达式)语句
do 表达式 while(表达式)(do-while语句)
for(表达式1;表达式2;表达式3)语句
可以只用”break“或”continue”跳出循环或跳出本次循环
6、函数
6.1 函数的分类
用户使用的角度:
系统函数,即库函数
用户自己定义的函数
函数形式:
无参函数
有参函数
6.2 函数的定义
/* 类型名 函数名([void]) { 声明部分 执行语句 } */
/* 类型名 函数名([void]) { 声明部分 执行语句 } */
6.3 函数的参数
6.4 函数的调用
调用的方式
函数语句函数表达式
函数参数
printstar(); //函数语句 c = 2 * max(a,b);//函数表达式 m = max(a, sqrt(b));//函数参数
函数调用时注意,当实参列表包括多个实参时,对实参的求值顺序并不是确定的。许多C++系统是按照从右至左的顺序求值。比如,若变量i的值为3时:
func(i, ++i); /*func(3,4),从左至右顺序求值 func(4,4),从右至左顺序求值*/
6.4 函数的声明与函数原型
函数声明是指函数尚未定义的情况下,事先将函数的有关信息通知编译系统,以便编译可以正常进行。
函数声明中可以不写形参名,只写形参类型,这种声明成为函数原型
float add(float, float);//函数原型
/*函数类型 函数名(参数类型1, 参数类型2...);
函数类型 函数名(参数类型1 参数名1, 参数类型2 参数名2...);
6.5 内置函数(内联函数)
编译时将函数代码嵌套到主调函数中,而不是将流程转出去
可以在声明函数和定义函数同时写inline;也可以只在函数声明时加inline,而定义时不加
内联函数中不能包括复杂的控制语句,如循环和switch语句
6.6 函数的重载
C++允许同一个函数名定义多个函数,而这些函数的参数个数和参数类型可以不相同
不允许只有函数的类型不同而参数的个数和类型相同,如:
int f(int); long f(int); void f(int);
6.7 函数模板
- 建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表
- 定义函数模板的一般形式:
template <typename T>//T为类型参数;typename也可以用class代替,都表示类型名 T max(T a, T b, T c) { if(b>a) a = b; if(c>a) a = c; return a; }
只适用于函数体相同、函数参数个数相同而类型不同的情况
6.8 有默认参数的函数
指定默认值的参数必须防止形参列表的最右端
如果函数的定义在函数调用之前,则应在函数定义中给出默认值;如果函数的定义在函数调用之后,则在函数调用之前需要有函数声明,此时必须在函数声明中给出默认值,在函数定义时可以不给默认值
一个函数不能既作为重载函数,又作为有默认参数的函数
6.9 内部函数和外部函数
内部函数:只能被本文件中其他函数调用
static 类型标识符 函数名(形参表)
外部函数:可以供其他文件调用
extern int func(int a, int b)//省略extern,默认为外部函数
6.10 函数参数的传递
将变量名作为实参和形参:形参是变量的值,传递是单向的
void swap(int a, int b); int i = 3, j = 5; swap(i, j);//调用函数时,形参和实参不是同一个存储单元。值传递(传值方式)
传递变量的地址:形参是实参变量的指针变量(地址),实参是一个变量的地址
void swap(int *p1, int *p2); int i = 3, j = 5; swap(&i, &j);//值传递(传值方式),实参的值是变量的地址
形参为实参的引用:以引用作为形参,使形参名作为实参的引用
void swap(int &a, int &b); int i = 3, j = 5; swap(i, j);//地址传递传递(传址方式),实参是变量名,而传递的是变量的地址
7、数组
7.1数组的定义与引用
类型名 数组名[常量表达式]//一维数组的定义
数组名[下标]//一维数组的引用
类型名 数组名[常量表达式][常量表达式]//二维数组的定义
数组名[下标][下标]//二维数组的引用
二维数组元素排列顺序为:按行存放,即在内存中先顺序存放第1行元素,再存放第2行元素
多维数组元素在内存中的排列顺序:第一维的下标变化最慢,最右边的下标变化最快
7.2用数组做函数参数
数组元素可以做函数参数,用法与变量相同,传递数组元素的值;数组名也可以做实参和形参,传递的是数组的起始地址,C++实际上把形参数组名作为一个指针变量来处处理
/*...*/ void select_sort(int array[], int n);//函数 int a[10]; select_sort(a,10);//调用函数 /*...*/ void select_sort(int array[], int n)//函数定义 { /*...*/ }
/*...*/
void select_sort(int array[], int n);//函数
int a[10];
select_sort(a,10);//调用函数
/*...*/
void select_sort(int array[], int n)//函数定义
{
/*...*/
}
7.3 字符数组
7.3.1 字符数组基础
char c[5]; c = {'C', 'h', 'i', 'n', 'a'};//错误 c[0] = 'C'; c[1] = 'h'; c[2] = 'i'; c[3] = 'n'; c[4] = 'a';//正确 char str[] = {"I am happy"};//正确,使用字符串常量初始化字符数组 char str[] = "I am happy";//正确
字符串结束标志:遇到字符'\0'表示字符串结束。对一个字符串常量,系统自动在所有字符后加'\0'作为结束符。程序中检测字符串长度也依靠字符串结束标志
如果输入字符串长于字符数组的长度,此时系统并不报错,而是将多余的字符元素顺序地存放到所定义字符数组后面的几个字节中,有可能破坏其他数据,甚至出现无法估计的后果
7.3.2 字符串处理函数
strcat(char[], const char[]);
strcpy(char[], const char[]); strcpy(str1, str2, 2);//将str2中前2个字符复制到str1中 str1 = str2;//错误,不能将字符数组直接赋值给另一个字符数组
strcmp(const char[], const char[]); /*如果字符串1等于字符串2,函数值为0 如果字符串1大于字符串2,函数值为一正整数 如果字符串1小于字符串2,函数值为一负整数*/
strlen(const char[]);//其值为字符串实际长度,不包括'\0'
7.3.3 字符串类
- 将C++标准库中的string头文件包含进来
#include <string> string string1;//定义字符串变量 string1 = "China";//赋值
不要求每个字符串元素具有相同的长度,同一个元素长度也可以变化每个元素的值只包含字符串本身的字符,而不包括\0
8、指针
- 一个变量的地址称为该变量的指针
- 专门存放地址(即指针)的变量称为指针变量
- C++中“*”表示指向,比如i_pointer是一个指针变量,则*i_pointer表示i_pointer指向的变量
8.1 指针变量的定义与引用
基类型 * 指针变量名 /*基类型指指针变量指向的变量的类型 "*"表示定义的该变量为指针变量
int * pointer_1; int a = 100; pointer_1 = &a;//变量a的地址给pointer_1 int * pointer_2 = &a;//定义指针变量并初始化
p = &a; p = array;//数组 p = &array[i]; p = max;//函数 p1 = p2;
8.2 指针与函数
8.2.1 指针做函数参数
void swap(int * p1, int * p);//声明指针参数的函数 int * pointer_1, * pointer_2; swap(pointer_1, pointer_2);//调用函数 void swap(int * p1, int * p)//函数定义 { /*...*/ }
8.2.2 指向函数的指针变量
int max(int x, int y); int (*p)(int,int);//定义指向函数的指针变量 p = max;//指针p指向max函数的入口地址 m = p(a, b);
8.2.3 返回指针值的函数( )
//类型名 * 函数名(参数列表) int *a(int x, int y);
8.3 指针与数组
int a[10]; int * p; p = &a[0];//将a[0]地址赋给指针变量p p = a;//与上面等价 /*p+1指向同一个数组中的下一个元素,实际地址是p+1*d*/
8.4 指针与字符串
- 访问字符串:
- 用字符数组存放一个字符串
- 用字符串变量存放字符串
- 用字符指针指向一个字符串
char str1[] = "I love China!"; cout << str1 << endl; string str2 = "I love China!"; cout << str2 << endl; char * str3 = "I love China!"; cout << str3 << endl;
8.5 const指针和void指针
- 指向常量的指针变量:不允许通过指针变量改变它指向的对象的值,但是指针变量p的值(即p的指向)是可以改变的
const 类型名 * 指针变量名;//常用作函数形参,防止指针形参所指对象的值改变影响实参
类型名 * const 指针变量名;//必须在定义时初始化,指定其指向
const 类型名 * const 指针变量名;//必须在定义时初始化,指定其指向
void指针:指向空类型或不指向确定类型的数据,其为过渡型的
9、引用
相当于给一个变量起别名
在数据类型后面出现的&是引用声明符,在其他场合出现的都是地址符(出现在声明中的&是引用声明符,其他情况是地址运算符)
声明一个引用时,必须同时使之初始化,声明后不能再使之作为另一变量的引用
不能建立引用数组,不能建立引用的引用,不能建立引用的指针
引用机制主要是把它作为函数参数,以扩充函数传递数据的功能(传址方式)
10、用户自定义数据类型
结构体类型(structure)、共用体类型(union)、枚举类型(enumeration)、类类型(class)
10.1 结构体(struct)
结构体中在一个组合项中包含若干个类型不同(也可以相同)的数据项
10.1.1 结构体的声明、定义、初始化与引用
/*声明*/ struct 结构体类型名//声明 {成员表};//类型名 成员名 /*定义*/ struct Student {/*...*/}; Student student1, student2;//先声明再定义变量 struct Student {/*...*/}student1,student2;//声明(Student结构体)的同时定义变量(student1,student2) /*初始化*/ struct Student {/*...*/}student1 = {/*...*/}; struct Student {/*...*/}; Student student2 = {/*...*/}; /*引用*/ student1 = student2; student1.num = 10010;//结构体变量名.成员名("."是成员运算符, 优先级最高)
10.1.2 指向结构体变量的指针
/*以下三种形式等价*/ /*p为指向结构体变量的指针*/ /*结构体变量.成员名,eg:stu.num (*p).成员名,eg:(*p).num p->成员名(->为指向运算符),eg:p->num*/ p->n++;//得到成员n的值,用完后使它加1 ++p->n;//得到成员n的值,并使之加1,然后再使用它
10.1.3 结构体类型数据作为函数参数
- 用结构体变量名作参数
- 用指向结构体的指针作参数,将结构体变量的地址传给形参
- 用结构体变量的引用作函数参数,成为实参的别名
10.1.4 new和delete运算符进行动态分配撤销存储空间
new 类型[初值]//new分配数组空间时不能指定初值 new int(100);//初值为100的整数空间,返回存储空间的地址 new char[10]; new int[5][4]; float *p = new float(3.14159); delete 指针变量; delete [] 指针变量;
10.2 枚举类型(enum)
- 一个变量只能有集中可能的值,可以定义为枚举类型
- 枚举类型按常量处理,成为枚举常量,编译系统按定义时的顺序对它们赋值为0,1,2,3…
enum 枚举类型名 {枚举常量表}; enum weekday{sun, mon, tue, wed, thu, fri, sat};//声明枚举类型 weekday workday, week_end;//定义变量 enum weekday workday, week_end;//C语言定义方式 enum weekday{sun, mon, tue, wed, thu, fri, sat}workday, week_end;//声明同时进行定义 workday = (weekday)2;//C语言强制类型转换 workday = weekday(2);//C++强制类型转换
10.3 声明新类型(typedef)
- 使用typedef声明一个新的类型名类代替已有的类型名
- 也可以对一个结构体类型声明一个新的名字
typedef int INTERGER; typedef struct { int month; int day; int year; }DATE;//DATE为新类型名,而不是结构体变量 typedef int NUM[100];//声明NUM为整型数组类型,包含100个元素 typedef char * STRING;//声明STRING为char * 类型 typedef int (* POINTER)();//声明POINTER为指向返回整型的函数的指针类型
最后,如果你想学C/C++可以私信小编“01”获取素材资料以及开发工具和听课权限哦!
猜你喜欢
- 2024-10-18 了解C语言中的操作符(c语言操作符怎么定义)
- 2024-10-18 20天轻松入门《C++第二章——程序设计基础》—3经坛教育
- 2024-10-18 C++中的volatile关键字(volatile关键字 c语言)
- 2024-10-18 C/C++软件开发证书怎么考?报考难度大吗?含金量高吗?
- 2024-10-18 c++数据类型(c++数据类型转换)
- 2024-10-18 C语言中实现边沿函数算法及应用,这是抛弃PLC留下的痛!
- 2024-10-18 C基础、经典问题:交换a、b值较好的方法?
- 2024-10-18 C++ 避免使用模块重新编译模板库(调用c++模块,不忽略异常)
- 2024-10-18 面试大厂c/c++后台开发岗,如何从技术层面上杀出重围?
- 2024-10-18 关于C语言交换两个数的实现方法以及个人心得
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- sqlset (64)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)