一、第一个C++ 程序
一般在学习C++ 入门,都从C 开始,有了C 的基础,进军C++ 就会更加简单
下面简单说一下面向过程与面向对象的区别:
面向过程:过程既是步骤,按部就班将大型项目分解成若个小项目,特点:自定向下,强调的是算法
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源:比如单片机,嵌入式开发等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易拓展
面向对象:有自己独特的个性,特点:方便地重用和修改现有的代码
优点:易维护、易复用、易拓展,由于面向对象封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低
编译器:源代码 -》 编译器 -》 目标代码 -》 链接程序(启动代码、库代码) -》 可执行代码
在vs编译器的注释,打开注释的快捷键,建议在熟悉操作之后装一个番茄助手
ctrl + K, ctrl + C 注释
ctrl + K, ctrl + U 打开注释
/*流程:
1. 创建项目
使用软件 VS(visual studio) -> File(文件)->New(新建)->project(项目)->visual C++ -> 选择 空项目
注意:起项目名,路径==不要出现中文名==
2. 创建文件
在源/头文件 右键 -》 添加 -》 新建项 -》 起文件名(起名尽量用英文)
3. 编写代码
main 是一个程序的入口,每个程序必须有这么一个函数,有且仅有一个
大括号{} 就是函数体
4. 编译运行程序
生成解决方案 F7
启动调试 F5
*/
#include <iostream> //头文件
using namespave std;
int main(int argc, char* argv[])//主函数,唯一的入口函数
{
cout << "hello world" << endl;
system("pause");//调用系统命令,会阻塞在这里,直到有任意按键按下,与 getchar() 效果一致
return 0;
}
注释
1、单行注释 //描述信息
2、多行注释 /* 描述信息*/
3、if 0 … endif //这样也是可以的
提示:在编译器运行时,会忽略注释的内容,不能注释嵌套
变量
作用:给一段指定的内存空间起名,方便操作这段内存
语法:数据类型 变量名 = 初始值;
实例:int a = 10;
命名规范:
1)只能使用字母、下划线、数字;
2)第一个字符不能为数字;
3)区分大小写;
4)不能用C++ 关键字作为名称。
常量
作用:用于记录程序中不可更改的数据
两种方式
1、#define 宏常量 : #define 常量名 常量值,eg #define DAY 7;
2、const 修饰的变量 const 数据类型 常量名 = 常量值,const int day = 7;
const 限定符 与 #define
1)能够明确指定类型
2)可以使用C++ 的作用域规则将定义在特定的函数或文件中
3)可以将const 用于更复杂的类型
关键字
作用:关键是C++ 中预先保留的单词(标识符)
asm if do return typedef
auto double inline short typeid
……
在定义变量或者常量的时候,不要用关键字,因为系统用了,否则会产生歧义
标识符命名规则
作用:C++规定给标识符(变量、常量)命名时,有一套自己的原则
标识符不能是关键字
只能由字母,下划线,数字组成
第一个字符必须由字母或者下划线
标识符中区分大小写
建议:给标识符命名时,争取做到见名知其意的效果,方便自己和他人阅读
二、数据类型
C++ 规定在创建一个变量或者常量时,必须要指定出相应的数据类型,否则无法给出变量分配内存
**整型**
作用:整型变量表示的是整型类型的数据
数据类型 占用空间 取值范围
short 2字节 -2^15^ ~ 2^15^-1
int 4字节 -2^31^ ~ 2^31^-1
long 4字节 -2^31^ ~ 2^31^-1
long long 8字节 -2^63^ ~ 2^63^-1
sizeof关键字
作用:利用sizeof 关键字 可以统计数据类型所占内存大小
语法:sizeof(数据类型 / 变量)
实例: sizeof(int);
实型(浮点型)
作用:用于表示小数
浮点型变量分为两种:
1、单精度float float f1 = 3.14f; 4个字节
2、双精度double 8个字节
默认情况下,输出一个小数,会显示出一个小数点后六位的有效数字
科学计数法
float f2 = 3e2;
字符型
作用:字符型变量用于单个字符
语法:char chTemp = ‘a’;
注意:在显示字符型变量时,用单引号将字符括起来,不要用双引号
单引号内只能有一个字符,不可以是字符串
C 和 C++ 中字符型变量只占用一个字节
字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放到存储单元
转义字符
作用:用于表示一些不能显示出来的ASCII字符
现阶段我们常用的转义字符有: \n, \ \t
\b 退格
\n 换行
\ 反斜杠
" 双引号
? ?
字符串
作用:用于表示一串字符
两种风格
1、C风格字符串: char 变量名[] = “字符串值”;// char str1[] = “hello world”;
2、C++风格字符串: string 变量名 = “字符串值”;
布尔类型 bool
作用:布尔数据类型代表真或假的值 占一个字符大小
true 真
false 假
数据的输入
作用:从键盘获取数据
关键字:cin
语法: cin >> 变量
int a;
cin >> a;
//读取一行
char address[80];
cin.getline(address, 80);
三、运算符
作用:用于执行代码的运算
运算符类型:算术运算符、赋值运算符、比较运算符、逻辑运算符
算术运算符:+ , - , * , / , %, ++ , – 注意:前置++ ,与后置++的区别
赋值运算符:=、 +=、 -=、 /= 、 %=
比较运算符: > 、 < 、 >= 、 <= 、== 、 !=
逻辑运算符:! 、 && 、 ||
四、程序流程结构
C/C++ 支持最基本流程的三种程序运行结构: 顺序结构,选择结构,循环结构
- 顺序结构:程序按顺序执行,不发生跳转; if, if - else, if - else if - else
- 选择结构:依据条件是否满足,有选择的执行相应的功能;
- 循环结构:依据条件是否满足,循环多次执行某段代码。
练习案例:三只小猪称体重
有三只小猪ABC,请分别输入三只小猪的体重,并且判断哪只小猪最轻?
#include <iostream>
using namespace std;
int main()
{
int numA = 0;
int numB = 0;
int numC = 0;
cout << "请依次输入小猪A,B,C的体重" << endl;
cin >> numA >> numB >> numC;
if(numA > numB)
{
if(numB > numC)
{
cout << "最轻的是小猪 C" << endl;
}
else
{
cout << "最轻的是小猪 B" << endl;
}
}
else
{
if(numA > numC)
{
cout << "最轻的是小猪 C" << endl;
}
else
{
cout << "最轻的是小猪 A" << endl;
}
}
system("pause");
return 0;
}
三目运算符
作用:通过三目运算符实现简单的判断
语法:表达式1 > 表达式2 ? 表达式3
eg: int c = a > b ? a : b;//如果a 大于 b 为真,则返回a,并赋值给c,否则,则返回b,赋值给c
也可以作为左值 (a > b ? a : b) = 20;//判断a , b ,然后根据条件进行赋值其中一个
switch 语句
作用:执行多条件分支语句
语法:
switch(表达式)
{
case 结果1: 执行语句; break;
case 结果2: 执行语句; break;
......
default:执行语句;break;
}
注意1:switch 语句表达式类型只能是整型或者字符型
注意2:case里如果没有break,那么程序会一直向下执行
while 循环语句
作用:满足循环条件,循环执行语句
语法:while(循环条件){循环语句}
解释:只要循环条件的结果为真,就执行循环语句
案例:
系统随机生成一个1 到 100 之间的数字,玩家进行猜测,如果猜错,提示玩家数字过大或过小,如果猜对恭喜玩家胜利,并且退出游戏
#include <iostream>
#include "ctime"
using namespace std;
int main()
{
srand((unsigned int)time(NULL));
int num1 = rand() % 100 + 1;
int num2;
cout << "请输入0 ~ 100 的数" << endl;
while (1)
{
cin >> num2;
if (num1 > num2)
{
cout << "玩家数字过小" << endl;
cout << "请重新输入0 ~ 100 的数" << endl;
}
else if(num1 < num2)
{
cout << "玩家数字过大" << endl;
cout << "请重新输入0 ~ 100 的数" << endl;
}
else
{
cout << "恭喜玩家胜利" << endl;
break;
}
}
std::cout << "Hello World!\n";
return 0;
}
do while 循环语句
作用:满足循环条件,循环执行语句
语法:do{循环语句}while(循环条件);
解释:与while 的区别 在于 do……while 会先执行一次循环语句,再判断循环条件
for 循环语句
作用:满足循环条件,循环执行语句
语法:for(起始表达式;条件表达式;末尾表达式) {循环语句;}
eg : for(int i = 0; i < 10; ++i)
嵌套循环
作用:在循环体重再嵌套一层循环,解决一些实际问题
跳转语句
- break 语句
作用:用于跳出选择结构 或 循环结构
break使用的时机:
出现在switch条件语句中,作用是终止case 并跳出switch
出现在循环语句中,作用是跳出当前的循环语句
出现在嵌套中,跳出最近的内存循环结构 - continue 语句
作用:在循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环 - goto 语句
作用:可以无条件跳转语句
语法:goto 标记;
解释:如果标记的名称存在,执行到goto 语句,会跳转到标记的位置
五、数组
所谓的数组,就是一个集合,里面存放了相同类型的数据元素
特点1:数组中的每个数据元素都是相同的的数据类型
特点2:数组是由连续的内存位置组成的
注意:数组下标从0开始
定义方式:
- 数据类型 数组名[数组长度];
- 数据类型 数组名[数组长度] = {值1, 值2 ……};
- 数据类型 数组名[] = {值1, 值2……};
实例:
int main()
{
int score[10];
score[0] = 100;
score[1] = 99;
return 0;
}
一维数组数组名
一维数组名称的用途:
- 可以统计整个数组在内存中的长度
- 可以获取数组在内存中的首地址
#include <iostream>
using namespace std;
int main(void)
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9 10};
cout << sizeof(arr) << endl;//整个数组占用内存空间为
cout << sizeof(arr[0]) << endl;//每个元素占用内存空间
return 0;
}
练习案例1:
在一个数组中记录了五只小猪的体重,如:int arr[5] = {300, 350, 200, 400, 250};
找出并打印最重的小猪体重
练习案例2:
请声明一个5个元素的数组,并且将元素逆置
(如原数组元素为:1,3,2,5,4 逆置输出结果为:4,5,2,3,1)
冒泡排序
作用:最常用的排序算法,对数组内的元素进行排序
1、比较相邻的元素,如果第一个比第二个大,就进行交换
2、对每一个相邻元素做同样的工作,执行完毕后,找到第一个最大值
3、重复以上的步骤,每次比较次数-1,直到不需要比较
二维数组
在一维数组上多加一个维度
四种定义方式:
1、数据类型 数组名[ 行数 ][ 列数 ];
2、数据类型 数组名[ 行数 ][ 列数 ] = {{数据1,数据2}, {数据3, 数据4}};//建议用这个,直观
3、数据类型 数组名[ 行数 ][ 列数 ] = {数据1,数据2,数据3, 数据4};
4、数据类型 数组名[ ][ 列数 ] = {数据1,数据2,数据3, 数据4};
应用案列:
有三名同学(张三,李四,王五),在一次考试中的成绩分别如下表,请分别输出三名同学的总成绩
语文 数学 英语
张三 100 100 100
李四 90 50 100
王五 60 70 80
int main(void)
{
int score[3][3] = {{100, 100, 100}, {90, 50, 100}, {60, 70, 80}};
for(int i = 0; i < 3; ++i)
{
int sum = 0;
for(int j = 0; j < 3; ++j)
{
sum += score[i][j];
cout << sum << endl;
}
}
return 0;
}
六、函数
作用:将一段经常使用的代码封装起来,减少重复代码
一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。
double (pf) (int);// 函数指针
doubel pf (int);// 指针函数
函数的定义:
1、返回值类型
2、函数名
3、参数表列
4、函数体语句
5、return 表达式
语法:
返回值类型 函数名(参数列表)
{
函数体语句;
return 表达式;
}
int Add(int num1, int num2);//声明
int main(void)
{
int a = 1;
int b = 2;
int sum = Add(a, b);//调用,实参
cout << sum << endl;
return 0;
}
int Add(int num1, int num2)//定义,形参
{
return num1 + num1;
}
值传递
所谓的值传递,就是函数调用时实参将数值传入给形参
值传递时,如果形参发生,并不会影响实参
void swap(int a, int b)
{
int temp;
temp = a;
a = b;
b = temp;
return;
}
声明可以有多次,定义只能有一次
函数分文件编写
作用:让代码结构更加清晰
1、创建后缀名为.h 的头文件
2、创建后缀名为.cpp 的源文件
3、在头文件中写函数的声明
4、在源文件中写函数的定义
七、指针
指针的作用:可以通过指针间接访问内存
内存编号是从0开始记录的,一般用十六进制数字表示
可以利用指针变量保存地址
指针变量的定义和使用
指针变量定义的语法: 数据类型 * 变量名;
//指针
int* p_updatas;//野指针
int* ptr = NULL;// 空指针
//使用 new 来 分配内存
int* pn = new int;//申请int 型内存
int main()
{
int a = 10;
int *p = &a;
cout << &a << endl;
cout << p << endl;
return 0;
}
指针所占内存空间 4个字节
空指针和野指针
空指针:指针变量指向内存中编号为0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的
实例:空指针
int main()
{
//指针变量p指向内存地址编号为0的空间
int * p = NULL;
//访问空指针报错
//内存编号为0 - 255为系统占用内存,不允许用户空间
cout << *p << endl;
}
实例:野指针
int main()
{
//指针变量p指向内存地址编号为0x1100的空间
int * p = (int *)0x1100;
//访问野指针报错
cout << *p << endl;
system("pause");
return 0;
}
const 修饰指针
const 修饰指针有三种情况:
1、const 修饰指针 —常量指针
2、const 修饰常量 ----指针常量
3、const 即修饰指针,又修饰常量
const int *p1 = &a;//指针指向的值不可更改
int * cosnt p2 = &a;//指针的指向不可更改,值可以改
const int* const p3 = &a;//指针的指向不可更改,值也不可以更改
指针和数组
作用:利用指针访问数组中元素
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *p = arr;
cout << arr[0] << endl;//第一个元素
cout << *p << endl;//指针访问第一个元素
for(int i = 0; i < 10; ++i)
{
//利用指针遍历数组
cout << *p << endl;
p++
}
system("pause");
return 0;
}
指针和函数
作用:利用指针作函数参数,可以修改实参的值
//地址传递
void swap(int* p1, int* p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
指针、数组、函数
案例描述:封装一个函数,利用冒泡排序,实现对整形数组的升序排序
例如数组: int arr[10] = {4, 3, 6, 9, 1, 2, 10, 8, 7, 5};
实例:
//冒泡排序函数
void bubbleSort(int *arr, int len)
{
for(int i = 0; i < len - 1; ++i)
{
for(int j = 0; j < len - 1 - i; ++j)
{
if(arr[j] > arr[j +1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return;
}
八、结构体、共用体、枚举
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
语法:struct 结构体名 { 结构体成员列表 };
通过结构体创建变量的方式有三种:
struct 结构体名 变量名
struct 结构体名 变量名 = {成员1值, 成员2值 ……};
定义结构体时顺便创建变量
struct student
{
string name;//名称
int age;//年龄
int score;//分数
};
union one4all
{
int int_val;
long long_val;
double double_val;
};//注意大端模式和小端模式之分
//枚举
enum spectrum{red, orange, yellow, green, violet};
spectrum myflag;
myflag = spectrum(1);
结构体指针
作用:通过指针访问结构体中的成员
利用操作符 -> 可以通过结构体指针访问结构体属性
struct student stu = {"张三", 10, 100};
struct student * p = stu;
cout << "姓名:" << p->name << "年龄:" << p->age << "分数:" << p->score << endl;
结构体嵌套
struct Teacher
{
int id;
string name;
int age;
struct Student stu;
};
结构体做函数参数
作用:将结构体作为参数向函数中传递
传递方式有两种:
值传递
地址传递
总结:如果你不想修改主函数中的数据,用值传递,反之用地址传递
结构体中 const 使用场景
作用:用const 来防止误操作
示例:
void PrintStudent(const Student* std);
在函数内不允许对变量 std 进行操作
案例:
学校正在做毕设项目,每名老师带领五个学生,总共有3名老师,需求如下:
设计学生和老师的结构体,其中在老师的结构体中,有老师姓名和一个存放五名学生的数组作为成员
学生的成员有姓名、考试分数,创建数组存放三名老师,通过函数给每个老师及所带的学生赋值
最终打印出老师数据以及所带的学生数据。
struct Student
{
string name;
int score;
};
struct Teacher
{
string name;
struct Student stu[5];
};
void GetValue(struct Teacher *T, int len);
void PrintInfo(const struct Teacher *T, int len);
int main(void)
{
struct Teacher T[3];
GetValue(T, sizeof(T)/sizeof(T[0]));
PrintInfo(T, sizeof(T)/sizeof(T[0]));
return 0;
}
九、异常的基本语法
//尝试执行一段 可能出现异常的代码
class MyException
{
public:
MyException()
{
cout << "构造函数" << endl;
}
~MyException()
{
cout << "析构函数" << endl;
}
MyException(const MyException& e)
{
cout << "MyException 拷贝构造函数调用" << endl;
}
};
int myDivide(int a, int b)
{
if (b == 0)
{
//a = a / b;
}
throw MyException();
return 0;
}
int main()
{
int a = 0;
int b = 0;
try
{
int ret = myDivide(a, b);
cout << "ret 结果为:" << ret << endl;
}
catch (int)//捕获异常
{
cout << "int 类型" << endl;
}
catch (double)//捕获异常
{
throw;//继续向上抛
cout << "double 类型" << endl;
}
catch (MyException e)
{
//e.printError();
int ddd = 0;
}
catch (...)
{
cout << "其他类型的捕捉" << endl;
}
==========================================
//使用系统标准异常
#include <stdexcept>
class MyException
{
public:
MyException()
{
cout << "构造函数" << endl;
throw length_error("0 ~ 150");
}
~MyException()
{
cout << "析构函数" << endl;
}
MyException(const MyException& e)
{
cout << "MyException 拷贝构造函数调用" << endl;
}
};
try
{
MyException p1;
}
catch(exception& e)
{
cout << e.what() << endl;
}