注:以下内容是在B站学习黑马C++课程时的笔记。
C++基础入门
1. 初识
1.1 万年不变的开始
-
#include <iostream> using namespace std; int main() { cout << "Hello world!" << endl; return 0; }
1.2 注释
-
代码 功能 // 描述信息
单行注释 /* 描述信息 */
多行注释
1.3 变量
- 作用:给一段内存空间起名,方便操作这段内存;
- 语法:
数据类型 变量名 = 初始值
;
1.4 常量
- 作用:记录不可更改的数据;
- 语法:
语法 定义位置 语法 #define 宏常量 文件上方 #define 常量名 常量值
const修饰的变量 变量定义前 const 数据类型 常量名 = 常量值
1.5 关键字
- 作用:预留单词,不可用于常量或变量的命名;
1.6标识符命名规则
- 不能是关键字;
- 只能字母、数字、下划线构成;
- 第一个字符必须是字母或下划线;
- 区分大小写
2. 数据类型
2.1 sizeof关键字
- 作用:统计数据类型占用内存大小;
- 语法:
sizeof(数据类型/变量)
2.2 整型
-
数据类型 占用空间 取值范围 short
(短整型)2字节 -215 ~ 215-1 int
(整型)4字节 -231 ~ 231-1 long
(长整型)Windows为4字节,
Linux为4字节(32位)/8字节(64位)-231 ~ 231-1 long long
(长长整型)8字节 -263 ~ 263-1
2.3 实型
- 作用:用于表示小数;
-
数据类型 占用空间 有效数字范围 单精度 float
4字节 7位有效数字;后面要加个 f
,例如3.14f
双精度 double
8字节 15~16位有效数字 - 无论哪种类型,默认都只显示6位有效数字,如需显示更多位要进行配置;
- 科学计数法
e
;例如3e2
、3e-2
;
2.4 字符型
- 作用:表示单个字符;
- 语法:
char ch = 'a'
;(注意①单引号②单个字符); - 占用1个字节,内存中实际存储的是ASCII码(
A
65,a
97);
2.5 转义字符
- 作用:表示不能显示出的ASCII字符;
- 常用:
\n
换行;\\
反斜杠字符;\t
水平制表(tab,8个字符一个表格);
2.6 字符串型
- 作用:表示字符串;
- C风格:
char 变量名[] = “字符串值”
- C++风格:
string 变量名 = “字符串值”
- 使用C++风格的时候,要包含头文件
#include <string>
2.7 布尔类型
- 作用:表示真假;
true
(1);false
(0);- 占用1字节;
- 布尔类型中,除了0代表假,其他都为真;
2.8 数据的输入
- 作用:用于从键盘获取数据;
- 语法:
cin >> 变量
;
3. 运算符
运算符类型 | 作用 | 符号 |
---|---|---|
算数运算符 | 四则运算 | + (正/加);- (负/减);* ;/ ;% (取模、取余);++ (前置递增/后置递增);-- (前置递减/后置递减); |
赋值运算符 | 给变量赋值 | = ;+= ;-= ;*= ;/= ;%= ; |
比较运算符 | 返回真或假 | == ;!= ;< ;> ;<= ;>= ; |
逻辑运算符 | 返回真或假 | && 与;|| 或;! 非; |
- 两整数想除,结果依然为整数,小数部分直接去除(没有四舍五入);
4. 程序流程结构
- 三种:顺序结构,选择结构,循环结构;
4.1 选择结构
4.1.1 if语句
if (条件1)
{
条件1满足执行的语句;
}
else if (条件2)
{
条件2满足执行的语句;
}
...
else
{
都不满足执行的语句;
}
4.1.2 switch语句
- 多条件分支语句;
case
判断时只能是整型或字符型;break
向外跳出一层,可有可无;- 注意:如果没有
break
,程序会一直向下执行所有的语句,但有时候也可以这样使用,比如不区分大小写时,可以这样
case 'a':
case 'A':
switch (表达式)
{
case 结果1:
执行语句;
break; //可选
case 结果2:
执行语句;
break; //可选
...
default:
执行语句;
break; //可选
}
4.1.3 三目运算符
- 语法:
表达式1 ? 表达式2 : 表达式3
; - 解释:1为真,返回2;1为假,返回3;
- 例:
c = a>b ? a : b
- 特殊:C++中三目运算符返回的是变量,可以继续赋值;
- 例:
(a>b ? a : b) = 100
,真则a = 100
,假则b = 100
;
4.2 循环结构
4.2.1 while语句
while (循环条件)
{
循环语句;
}
4.2.2 do…while语句
- 与while语句区别:先执行一次语句再判断循环条件;
do
{
循环语句;
} while (循环条件) ;
4.2.3 for语句
for (起始表达式;条件表达式;末尾循环体)
{
循环语句;
}
4.3 跳转语句
4.3.1 break
- 作用:跳出选择结构或循环结构;
- 使用:
1)switch
条件语句中,终止case
并跳出switch
;
2)循环语句中,包括for
、while
、do-while
语句,跳出当前循环语句;
3)嵌套语句中,跳出最近的内层循环语句;
4)对于if
判断语句无作用!
4.3.2 continue
- 作用:循环语句中,跳过后续语句,进入下一次循环;
4.3.3 goto(不建议使用,很混乱)
- 作用:无条件跳转语句;
- 语法:
goto 标记
- 解释:如果标记的名称存在,执行到
goto
时跳转到标记位置;
5. 数组
5.1 概述
- 数组中每个数据元素都是相同数据类型;
- 数组由连续的内存位置组成;
5.2 一维数组
- 定义方法:
1)数据类型 数组名[ 数组长度 ]
;
2)数据类型 数组名[ 数组长度 ] = { 值1, 值2, ... }
;若不够,填充0;
3)数据类型 数组名[ ] = { 值1, 值2, ... }
; - 通过下标进行访问数组元素,从0开始;
- 数组名的用途:
1)统计数组占在内存中的长度;sizeof(array)
;
2)获取数组在内存中的首地址;cout << array << endl
;
默认以十六进制数显示,可以利用int()
强转成十进制数;
查看某一元素的地址,要加&
,如cout << &array[0] << endl
数组名是常量,不可以进行赋值; - 冒泡排序:
#include <iostream>
using namespace std;
int main()
{
int array[] = {4, 2, 8, 0, 5, 7, 1, 3, 9};
int len = sizeof(array) / sizeof(array[0]);
bool exch = 1;
int times = 0;
for (int i = 0; i < len - 1; i++)
{
if (exch)
{
exch = 0;
times++;
for (int j = 0; j < len - 1 - i; j++)
{
if (array[j] > array[j + 1])
{
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
exch = 1;
}
}
}
}
cout << "一共扫描" << times << "次" << endl;
for (int i = 0; i < len; i++)
{
cout << array[i] << endl;
}
return 0;
}
5.3 二维数组
- 定义方法:
1)数据类型 数组名[ 行数 ][ 列数 ]
2)数据类型 数组名[ 行数 ][ 列数 ] = { {数据1,数据2} , {数据3,数据4} }
3)数据类型 数组名[ 行数 ][ 列数 ] = { 数据1,数据2,数据3,数据4}
4)数据类型 数组名[ ][ 列数 ] = { 数据1,数据2,数据3,数据4} in
6. 函数
6.1 定义
返回值类型 函数名 (参数列表)
{
函数体语句;
return表达式;
}
6.2 调用
函数名 (参数)
6.3 值传递
- 值传递,就是函数调用时实参将数值传入给形参;
- 值传递时,函数的形参发生改变,并不会影响实参;
6.4 函数样式
- 无参无返;有参无返;无参有返;有参有返;
- 无返回值的函数,返回值类型使用
void
; - 无返回值的函数,不可以创建变量 ,原因是无法非配内存;
6.5 函数的声明
- 提前告诉编译器函数的存在,函数即可写在
main
函数之后; - 声明可以有多次,但是定义只能有一次;
6.6 函数的分文件编写
- 步骤:
1)创建后缀名为.h
的头文件;
2)创建后缀名为.cpp
的源文件;
3)在头文件中写函数的声明;
4)在源文件中写函数的定义 - 例:
//swap.h 头文件
#include <iostream>
using namespace std;
void swap(int a, int b); //函数的声明
//swap.cpp 源文件
#include "swap.h" //使用双引号表示自定义的头文件
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
//main.cpp
#include <iostream>
using namespace std;
#include "swap.h"
int main()
{
int a = 10;
int b = 20;
swap(a,b);
return 0;
}
7. 指针
7.1 基本概念
- 作用:通过指针间接访问内存;
- 内存编号从0开始记录,一般用十六进制数表示;
- 可以利用指针变量保存地址(指针就是一个地址);
7.2 指针变量的定义和使用
- 指针变量的定义:
数据类型 * 变量名
- 示例:
int main()
{
//1.定义
int a = 10;
int * p; //定义指针
p = &a; //指针指向变量a的地址,&取址符
//2.使用
//指针前加*代表解引用,操作指针指向的内存中的数据
cout << "*p = " << *p << endl; //输出 *p = 10;
return 0;
}
7.3 指针所占内存空间
- 32位操作系统,4字节;
- 64位操作系统,8字节;
7.4 空指针和野指针
- 空指针:指向内存中编号为0的空间,用于初始化指针变量;
int * p = NULL
; - 空指针指向的内存是不可以访问的,因为0~255之间的内存编号是系统占用的;
- 野指针:指向非法的内存空间;
int * p = (int *) 0x1100
; - 野指针也不可以访问,而且应该尽量避免这种情况;
7.5 const修饰指针
- 三种情况:
1)const修饰指针 — 常量指针
const int * p = &a
指向可以修改,指向的值不可修改;
2)const修饰常量 — 指针常量
int * const p = &a
指向不可修改,指向的值可以修改;
3)const既修饰指针,又修饰常量
const int * const p = &a
指向和指向的值都不可修改; - const竟然可以直接在函数定义时的形参中使用OHHHHHHH
7.6 指针和数组
- 利用指针访问数组中的元素;
- 例,遍历数组:
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
int *p = arr;
for (int i = 0; i < 10; i++)
{
cout << *p << endl;
p++;
}
return 0;
}
7.7 指针和函数
- 地址传递:利用指针作为函数参数,可以修改实参的值;
(区别于前面的值传递)
//值传递
void swap1(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
//地址传递
void swap2(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main()
{
int a = 10;
int b = 20;
swap1(a, b);
cout << a << ' ' << b << endl; //输出 10 20
swap2(&a, &b);
cout << a << ' ' << b << endl; //输出 20 10
return 0;
}
7.8 数组、指针和函数
- 注:结构体之后进行的补充(两种地址传递的形式)
struct Student { string name; int age; int score; }; void getInf(Student *arr) //void getInf(Student arr[]) 这样写同样也是地址传递!! { arr[0].age = 5; } int main() { Student stuArr[3]; getInf(stuArr); cout << stuArr[0].age << endl; }
8. 结构体
8.1 概念
- 用户自定义的数据类型,允许用户存储不同的 数据类型;
8.2 定义和使用
- 语法:
struct 结构体名 { 结构体成员列表 }
;
//创建学生类型
struct Student
{
string name;
int age;
int score;
};
struct
关键字在定义结构体时不可省略,但是在创建变量时可以省略;- 通过结构体创建变量的方式:
1)struct 结构体名 变量名
;
2)struct Student s1; //struct可省略 s1.name = "Jack"; s1.age = 18; s1.score = 100;
struct 结构体名 变量名 = { 成员1值, 成员2值 ... }
;
3)定义结构体时顺便创建变量(很少用);struct Student s2 = {"Rose", 19 ,90}; //struct可省略
struct Student { string name; int age; int score; } s3; int main(): { s3.name = "Sam"; s3.age = 20; s3.score = 85; }
8.3 结构体数组
- 创建方式:
struct 结构体名 数组名[元素个数] = { { }, { }, ..., { }}
Student stuArray[3] = { {"Jack", 18, 100}, {"Rose", 19 ,90}, {"Sam", 20 85}};
8.4 结构体指针
-
Student s = {"Rose", 19 ,90}; Student *p = &s; cout << p->name << endl; //通过箭头访问
8.5结构体嵌套结构体
-
struct Student { string name; int age; int score; }; struct Teacher { int id; string name; int age; struct Student stu; }; int main() { Teacher t; t.id = 10000; t.name = "Wang"; t.age = 50; t.stu.name = "Jack"; t.stu.age = 18; t.stu.score = 100; return 0;
8.6 结构体做函数参数
- 在地址传递中:
结构体做参数时,使用->
访问结构体中的成员;
结构体数组做参数时,使用.
访问结构体中的成员;
例1如下,例2参见7.8节。 -
//值传递 void printStudent1(Student s) { cout << s.name << endl; s.age = 200; //形参改变,外部实参依然不变 } //地址传递 void printStudent2(Student *s) { cout << s->name << endl; s->age = 200; //形参改变,外部实参也会改变 } int main() { struct Student s1 = {"Jack", 18, 100}; printStudent1(s1); printStudent2(&s1); }
8.7 结构体中的const使用场景
- 作用:防止误操作;
void printStudent2(const Student *s) { s->age = 200; //此时就会报错!! cout << s->name << endl; } //void printStudent2(Student *const s) //{ // s->age = 200; //这样不会报错,但const加与不加都可修改。 // cout << s->name << endl; //} int main() { struct Student s1 = {"Jack", 18, 100}; printStudent2(&s1); }
其他
- 生成随机数:
#include<ctime> //time系统时间头文件
int main() {
//添加随机种子,利用当前系统时间生成随机数,避免每次随机数都一样
srand((unsigned int)time(NULL));
//生成1~100的随机数
int num = rand()%100 + 1;
}
- Visual Studio Code可以通过以下快捷键格式化代码:
操作系统 快捷键 Windows Shift + Alt + F
Mac Shift + Option + F
Ubuntu Ctrl + Shift + I