C++学习笔记 C++语言基础

C++语言基础

1. 数据类型

  • 基本数据类型: 预定义好的数据类型
数据类型关键词字节数数值范围
字符型char1-128-127
整型int4-214783648-2147483647
单精度浮点型float4
双精度浮点型double8
长双精度浮点型long double10
布尔型bool1
无值型void0
  • 构造类型:枚举类型(enum),数组类型,结构体类型,共用体类型
  • 指针类型
  • 引用类型

2. 类型修饰符

  • signed : 有符号类型,修饰的类型值可以为正数或者负数
  • unsigned : 无符号类型,修饰的类型值只能为正数
  • short : 短型,修饰的类型值一定不大于对应的整数
  • long : 长型,修饰的类型值一定不小于对应的整数
  • 四种修饰符都可以用修饰整型和字符型

3. 常量

3.1 常量类型
  • 整型常量:
    • 十进制形式: 由数字0-9以及正负号组成.如果为long int 型常量,则需要在常量后加字母l/L eg.123L
    • 八进制形式: 以0开头的数字(0-7)序列
    • 十六进制形式: 以0x/0X开头的数字(0-9/a-f)序列
  • 浮点型常量
3.2 常量表示方法
  • 在程序中直接写入常量 : i = 20;
  • 使用#define定义宏常量 : #define 宏名 常数 eg.#define PI 3.14
  • 使用const定义正规常数 : const [数据类型标识符] 常数名 = 常量值; (如果省略了数据类型,一般默认是整型)

4. 变量

4.1 变量定义修饰符
  • volatile: 说明一种特殊的变量,其值可能随时变化.关键词volatile用于特殊的程序,是一个高级修饰符
  • register: 指明一类频繁使用的变量,这些变量放在计算机的寄存器中
  • static: 在函数体外被其修饰的变量只能由定义该变量的文件访问;在函数体内被其修饰的变量表示其是永久的,只被初始化一次
  • extern: 表示变量已经在其他文件中定义了,在此只是进行是说明
  • auto: 从堆栈中分配的变量,该关键词很少使用
4.2 定义变量的位置
定义位置变量名称作用范围
函数体内部定义局部变量定义该函数体的内部发挥作用
函数名后的括号中形式参数在函数中
在函数体外部定义全局变量在整个程序中发挥作用
4.2.1 区分局部变量和全局变量
  • 局部变量和全局变量同名时,使用域解析符"::"对隐藏的同名全局变量进行访问
    源程序
#include<iostream>
using namespace std;
int sum = 5050;  //定义全局变量 sum
int main()
{
	int arr[3], i; //定义局部变量,但是i的作用域不包括for循环体内
	{
		for (int i = 0; i < 3; i++)
		{
			cin >> arr[i];
		}
	}
	int sum = 0;  //定义局部变量,与全局变量同名
	for (i = 0; i < 3; i++)   //此处的i为函数开始定义的i
	{
		sum += arr[i];
	}
	for (i = 0; i < 3; i++)//此处的i为函数开始处定 义的i
	{
		cout << arr[i] << endl;
	}
	
	cout << " 局部sum = " << sum << endl;//输出局部变量
	::sum += sum;//域解析符对全局变量进行访问,赋值号右边sum为局部变量
	cout << " 全局sum = " << ::sum << endl;//输出全局变量sum的值
	 return 0;
}

运行结果
运行结果

5. const修饰符和指针的结合

  • 指向常量的指针: const 类型名*指针名;
    • const int *p;
    • 代码理解
#include<iostream>
using namespace std;
int main()
{
	int a = 666;
	int b = 999;
	const int* p = &a;  //指向常量的指针,不可以通过指针改变所指向的内容
	cout << *p << endl;
	a = 111;//但是可以通过直接修改常量本身进行改变常量的值
	cout << "直接修改常量后p指向的值: " << * p << endl;
	//*p = 222; 此处程序会报错,因为p指向的内容不可以该百年
	p = &b;//但是p的指向可以改变
	cout <<"改变p的指向之后的值: " << * p << endl;
	return 0;
}
  • 运行结果
    运行结果
  • 常指针: 类型名* const 指针名 = 地址值;
    • int * const p;
#include<iostream>
using namespace std;
int main()
{
	/*
	定义常指针,地址不变,
	就指针本身的作用而言,指针不能改变就是它指向的地址不可以改变
	但是指针所指向的地址所存储的内容是可以随意改变的
	*/
	int a = 666;
	int b = 999;
	int* const p = &a;
	// p = &b;不可以修改p的指向
	*p = 111;//但是可以修改内容
	
	
}
  • 指向常量的常指针: const 类型名* const 指针名 = 地址值;
    • const int *const p;
    • 综合使用上面两种方法;

