C++基础入门(内容与C语言大致相同)
1 C++初识
1.1 第一个C++程序
基础框架
#include<iostream>
using namespace std;
int main() {
cout << "hello world" << endl;//相当于printf,<<endl是换行操作
system("pause");
return 0;
}
后续示例代码为了简略,可能会省略部分框架
1.2 注释
1.3 变量
1.4 常量
**作用:**用于记录程序中不可修改的数据
1.#define 宏常量,通常在文件上方定义
2.const 修饰的变量,通常在变量定义前加关键字const
1.5 关键字
在定义变量或者常量的时候,不要使用关键字
1.6 标识符命名规则
规则:
1.标识符不能是关键字
2.标识符只能由字母、数字、下划线组成
3.第一个字符必须为字符或下划线(即第一个字符不能是数字)
4.标识符中字符取分大小写,大写和小写不是同一个名称
建议:给标识符命名时,争取做到见名知意的效果,方便自己和他人阅读
2 数据类型
C++规定在创建一个变量或者常量时,必须要指定出相应的数据类型,否则无法给变量分配内存
2.1 整型
**作用:**表示整数类型的数据
有以下几种类型,区别在于所占内存空间不同
数据类型 | 占用空间 | 取值范围 |
---|---|---|
short(短整型) | 2字节 | -215~215-1(-32768 ~ 32767) |
int(整型) 最常用 | 4字节 | -231~231-1 |
long(长整型) | Windows为4字节,Linux为4字节(32位),8字节(64位) | -231~231-1 |
long long(长长整型) | 8字节 | -263~263-1 |
**结论:**short<int<=long<=long long
2.2 sizeof关键字
**作用:**统计数据类型所占内存大小
语法:sizeof(数据类型/变量)
示例:
int main(){
cout<<"int类型所占内存空间为:"<<sizeof(int)<<endl;
system("pause");
return 0;
}
2.3 实型(浮点型)
**作用:**用于表示小数
1.单精度 float
2.双精度 double
**二者区别:**表示的有效数字的范围不同
****数据类型 | 占用空间 | 有效数字范围 (小数点前后都算) |
---|---|---|
float | 4字节 | 7位有效数字 |
double | 8字节 | 15~16位有效数字 |
注意如果使用float通常会在数字后加一个字母f,否则编译器将默认为double类型
示例:
float f1 = 3.14 ; // (double)(3.14000…)
float f1 =3.14f ; // (float)(3.14000…)
科学计数法
float f2=3e2;//3*10^2=300
float f3=3e-2;//3*0.1^2=0.03
2.4 字符型
**作用:**用于表示单个字符
语法:char ch ='a';
注意:
1.在显示字符型变量时,是用单引号将字符括起来而非双引号
2.单引号内只能有一个字符,不可以是字符串
- C和C++中字符型变量只占用1个字节
- 字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元
常见字符型变量对应的ASCII编码
a:97
A:65
空格:32
ASCII码大致由以下两部分组成:
1.ASCII非打印控制字符:ASCII表上的数字0-31分配给了控制字符,用于控制像打印机等一些外围设备
2.ASCII打印字符:数字32-126分配给了能在键盘上找到的字符,当查看或打印文档时就会出现
2.5 转义字符
**作用:**用于表示一些不能显示出来的ASCII字符
现阶段常用的转义字符:\n(换行符),\\(代表一个反斜线字符“\"),\t(水平制表,应该加上前面字符一共有八个单位长度?)
2.6 字符串型
**作用:**用于表示一串字符
两种风格
1.C风格字符串:char 变量名[]="字符串值"
char str[]="hello world";
注意字符串要用双引号括起来
2.C++风格字符串:string 变量名="字符串值"
string str="hello world";
C++风格字符串,需要加入头文件#include
2.7 布尔类型 bool
**作用:**代表真或假的值
**只有两个值:**true:真(本质是1)
false:假(本质是0)
与C语言不同不必再声明一个头文件?
bool类型占1个字节大小
2.8 数据的输入
**作用:**用于从键盘获取数据
**关键字:**cin
语法:cin >> 变量
//整型输入
int a=0;
cout<<"请输入整型变量:"<<endl;
cin>>a;
cout<<a<<endl;
3 运算符
主要讲解一下几类运算符:
运算符类型 | 作用 |
---|---|
算术运算符 | 用于处理四则运算 |
赋值运算符 | 用于将表达式的值赋给变量 |
比较运算符 | 用于表达式的比较,并返回一个真值或假值 |
逻辑运算符 | 用于根据表达式的值返回真值或假值 |
3.1 算术运算符
+ | - | * | / | % | ++ | – |
---|---|---|---|---|---|---|
正号/加 | 负号/减 | 乘 | 除 | 取模(取余) | 前置/后置递增 | 前置/后置递减 |
注意:
1.两个整数相除结果依然是整数
2.除数不可为0
3.两个小数可以相除,但做不了取模运算,即只有整型变量可以做取模运算
3.2 赋值运算符
= | += | -= | *= | /= | %= |
---|
3.3 比较运算符
== | != | < | > | <= | >= |
---|
3.4 逻辑运算符
! | && | || |
---|
C++中,除了0,都为真
4 程序流程结构
C/C++支持最基本的三种顺序运行结构:顺序结构,选择结构,循环结构
- 顺序结构:程序按顺序执行,不发生跳转
- 选择结构:依据条件是否满足,有选择地执行相应功能
- 循环结构:依据条件是否满足,循环多次执行某段代码
4.1 选择语句
4.1.1 if语句
三种形式:
1.单行格式if语句:if(条件){条件满足时执行的语句}
注意if后面不要加分号
2.多行格式if语句:if(条件){条件满足时执行的语句}else{条件不满足时if执行的语句}
3.多条件的if语句
嵌套if语句
4.1.2 三目运算符
语法:表达式1?表达式2:表达式3
解释:
如果表达式1的值为真,执行表达式2并返回其结果;
如果表达式1的值为假,执行表达式3并返回其结果.
C++中三目运算符返回的是变量,可以继续赋值
4.1.3 switch语句
语法:
switch(表达式){
case 结果1:执行语句;break;
case 结果2:执行语句;break;
......
default:执行语句;break;
}
注意:
1.switch语句中表达式类型只能是整型或者字符型
2.case里如果没有break,那么程序会一直向下执行
总结:与if语句相比,对于多条件判断时,switch的结构清晰,执行效率高,缺点是switch不可以判断区间
4.2 循环结构
4.2.1 while循环语句
注意:在执行循环语句的时候,程序必须提供跳出循环的出口,否则出现死循环
//随机生成0+1~99+1的数
int num=rand()%100+1;
//生成随机数
#include<ctime>//time系统时间头文件包含
srand((unsigned int)time(NULL));//记住格式就好
4.2.2 do…while循环语句
语法:do{循环语句}while(循环条件);
注意:
1.结尾要加;
2.与while循环的区别在于,do…while先执行一次循环语句,再判断循环条件
4.2.3 for循环语句
总结:while,do…while,for都是开发中常用的循环语句,for循环结构比较清晰,比较常用
4.2.4 嵌套循环
**作用:**在循环体中再嵌套一层循环,解决一些实际问题
//打印10*10星号
for(int i=0;i<10;i++){
cout<<"*";
}
cout<<endl;//换行
//乘法口诀表,打印行数
for(int i=1;i<=9;i++){
cout<<i<<endl;
for(int j=1;j<=9;j++){
cout<<j;
//cout<<j<<"*"<<i<<"="<<j*i<<" ";
}
cout<<endl;
}
4.3 跳转语句
4.3.1 break语句
**作用:**用于跳出选择结构或者循环结构,switch,for,while等
4.3.2 continue语句
**作用:**在循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环
4.3.3 goto语句(实际情境中不推荐使用)
**作用:**可以无条件跳转语句
语法:goto 标记;
**解释:**如果标记的名称存在,执行到goto语句时,会跳转到标记的位置
cout<<"1"<<endl;
goto FLAG;
cout<<"2"<<endl;
FLAG:
cout<<"3"<<endl;
5 数组
5.1 概述
特点:
1.数组中每个数据元素都是相同的数据类型
2.数组是由连续的内存位置组成的
5.2 一维数组
5.2.1 一维数组定义方式
三种方式:
1.数据类型 数组名[数组长度];
2.数据类型 数组名[数组长度]={值1,值2...};
3.数据类型 数组名[ ]={值1,值2...};
如果在初始化数据的时候,没有全部填写完,会用0来填补剩余数据
注意:
1.数组名的命名规范与变量名命名规范一致,不要和变量重名
2.数组中下标是从0开始索引
5.2.2 一维数组数组名
一维数组名称的用途:
1.可以统计整个数组在内存中的长度
2.可以获取数组在内存中的首地址
//1.可以获取整个数组占用内存空间大小
int arr[10]={1,2,3,4,5,6,7,8,9,10};
cout<<"整个数组所占内存空间为:"<<sizeof(arr)<<endl;
cout<<"每个元素所占内存空间为:"<<sizeof(arr[0])<<endl;
cout<<"数组的元素个数为:"<<sizeof(arr)/sizeof(arr[0])<<endl;
//2.可以通过数组名获取到数组首地址
cout<<"数组首地址为:"<<(int)arr<<endl;//不强制转换格式将会是16进制
cout<<"数组中第一个元素地址为:"<<(int)&arr[0]<<endl;//与首地址相同
cout<<"数组中第二个元素地址为:"<<(int)&arr[1]<<endl;
//arr=100,错误,数组名是常量,因此不可以赋值
**练习案例:**数组元素逆置
//创建数组
int arr[5]={1,3,2,5,4};
cout<<"数组逆置前:"<<endl;
for(int i=0;i<5;i++){
cout<<arr[i]<<endl;
}
int start=0;//起始下标
int end=sizeof(arr)/sizeof(arr[0])-1;//结束下标
while(start<end){
//实现元素互换
int temp=arr[start];
arr[start]=arr[end];
arr[end]=temp;
//下标更新
start++;
end--;
}
//3.打印逆置后的数组
cout<<"数组逆置后:"<<endl;
for(int i=0;i<5;i++){
cout<<arr[i]<<endl;
}
5.2.3 冒泡排序
**示例:**将数组{4,2,8,0,5,7,1,3,9}进行升序排序
int main(){
int arr[9]={4,2,8,0,5,7,1,3,9};
cout<<"排序前:"<<endl;
for(int i=0;i<9;i++){
cout<<arr[i]<<" ";
}
cout<<endl;
for(int i=0;i<9-1;i++){
for(int j=0;j<9-1-i;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
cout<<"排序后:"<<endl;
for(int i=0;i<9;i++){
cout<<arr[i]<<" ";
}
}
5.3 二维数组
5.3.1 二维数组定义方式
二维数组定义的四种方式:
1.数据类型 数组名[行数][列数];
2.数据类型 数组名[行数][列数]={{数据1,数据2},{数据3,数据4}};
//注意大括号最后要有;
3.数据类型 数组名[行数][列数]={数据1,数据2,数据3,数据4};
4.数据类型 数组名[][列数]={数据1,数据2,数据3,数据4};
建议:以上4种定义方式,利用第二种更加直观,提高代码的可读性
5.3.2 二维数组数组名
作用:
1.查看二维数组所占空间
2.获取二维数组首地址
cout<<"二维数组大小:"<<sizeof(arr)<<endl;
cout<<"二维数组一行大小:"<<sizeof(arr[0])<<endl;
cout<<"二维数组元素大小:"<<sizeof(arr[0][0])<<endl;
6 函数
6.1 概述
6.2 函数的定义
语法:
返回值类型 函数名(参数列表){
函数体语句
return表达式
}
注意:一个函数只能返回一个值
6.3 函数的调用
语法:函数名(参数)
- 定义中的num1,num2称为形式参数,简称形参
- 调用时的a,b称为实际参数,简称实参
6.4 值传递
- 所谓值传递,就是函数调用时实参将数值传入给形参
- 值传递时,如果形参发生,并不会影响实参
当函数声明时,不需要返回值,可以不写return
6.5 函数的常见形式
常见的函数形式有4种:无参无返,有参无返,无参有返,有参有返
6.6 函数的声明
注意:函数的声明可以多次,但是函数的定义只能有一次
6.7 函数的分文件编写
**作用:**让代码结构更加清晰
函数分文件编写一般有4个步骤:
1.创建后缀名为.h的头文件
2.创建后缀名为.cpp的源文件
3.在头文件中写函数的声明
4.在源文件中写函数的定义
示例:
//swap.h文件
#include<iostream>
using namespace std;
//实现两个数字交换的函数声明
void swap(int a, int b)
//swap.cpp文件
#include"swap.h"
引号表示访问本地资源
7 指针
7.1 指针的基本概念
**作用:**可以用指针访问内存
- 内存编号是从0开始记录的,一般用十六进制数字表示
- 可以利用指针变量保存地址
7.2 指针变量的定义和使用
语法:数据类型* 变量名;
1.对变量取地址:&
2.指针指向的原型:*
7.3 指针所占空间
在32位操作系统下,指针是占4个字节空间大小,不管是什么数据类型
在64位操作系统下,指针是占8个字节空间大小
(不管是什么变量类型)
7.4 空指针和野指针
**空指针:**指针变量指向内存中编号为0的空间
**用途:**初始化指针变量
注意:空指针指向的内存是不可以访问的
**野指针:**指针变量指向非法的内存空间
int* p=(int*)0x1100;//事先未申请过的区域
在程序中,尽量避免出现野指针
**总结:**空指针和野指针都不是我们申请的空间,因此不要访问
7.5 const修饰指针
const修饰指针有三种情况:
1.const修饰指针:常量指针
//指针的指向可以改,但是指针指向的值不可以改(const在int前,修饰int)
const int* p1=&a;
p1=&b;//正确
*p1=100;//错误
2.const修饰常量:指针常量
//指针的指向不可以改,但是指针指向的值不可以改(const在p2前,修饰p2)
int* const p2=&a;
p2=&b;//错误
*p2=100;//正确
3.const既修饰指针,又修饰常量
const int* const p3=&a;
p3=&b;//错误
*p3=100;//错误
技巧:看const右侧紧跟着的是指针还是常量,是指针就是常量指针,是常量就是指针常量
7.6 指针和数组
**作用:**利用指针访问数组中的元素
int arr[]={,,,,};
int *p=arr;//指向数组的指针
cout<<"第一个元素:"<<arr[0]<<endl;
cout<<"指针访问第一个元素:"<<*p<<endl;
//利用指针遍历数组(要先找到首地址)
for(int i=0;i<10;i++){
cout<<*p<<endl;
p++;
}
7.7 指针和函数
**作用:**利用指针作为函数参数,可以修改实参的值
值传递不会改变实参,地址传递会改变实参
如果不想修改实参,就用值传递;如果想修改实参,就用地址传递
7.8 指针、数组、函数
8 结构体
8.1 结构体基本概念
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
8.2 结构体定义和使用
语法:struct 结构体名{结构体成员列表};
通过结构体创建变量的方式有三种:
1.struct结构体名 变量名
2.struct结构体名 变量名={成员1值,成员2值…}
3.定义结构体是顺便创建变量
示例:
struct student{
string name;//引用类型
int age;
int score;
}stu3;//结构体变量创建方式3(在主函数外)
int main(){
//结构体变量创建方式1
struct student stu1;//struct关键字可以省略
stu1.name="张三";
stu1.age=18;
stu1.score=100;
//结构体变量创建方式2
struct student stu2={"李四",19,60};
...
}
string是引用类型,剩下的不知道了,猜测一般是字符串用
结构体大括号后要加上分号;
注意:
1.定义结构体时的关键字是struct,不可省略
2.创建结构体变量时,关键字struct可以省略
3.结构体变量利用操作符”."访问成员
8.3 结构体数组
**作用:**将自定义的结构体放入到数组中方便维护
语法:struct 结构体名 数组名[元素个数]={{},{},...{}}
示例:
struct student arr[3]={
{"张三",18,80},
{,,},
...
};
8.4 结构体指针
利用操作符->
可以通过结构体指针访问结构体属性
struct student s={"张三",18,100};
struct student* p=&s;
8.5 结构体嵌套结构体
结构体中的成员可以是另一个结构体
在结构体中可以定义另一个结构体作为成员,用来解决实际问题
8.6 结构体做函数参数
**作用:**将结构体作为参数向函数中传递
传递方式有两种:
1.值传递
2.地址传递
如果不想修改主函数中的数据,用值传递,反之用地址传递
8.7 结构体中const使用情景
**作用:**加入const之后,一旦有修改的操作就会报错,可以防止我们的误操作
将函数中的形参改为指针,可以减少内存空间,而且不会复制出新的副本出来
8.8结构体案例
可能是结构体里出现string这个类型,所以要用头文件
C++万能头文件:stdc++.h
通讯录管理系统
系统中实现的功能如下:
- 添加联系人
- 显示联系人
- 删除联系人
- 查找联系人
- 修改联系人
- 清空联系人
- 退出通讯录
补充:C语言中没有的system
system("pause");//请按任意键继续
system("cls");//清屏操作
//-封装函数显示该界面 如void showMenu()
//-在main函数中调用封装好的函数
#include<iostream>
using namespace std;
#include<string>
#define MAX 1000
//设计联系人结构体
struct Person {
string m_Name;//姓名
int m_Sex;//性别 1男2女
int m_Age;//年龄
string m_Phone;//电话
string m_Addr;//住址
};
//设计通讯录结构体
struct Addressbooks {
struct Person personArray[MAX];//通讯录中保存的联系人数组
int m_Size;//通讯录中当前记录联系人个数
};
//1、添加联系人
void addPerson(Addressbooks* abs) {
//判断通讯录是否已满,如果满了就不再添加
if (abs->m_Size == MAX) {
cout << "通讯录已满,无法添加!" << endl;
return;
}
else {
//添加具体联系人
//姓名
string name;
cout << "请输入姓名: " << endl;
cin >> name;
abs->personArray[abs->m_Size].m_Name = name;
//性别
int sex = 0;
cout << "请输入性别: " << endl;
cout << "1---男" << endl;
cout << "2---女" << endl;
while (true)//可以让用户持续输入直到格式正确为止
{
cin >> sex;
if (sex == 1 || sex == 2) {
abs->personArray[abs->m_Size].m_Sex = sex;
break;
}
cout << "输入有误,请重新输入" << endl;
}
//年龄
int age = 0;
cout << "请输入年龄: " << endl;
cin >> age;
abs->personArray[abs->m_Size].m_Age = age;
//电话
string phone;
cout << "请输入联系电话: " << endl;
cin >> phone;
abs->personArray[abs->m_Size].m_Phone = phone;
//住址
string address;
cout << "请输入家庭住址: " << endl;
cin >> address;
abs->personArray[abs->m_Size].m_Addr = address;
//更新通讯录人数
abs->m_Size++;
cout << "添加成功!" << endl;
system("pause");//请按任意键继续
system("cls");//清屏操作
}
}
//2、显示所有联系人
void showPerson(Addressbooks* abs) {
if (abs->m_Size == 0) {
cout << "当前记录为空" << endl;
}
else {
for (int i = 0; i < abs->m_Size; i++) {
cout << "姓名:" << abs->personArray[i].m_Name << "\t";
cout << "性别:" << (abs->personArray[i].m_Sex==1?"男":"女") << "\t";//妙啊
cout << "年龄:" << abs->personArray[i].m_Age << "\t";
cout << "电话:" << abs->personArray[i].m_Phone << "\t";
cout << "住址:" << abs->personArray[i].m_Addr << endl;
}
}
system("pause");
system("cls");
}
//检测联系人是否存在,如果存在,返回联系人在数组中的具体位置,不存在返回-1
int isExist(Addressbooks* abs,string name)//参数1 通讯录 参数2 对比姓名
{
for (int i = 0; i < abs->m_Size; i++) {
if (abs->personArray[i].m_Name == name) {
return i;
}
}
return -1;
}
//3.删除指定联系人
void deletePerson(Addressbooks* abs) {
string name;
cout << "请输入您要删除的联系人" << endl;
cin >> name;
int ret = isExist(abs, name);
if (ret != -1) {
for (int i = ret; i < abs->m_Size; i++) {
abs->personArray[i] = abs->personArray[i + 1];//数据前移
}
abs->m_Size--;//更新通讯录中的人员数
cout << "删除成功" << endl;
}
else {
cout << "查无此人" << endl;
}
}
//4、查找指定联系人信息
void findPerson(Addressbooks* abs) {
string name;
cout << "请输入您要查找的联系人" << endl;
cin >> name;
int ret = isExist(abs, name);
if (ret != -1) {
cout << "姓名: " << abs->personArray[ret].m_Name << "\t";
cout << "性别: " << abs->personArray[ret].m_Sex << "\t";
cout << "年龄: " << abs->personArray[ret].m_Age << "\t";
cout << "电话: " << abs->personArray[ret].m_Phone << "\t";
cout << "住址: " << abs->personArray[ret].m_Addr << endl;
}
else {
cout << "查无此人" << endl;
}
system("pause");
system("cls");
}
//5、修改指定联系人信息
void modifyPerson(Addressbooks* abs) {
string name;
cout << "请输入您要修改的联系人" << endl;
cin >> name;
int ret = isExist(abs, name);
if (ret != -1) {
//姓名
string name; cout << "请输入姓名: " << endl;
cin >> name;
abs->personArray[ret].m_Name = name;
//性别
int sex = 0;
cout << "请输入性别: " << endl;
cout << "1---男" << endl;
cout << "2---女" << endl;
while (true) {
cin >> sex;
if (sex == 1 || sex == 2) {
abs->personArray[ret].m_Sex = sex;
break;
}
else {
cout << "输入有误,请重新输入" << endl;
}
}
//年龄
int age = 0;
cout << "请输入年龄: " << endl;
cin >> age;
abs->personArray[ret].m_Age = age;
//电话
string phone;
cout << "请输入联系电话: " << endl;
cin >> phone;
abs->personArray[abs->m_Size].m_Phone = phone;
//住址
string address;
cout << "请输入家庭住址: " << endl;
cin >> address;
abs->personArray[abs->m_Size].m_Addr = address;
}
else {
cout << "查无此人" << endl;
}
system("pause");
system("cls");
}
//6、清空联系人
void cleanPerson(Addressbooks* abs) {
abs->m_Size = 0;//逻辑清空操作
cout << "通讯录已清空" << endl;
system("pause");
system("cls");
}
//菜单界面
void showMenu() {
cout << "***************************" << endl;
cout << "***** 1、添加联系人 *****" << endl;
cout << "***** 2、显示联系人 *****" << endl;
cout << "***** 3、删除联系人 *****" << endl;
cout << "***** 4、查找联系人 *****" << endl;
cout << "***** 5、修改联系人 *****" << endl;
cout << "***** 6、清空联系人 *****" << endl;
cout << "***** 0、退出通讯录 *****" << endl;
cout << "***************************" << endl;
}
int main() {
Addressbooks abs;//创建通讯录结构体变量
abs.m_Size = 0;//初始化通讯录中当前人员个数
int select = 0;//创建用户选择输入的变量
while (true) {
//菜单调用
showMenu();
cin >> select;
switch (select) {
case 1://1、添加联系人
addPerson(&abs);//利用地址传递可以修饰实参
break;
case 2://2、显示联系人
showPerson(&abs);
break;
case 3://3、删除联系人
{
string name;
cout << "请输入删除联系人的姓名: " << endl;
cin >> name;
if (isExist(&abs, name) == -1) {
cout << "查无此人" << endl;
}
else {
cout << "找到此人" << endl;
}
deletePerson(&abs);
system("pause");
system("cls");
}
break;
case 4://4、查找联系人
findPerson(&abs);
break;
case 5://5、修改联系人
modifyPerson(&abs);
break;
case 6://6、清空联系人
cleanPerson(&abs);
break;
case 0://0、退出通讯录
cout << "欢迎下次使用" << endl;
system("pause");
return 0;
break;
default:
break;
}
}
system("pause");
return 0;
}