欢迎大家来一块学习与进步,此文章旨在进行C++的基础知识回顾,后续会针对C++特性进行复习总结,此文章请核心关注代码块中的注释总结
相关资料有需要的可以评论或者私信!!!
1.基础模版与注释方式
1.1基础模版
cpp
#include <iostream>
using namespace std;
int main() {
system("pause");
return 0;
}
1.2注释方式
cpp
#include<iostream>
using namespace std;
/*
添加多行注释
main 函数是一个函数的入口,
每个程序必须有一个这样的函数,
有且只有一个!!!
*/
int main() {
// 添加单行注释
cout << "hello world" << endl;
return 0;
}
2.变量与常量
2.1变量
cpp
#include <iostream>
using namespace std;
int main() {
// 变量的定义
// 语法:数据类型 变量名 = 初始值;
int a = 5;
cout << "a = " << a << endl;
return 0;
}
2.2常量
cpp
#include <iostream>
using namespace std;
/*
* 常量的定义方式:
* #define 宏常量
* const 修饰的变量
*/
#define Day 7 //常量不可修改
int main() {
const int a = 1;
cout << "Day = " << Day << ",a = " << a << endl;
return 0;
}
3.关键字与标识符
3.1关键字
**作用:**关键字是C++中预先保留的单词(标识符)
- 在定义变量或者常量时候,不要用关键字
C++关键字如下:
| asm | do | if | return | typedef |
|---|---|---|---|---|
| auto | double | inline | short | typeid |
| bool | dynamic_cast | int | signed | typename |
| break | else | long | sizeof | union |
| case | enum | mutable | static | unsigned |
| catch | explicit | namespace | static_cast | using |
| char | export | new | struct | virtual |
| class | extern | operator | switch | void |
| const | false | private | template | volatile |
| const_cast | float | protected | this | wchar_t |
| continue | for | public | throw | while |
| default | friend | register | true | |
| delete | goto | reinterpret_cast | try |
3.2标识符
cpp
#include <iostream>
using namespace std;
int main() {
/*
* 标识符不能是关键字
* 只能由字母、数字、下划线组成
* 第一个字符必须为字母或者下划线
* 区分大小写
*/
// 见名知意!!!
return 0;
}
4.数据类型与运算符
4.1数据类型
cpp
#include <iostream>
#include <string>
using namespace std;
/*
* sizeof 关键字
* 用法:sizeof( 数据类型/变量 )
*/
/*
* 整型:short, int,
* long(Linux中32位系统为4位,64位系统为8位), long long
* 浮点型:float, double
* 科学计数法(例如:3e2 -> 3 * 10^2,3e-2 -> 3 * 0.1^2)
* 默认情况下 输出小数会显示6位有效数字
* 字符型:char
* 语法: char ch = 'a';
* 字符型变量并不是把字符本身放到内存中,而是将其对应的ASCII编码放入到内存中
* cout << (int)ch << endl;
* 'a' - 'A' = 32, A = 65, a = 97, 0 = 48
* 转义字符:反斜杠\ 用于表示一些不能显示出来的ASCII字符
* \n 换行,\\ 反斜杠,\t 制表符(补满8个字符位)
* 字符串型:C语言风格:char 变量名[] = "字符串值";
* Cpp风格: string 类型名 = "字符串值"; #include<string>
* 布尔类型: true(1) false(0) 单字节
* 用法:bool 变量名 = true/false;
* 数据的输入:cin >> 变量
*/
int main() {
float f1 = 3.14f; // (默认情况下编译器会将其认为双精度)
string str = "abcde";
cout << str << endl;
/*string a = "hello";
cout << "请输入字符串型变量a的值:" << endl;
cin >> a;
cout << "字符串变量:" << a << endl;*/
bool flag = false;
cout << "请给布尔类型变量赋值:" << endl;
cin >> boolalpha >> flag;
cout << "布尔类型变量:" << flag << endl;
return 0;
}
4.2运算符
cpp
#include <iostream>
using namespace std;
/*
* 算术运算:
* 加减乘除:+ - * /
* 除法:两个数相除,除数不为0;两小数可相除
* 取余:%
* 本质就是求余数,操作对象必须为整型
* 自增自减 区分前置和后置
* 前置:先变量 +/- 1后运算表达式;后置:先运算表达式后 +/- 1
* ------------------------------------------------------------
* 赋值运算:= , += , -= , *= , /= , %=
* 比较运算符:== , != , < , > , <= , >=
* 逻辑运算符:! , && , ||
* 位运算:&(位与),|(位或),^(异或),~(取反),
<<(左移,低位补0),>>(右移,高位补符号位或无符号补0) ->乘以/除以2的n次
*/
int main() {
int arr[] = { 10, 20, 30, 40 };
int* p = arr;
printf("初始: p指向arr[0]=%d\n", *p);
// 情况1: *p++
printf("*p++ = %d\n", *p++); // 输出10,p指向arr[1]
printf("现在p指向: %d\n", *p); // 输出20
// 情况2: *++p
printf("*++p = %d\n", *++p); // 先p++指向arr[2],输出30
printf("现在p指向: %d\n", *p); // 输出30
// 情况3: ++*p 等价于 (*p)++
printf("++*p = %d\n", ++*p); // *p自增1,输出31
printf("现在*p的值: %d\n", *p); // 输出31
return 0;
}
5.程序流程结构与数组
5.1程序流程结构
cpp
#include <iostream>
using namespace std;
#include <ctime>
/*
* 选择结构:
单行if语句( if(){} ),多行if语句( if(){} else {} ),
多行if语句( if(){} else if(){} ... else{} ),
if语句嵌套( if( if(){} else{} ){} else{} )
三目运算符 表达式1?表达式2:表达式3 ( 真执行前者表达式,假执行后者表达式 )
特殊的,在C++中三目运算符返回的是变量,可以继续赋值
switch语句( switch(条件){ case 结果1: 语句;break; ... default:语句; } )
条件必须是整数或者字符,结果n是常量表达式
比较:与if语句比,对于多条件判断时,switch的结构清晰,执行效率高,缺点是switch不可以判断区间
* 循环结构:
while语句( while(循环条件){循环语句;} )
do while语句( do{循环语句;} while(循环条件); )
for语句( for(;;){ } )
嵌套循环
* 跳转语句:
break关键字:用于跳出循环结构 或者 选择结构
switch语句,循环语句,嵌套循环结构
continue语句:在循环语句中跳过本次循环剩余未执行部分进行下一次循环
goto语句:可用于无条件跳转到指定标记位置(特殊的也可以用作循环)
goto 标志; -> 标志:
*/
int main() {
int score = 0;
cin >> score;
if (score >= 600) {
if (score >= 700)
cout << "恭喜你考上北大" << endl;
else
cout << "恭喜你考上一本" << endl;
}
else if (score >= 500)
cout << "恭喜你考上二本" << endl;
else if (score >= 400)
cout << "恭喜你考上三本" << endl;
else
cout << "很遗憾你未考上本科" << endl;
//---------------------------------------
int a = 20, b = 30;
(a > b ? a : b) = 100;
cout << "a = " << a << ",b = " << b << endl;
//---------------------------------------
srand((unsigned int)time(NULL)); // 随机数种子
int num = rand() % 100 + 1;
//---------------------------------------
system("pause");
return 0;
}
5.2数组
cpp
#include <iostream>
using namespace std;
/*
* 一维数组
定义方式:数据类型 数组名[ 数组长度 ]; 数据类型 数组名[ 数组长度 ] = {值1,值2,...};
数据类型 数组名[ ] = {值1,值2,...};
特点:放在一块连续内存空间中;每个元素都是相同的类型;定长数组未给满数据时补0/空
数组名用途:统计整个数组在内存中的长度;获取数组在内存中的首地址;数组名是一个常量不可以被修改或者赋值
* 二维数组
定义方式:数据类型 数组名[ 行数 ][ 列数 ];
数据类型 数组名[ 行数 ][ 列数 ] = { {数据1,数据2 } ,{数据3,数据4 } };
数据类型 数组名[ 行数 ][ 列数 ] = { 数据1,数据2,数据3,数据4};
数据类型 数组名[ ][ 列数 ] = { 数据1,数据2,数据3,数据4};
数组名用途:查看二维数组所占内存空间;查看二维数组首地址(第一行地址(注意虽然和第一个元素的地址数值一样但是类型不同))
二维数组名会退化为指向第一行的指针,类型为 指向一维数组的指针
int arr[3][4];// arr 的类型是 int (*)[4],指向包含 4 个 int 的一维数组
int (*p)[4] = arr; // 正确:p 指向第一行
*/
void sort(int arr[], int len) {
for (int i = 0; i < len-1; i++) {
for (int j = 0; j < len-i-1; j++) {
if (arr[j] > arr[j+1]) {
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
for (int i = 0; i < len-1; i++) {
if (i == len-2) {
cout << arr[i];
}
else {
cout << arr[i] << ",";
}
}
cout << endl;
}
int main() {
//char arr[5] = {'a','b'};
//float arr[5] = { 3.14,2.28 };
int arr[10] = { 3,7,5,9,0,-2,12,89,56,90 };
int len;
len = sizeof(arr) / sizeof(arr[0]);
/*for (int i = 0; i < len; i++) {
cout << arr[i] << endl;
}*/
sort(arr, len);
//------------------------------------------
int arr1[2][3] =
{
{1,2,3},
{4,5,6}
};
cout << "二维数组大小: " << sizeof(arr1) << endl;
cout << "二维数组一行大小: " << sizeof(arr1[0]) << endl;
cout << "二维数组元素大小: " << sizeof(arr1[0][0]) << endl;
cout << "二维数组行数: " << sizeof(arr1) / sizeof(arr1[0]) << endl;
cout << "二维数组列数: " << sizeof(arr1[0]) / sizeof(arr1[0][0]) << endl;
//地址
cout << "二维数组首地址:" << arr1 << endl;
cout << "二维数组第一行地址:" << arr1[0] << endl;
cout << "二维数组第二行地址:" << arr1[1] << endl;
cout << "二维数组第一个元素地址:" << &arr1[0][0] << endl;
cout << "二维数组第二个元素地址:" << &arr1[0][1] << endl;
system("pause");
return 0;
}
6.函数规范及分文件编程示例
main函数:
cpp
#include "swap.h"
/*
* 函数:
语法:返回值类型 函数名( 形参列表 ){ 函数体语句; return表达式; }
调用:函数名( 实参 ); 值传递和址传递
样式:无参无返,有参无返,无参有返,有参有返
函数声明:返回值类型 函数名( 形参列表 );
提前告知编译器函数的存在!
声明可以多次编写,但是定义只能有一份!
* 分文件编写:
实现步骤:创建头文件(.h),创建源文件(.cpp),在头文件中声明,在源文件中定义
*/
int main() {
int a = 10, b = 20;
swap(a, b);
return 0;
}
分文件函数:
cpp
//头文件
#pragma once
#include<iostream>
using namespace std;
//实现两个数字交换的函数声明
void swap(int a, int b);
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;
}
7.指针
cpp
#include <iostream>
using namespace std;
/*
* 指针:
用途:可以通过指针间接访问内存地址
内存编号是从0开始记录,一般用十六进制数表示;可以利用指针变量保存地址
定义:数据类型* 指针变量名; 示例:int* p; p = &a;
解引用:*指针变量名
获取指针指向内存地址的数据,可用于读取或者修改!
内存空间:大小恒定 -> 64位系统:8字节;32位系统:4字节
空指针:指针变量指向内存中编号为0的空间 int *p = NULL;
用于初始化指针变量;空指针指向的内存空间不可访问
野指针:指向非法的内存空间
示例:随便指向一个数字:int *p = (int *)0x1100; (×)
* const关键字:
const修饰指针的三种形式: const往右看,看离得谁近谁就不可以修改(也可从右往左读)/const读作常量,*读作指针,看位置读
常量指针(const修饰指针):const int* p = &a;/int const * p; 指针的指向可以修改,指针指向的值不可修改。
p是指针,指向const int类型的数据
指针常量(const修饰常量):int * const p = &a; 指针的指向不可以修改,指针指向的值可以修改。(指针是一个常量)
p是const类型的指针,指向int类型的数据
指向常量的常量指针:const int * const p = &a;/int const* const p;
p是const类型的指针,指向const int类型的数据
* 指针和数组:
利用指针访问数组中的元素 int arr[10]; int *p = arr; *p;/p++;(指针向后偏移4字节)*p;
* 与 前++优先级一致,从右往左进行运算( *++p/++*p );
前++ 先自身+1后干别人让干的事:*++p(先给p+1后解引用),++*p(先对*p进行+1后去干别人让干的事)
后++时,从左往右运算,可以理解为先进行 * 解引用后++( *p++ )
实际 "后++" 优先级高于 "*" ,编译器底层会开辟无名空间,先保存当前p指向的地址后进行p+1操作,然后解引用保存的原先地址
* 指针与函数:
利用指针作为函数形参可以改变实参的值,即地址传递 swap(&a, &b); //地址传递会改变实参
void swap(int *p); / void swap(int arr[]); / void swap(int arr[n]);//n可以为任意合法值,但是编译器会忽略这里的数组大小
优势在于形参为指针可以减少内存空间占用,而且不会复制新的副本出来
*/
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;
}
system("pause");
return 0;
}
8.结构体
cpp
#include <iostream>
using namespace std;
/*
* 结构体:
* 定义:属于用户自定义的数据类型,允许用户存储不同的数据类型
* 语法:struct 结构体名 { 结构体成员列表; };
* 创建变量方式:
struct 结构体名 变量名
struct 结构体名 变量名 = { 成员1值 , 成员2值...}
定义结构体时顺便创建变量
!!! 创建变量时在C++中 struct 关键字可以省略:Student s1;
C语言中通常不可以省略,可以用typedef定义别名:
typedef struct Node{}Node; typedef struct{}Node;
* 结构体变量访问方式:
方式1:struct Student s1;// 创建结构体变量 s1.id = 1001;// 点运算符访问成员
方式2:struct Student s1 = {1001, "张三", 95.5}; struct Student *ptr; // 结构体指针
ptr = &s1; // 指向s1 ptr->score = 98.0;// 箭头运算符访问与修改成员
!!! ptr->name 等同于 (*ptr).name
* 结构体数组:struct 结构体名 数组名[元素个数] = { {} , {} , ... {} }
* 结构体指针:利用操作符 -> 可以通过结构体指针访问结构体属性
* 结构体嵌套结构体:在结构体中可以定义另一个结构体作为成员,用来解决实际问题
* 结构体做函数参数:值传递和地址传递
值传递:void printStudent( student stu ){} //依旧可以省略struct关键字
地址传递:void printStudent2(student *stu){} // !!! 通常在C++中想修改实参不采用传递指针,而是采用别名引用(后续)
* 结构体中const关键字的使用:
用const来防止误操作!!! -> 常量指针
void printPoint(const struct Point* p) {
// p->x = 10; // 错误!不可修改
printf("(%d, %d)\n", p->x, p->y);
}
*对齐补齐规则:
* 对齐:每个成员的起始地址必须是其类型大小的整数倍;结构体总大小必须是最大成员对齐值的整数倍;
* 补齐:不满足对齐规则就补
* 优化规则:
从大到小排列成员:double → long → int → short → char
相同类型放一起:减少补齐
数组放在最后:避免拆分
1字节成员最后:char、bool放末尾
考虑缓存行:对齐到64字节边界
网络传输用1字节对齐:避免平台差异 #pragma pack(1)
性能敏感结构体单独优化:不要依赖默认对齐
* 修改对齐方式
#pragma pack(push, n) // 保存当前对齐设置,并设置新的对齐值n
#pragma pack(pop) // 恢复之前保存的对齐设置
#pragma pack(n) // 直接设置对齐值n(不推荐,不保存状态)
* 查看成员偏移量
函数头文件:#include <cstddef>
函数原型:offsetof(MyClass, member)
*/
//结构体类型声明
struct student{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
};
int main() {
// 省略struct关键字
struct student stu = { "张三",18,100, };
student* p = &stu;
system("pause");
return 0;
}
作者:趙小贞
声明:本文基于个人学习经验总结,如有错误欢迎指正!
版权:转载请注明出处,禁止商业用途。
声明:整体内容原创,用于复习总结以及分享经验,欢迎大家指点!