6. 枚举类型

  • 使用enum定义符号常量
enum{Min = 0,Max = 100};
int x = Min,arr[Max];//可以直接匿名使用enum

7. 无名联合

  • 无名联合在关键词union后没有给出联合体的类型名称,这样可以使一组变量 共享同一段内存空间,起始地址相同
在此代码段中三个变量具有相同的起始地址,可以直接使用数据项的名字直接存取数据
union
{
 char c;
 int  i;
 double d;
 };

8. 扩展结构体

  • c++中的结构体不仅包含是数据成员,也可以将对这些数据成员进行操作的成员函数也定义在结构体中.
struct Point
{
  double x,y;
  void SetVal(double a,double b)
  {x = a; y = b;}
}p;
  • C++中定义结构体时,struct后面的标识符可以直接作为该结构体类型的类型名
struct Point{
  double x,y;
};
Point p;
//C语言中的写法: struct Point p;

9. void型指针

  • void作为指针类型时表示不确定的类型.是一种通用型指针,任何类型的指针值都可以赋值给该类型的变量
void *p;
  • 但是对于已经获值的void指针,对它进行处理时(eg.输出/传递指针),必须进行显示类型转换,否则会出错
    代码理解
#include<iostream>
using namespace std;
int main() 
{
	void* p;
	int i = 999;
	char a = 'A';
	p = &i;
	cout << *(int*)p << endl;
	p = &a;
	cout << *(char*)p << endl;
	return 0;
}

10. 运算符

  • 运算符优先级:
    单目运算符>算数运算符>关系运算符>逻辑运算符>条件运算符>赋值运算符

11. 数据类型转换

  • (目标类型)带转换的源数据

12. 内联函数

  • 函数说明前冠以关键字"inline",则声明为内联函数
  • 程序中出现对该函数的调用时,编译器使用函数体中的代码插入到该函数的语句之处,程序运行的时候不再进行函数的调用
  • 引入内联函数的原因: 为了消除函数调用时的系统开销,提高运行速度
  • 内联函数中不能有循环语句和开关语句
  • 内联函数是一种空间换时间的措施,内联函数太长且调用频繁程序就会加长很多,因此,只有较短的函数才能定义为内联函数

13. 重载

  • 函数名相同
  • 参数个数不同或者参数类型不同
  • 或者两者兼而有之
int add(int a,int b)
{
return a + b;
}
float add(float a,float b)//参数类型不同
{
return a + b;
}
float add(float a, float b, float c)//参数个数不同
{
return a + b + c;
}
double add (double a,double b,double c)//参数类型且个数不同
{
return a + b + c;
}


14. 引用

  • 引用是C++新增加的概念,用作函数参数或者作为函数的返回类型
  • C++是通过引用运算符&来声明一个引用的,在声明时必须进行初始化
  • 声明格式如下:
数据类型 &引用名 = 已定义的变量名
int i = 5;
int & j = i;
  1. 声明引用时使用&, & 不是取地址符,而是引用运算符,只在声明一个引用时使用,之后引用就像普通对象一样不再使用&
  2. 声明引用的同时,如果不是作为函数的参数或者返回值类型,就必须进行初始化,以明确该引用是哪一个对象的别名
  3. 不能建立void型引用,引用的引用,指向引用的指针,引用数组
14.1 引用作为参数传递
#include<iostream>
using namespace std;
int main() 
{
	int a = 5, b = 10;
	cout << "交换前a,b的值分别为: " << a << " " << b << endl;
	swap(a, b);//相当于 int &m = a; int &n = b;
	cout << "交换后a,b的值分别为: " << a << " " << b << endl;
	return 0;
}
void swap(int& m, int& n)
{
	int temp;
	temp = m;
	m = n;
	n = temp;
}

运行结果

交换前a,b的值分别为: 5 10
交换后a,b的值分别为: 10 5
  • 形式参数克服了值传递并不能改变对应实际参数的缺陷,因为引用参数和对应实际参数变量共享同一个内存
  • 与引用参数对应的实际参数只能是变量,而不能是常量或表达式
  • 就算不需要改变实际参数的值,引用参数仍然比值形式参数更高效,因为无需另外分配空间和进行传值操作
14.2 引用和指针的区别
  • 使用起来的效果是一样的,引用可以说是一种"自动间接引用的指针"
  • 引用不需要使用*,超级方便,真的好好用

指针形式实现以上交换

#include<iostream>
using namespace std;
void swap(int* m, int* n)
{
	int temp;
	temp = *m;
	*m = *n;
	*n = temp;
}
int main() 
{
    int a = 5, b = 10;
	cout << "交换前a,b的值分别为: " << a << " " << b << endl;
	swap(&a, &b);//相当于 int &m = a; int &n = b;
	cout << "交换后a,b的值分别为: " << a << " " << b << endl;
	return 0;
}
14.3 引用作为返回类型
  • 引用返回函数的类型声明
    类型名& 函数名(形式参数表);
  • 调用引用返回函数可以作为:
  1. 独立的函数语句;
  2. 表达式的某一个运算对象;
  3. 作为左值,这是引用作为返回值的函数的主要用法

代码理解

#include<iostream>
using namespace std;
int& Fun(const int& x, int& y, int z)
{
	z++;
	y = x + y + z;
	return y;
}
int main()
{
	int a = 1, b = 2, c = 3, d = 0;
	cout << "a = " << a << "\t b = " << b  << "\tc = " << c << "\td = " << d << endl;
	Fun(a, b, c) = 20;
	cout << "a = " << a << "\t b = " << b << "\tc = " << c << "\td = " << d << endl;
}

运行结果

a = 1    b = 2  c = 3   d = 0
a = 1    b = 20 c = 3   d = 0
  • return 后面只能是变量,而不能是常量或者表达式
  • return 后面变量的内存空间在本次函数调用结束后仍然存在,因此局部自动型变量不能作为引用值返回
  • return 后面返回的不能是常饮用,因为常引用是为了保护对应的实在参数变量不被修改,而引用返回的函数作为左值必定要引起变量的修改

15. 动态内存分配

15.1 动态内存分配与释放函数
  • 程序运算时,计算机内存被分为4个区:
    • 程序代码区
    • 全程数据区
  • 堆由用户分配和释放
  • C语言中使用malloc()和free()等进行管理,并在头部嵌入头文件#include<stdlib.h>
    • malloc函数
      void * malloc(unsigned int size)
      • 作用: 在内存的动态存储区中分配一个长度为size的连续空间
      • 此函数的返回值是一个指向分配域起始地址的指针
      • 如果此函数未能成功执行,则返回空指针
    • calloc函数
      void *calloc(unsigned n,unsigned size);
      • 作用: 在内存的动态区存储中分配n个长度为size的连续空间.函数返回一个指向分配域起始地址的指针,分配不成功返回NULL
      • 用calloc函数可以为一位数组开辟动态存储空间,n为数组元素个数,每个元素长度为size
    • free函数
      void free(void *p)
      • 作用是释放由p指向的内存区,使这部分内存区域能被其他变量使用
      • p使最近一次调用calloc或malloc函数时返回的值,free函数无返回值
15.2 new和delete
15.2.1 具体使用
  1. new
  • 分配内存的最基本的语法形式: 指针变量 = new 类型名;
int *p = new int;
int *p = new int(99);//分配空间的同时进行初始化
  • 该语句运行的时候从堆中为程序分配一块sizeof字节大小的内存空间,该内存空间的首地址被存于指针变量中
  • new为数组动态分配内存空间时,后缀数组大小: 指针变量 = new 类型名[下缀表达式];
int *p = new int[10];
  1. delete
  • 释放new分配的存储空间: delete 指针变量;
  • 指针变量保存着new分配的内存首地址
  • delete释放数组存储区域时,可以不用指出数组大小
delete []p;
15.2.2 new和delete的优点
  1. new可以自动计算分配内存的类型大小
  2. new能够自动返回正确的指针类型,不需要对返回指针进行强制的类型转换
  3. 可以使用new将分配的对象初始化
  4. new和delete都可以被重载
15.2.3 注意点
  1. new分配的空间只能由delete显式释放
  2. new动态分配内存时,如果没有足够的内存满足分配要求,new将返回空指针,因此常需对内存的动态分配是否成功进行检查

代码理解

#include<iostream>
using namespace std;
int main()
{
	int* p;
	p = new int;
	if (!p)
	{
		cout << "分配内存失败!" << endl;
		return -1;
	}
	*p = 20;
	cout << *p;
	delete p;
	return 0;
}

16. 异常处理

16.1 程序中的错误类型
  1. 语法错误: 包括编译错误和链接错误,这类错误在编译链接时根据出现的错误信息可以进行纠正
  2. 运行错误: 在编译链接通过后在运行时出现的错误,通常包括不可预料的逻辑错误和可预料的运行异常
16.2 异常处理的机制
  • C++中使用throw和try-catch语句支持异常处理
  • C++语言中异常处理的机制由三步解决"
  1. 检查异常(try块)
  2. 抛出异常(throw块)
  3. 捕捉异常(catch块)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值