cpp(c++)基础
基础
创建项目
1、在 c++、windows 的筛选条件下,选择创建一个新的 空项目
2、新建 cpp 文件,Source Files --> Add --> New Item
3、如下选择 c++ 文件
基本规则
1、一个 c++ 程序只能有一个 main() 函数,若存在多个则程序无法运行
2、c++ 关键字
- 1)、数据类型
- short、int、long、 float、double、bool、char、enum、true、false、wchar_t
- 2)、流程控制
- break、continue、switch、case、try、catch、if、else、do、for、throw、while
- 3)、标识关键字
- class、const、const_cast、dynamic_cast、namespace、new、private、public、reinterpret_cast、return、signed、unsigned、static、static_cast、this、using、virtual、void、volatile、
- 4)、其他
- asm、auto、default、delete、explicit、export、extern、friend、goto、inline、mutable、opeartor、protected、register、sizeof、struct、template、typedef、typeid、typename、union
hello world
#include <iostream>
using namespace std;
int main() {
cout << "hello world" << endl;
system("pause");
return 0;
}
注释
单行注释: //
多行注释: /* */
变量
c++大小写敏感,且标识符规则如下:
- 不能为关键字
- 字母、数字、下划线组成
- 第一个字符必须是字母或下划线
声明语法:
数据类型 变量名 = 值;
如:
int a = 10
#include <iostream>
using namespace std;
int main() {
int a = 10;
cout << "a = " << a << endl;
system("pause");
return 0;
}
常量
两种常量定义方式:
1、宏常量。#define 常量名 常量值 —— 需要在文件上方定义
2、const修饰变量。const 常量类型 常量名 常量值
数据类型
c++在创建一个变量或者常量的时候,必须要指定出相应的数据类型,否则无法为变量分配内存
原因:分配合理的大小以节省内存空间
整型
数据类型 | 占用空间 | 取值范围 |
---|---|---|
short | 2字节 | (-2^15~2^15-1) |
int(最常用) | 4字节 | (-2^31~2^31-1) |
long | 4字节(windows、linux 32bit)、8字节(linux 64bit) | (-2^31~2^31-1) |
long long | 8字节 | (-2^63~2^63-1) |
大小关系:
short < int <= long(与操作系统有关)<= long long
注:当超出取值范围时,并不会抛出异常,而是用 “最小值(负值) + (超出的值 - 1)”作为当前值,如:
// 此值输出为 -32768
short s = 32768;
// 此值输出为 -32767
short s = 32769;
实型(浮点型)
数据类型 | 占用空间 | 取值范围 |
---|---|---|
float | 4字节 | 7 位(小数点前后总个数)有效数字 |
double | 8字节 | 15 ~ 16 位(小数点前后总个数)有效数字 |
注意
定义 float 时,作为值的数字后要加个 f,否则将被识别为 double ,如 float a = 3.14f;
科学计数法:
- 3.14e2 —— 3.14 * 10^2
- 3.14e-2 —— 3.14 * 10^(-2)
字符型
含义:字符型变量用于显示单个字符
语法:char ch = ‘a’
注意:
- 字符型只支持单引号
- 单引号内只有一个字符
- 字符型变量在 c/c++ 中只占一个字节
- 字符型变量并不是把字符本身放到内存中,而是把ASCII码放入存储单元
查看字符对应的 ASCII 码,使用 (int) 来将数据强转为 int 型,则对其对应ASCII码
转义字符
写法 | 含义 | ASCII码 |
---|---|---|
\a | 警报 | 007 |
\b | 退格(BS),将光标位置移动到前一列 | 008 |
\f | 换页(FF),将光标位置移动到下页开头 | 012 |
\n | 换行(LF),将光标位置移动到下一行开头 | 010 |
\r | 回车(CR),将光标位置移动到本行开头 | 013 |
\t | 水平制表(HT),跳到下一个TAB位置 | 009 |
\v | ||
注: \t 代表移动到下个 TAB 位置,一个 TAB 位置占 8 个空格,其特别处如下
- “aaa\tbbb” —— aaa 和 bbb 中间有5个空格
- “aa\tbbb” —— aa 和 bbb 中间有6个空格
- “aaaaa\tbbb” —— aaaaa 和 bbb 中间有3个空格
- “aaaaaaaa\tbbb” —— aaaaaaaa 和 bbb 中间有8个空格,当字符占满当前 TAB 位置时,移动到下下个 TAB 位置
字符串
C 风格字符串: char ch[] = “abc”;
C++ 风格字符串: string ch = “abc”;
注意:在使用 C++ 风格字符串的时候,要引入头文件(C ++ 11之后不需要)#include<string> string str1 = "abc";
布尔型
布尔型只占用一个字节内存
- true —— 真,本质为1
- false —— 加,本质为0
数组
含义:放在一块连续的内存空间中,数组中每个元素都是相同数据类型
定义方式:
1、数据类型 数组名[数组长度];
2、数据类型 数组名[数组长度] = {值1, 值2, …}; —— 若初始化的时候没有补齐元素,则使用 0 进行填充
3、数据类型 数组名[] = {值1, 值2, …}
注意:
1、若使用 int arr[5]; 的形式进行数组声明,则会有如下情况:
- 所有数组内的值均为 -858993460
- 数组外的值均为随机值 —— 当取 arr[10] 回随机返回一个数
2、若使用 int arr[5] = {10, 20, 30} 的形式进行声明,则:
- 数组中未明确定义的部分默认赋值 0
- 数组外的值均为随机值 —— 当取 arr[10] 回随机返回一个数
3、若使用 int arr[] = {10, 20, 30}; 的形式进行声明,则:
- 数组外的值均为随机值 —— 当取 arr[10] 回随机返回一个数
常用方法
1、获取数组长度
sizeof(arr)/sizeof(arr[0]);
2、获取数组内存首地址
cout << arr << endl;
3、查看元素内存地址
&arr[0]
4、数组逆序
#include<iostream>
using namespace std;
int main(void)
{
int arr[5] = {1, 3, 2, 5, 4};
int arrLen = sizeof(arr) / sizeof(arr[0]);
int arrNew[5];
int end = arrLen - 1;
int start = 0;
// 元素互换
while (start < end) {
int _ = arr[start];
arr[start] = arr[end];
arr[end] = _;
start++;
end--;
}
for (int i = 0; i < arrLen;i++) {
cout << arr[i] << endl;
}
system("pause");
return 0;
}
二维数组
定义方式:
1、数据类型 数组名[ 行数 ][ 列数 ];
2、数据类型 数组名[ 行数 ][ 列数 ] = { {数据1, 数据2}, {数据3, 数据4}};
3、数据类型 数组名[ 行数 ][ 列数 ] = { 数据1, 数据2, 数据3, 数据4};
4、数据类型 数组名[ ][ 列数 ] = { 数据1, 数据2, 数据3, 数据4};
常用第二种
1、获取整个数组所占内存空间
sizeof(arr)
2、获取数组第一行所占内存空间
sizeof(arr[0])
3、获取数组有多少行
sizeof(arr)/sizeof(arr[0])
4、获取数组有多少个元素
sizeof(arr) / sizeof(arr[0][0])
5、获取数组有多少列
cout << sizeof(arr[0]) / sizeof(arr[0][0]) << endl;
结构体(struct)
作用:创建用户自定义的数据类型。结构体可以定义在函数外部(包括 main 函数)
定义语法:struct 结构体名 { 结构体成员列表 };
注:成员列表类似属性
结构体的使用:
方法一:struct Student s1; 或者 Student s1;
方法二:struct Student s2 = {}; 或者 Student s2 = {};
方法三:在定义结构体时,顺便创建结构体变量
获取属性(属性可读可写):s1.name;
如:
#include<iostream>
#include<string>
using namespace std;
int main(void)
{
struct Student {
string name;
int age;
int score;
};
// 方法一
Student s1;
// 设置属性
s1.name = "zs";
s1.age = 18;
s1.score = 100;
cout << "s1.name: " << s1.name << endl;
cout << "s1.age: " << s1.age << endl;
cout << "s1.score: " << s1.score << endl;
// 方法二
Student s2 = { "ls", 19, 80 };
cout << "s2.name: " << s2.name << endl;
cout << "s2.age: " << s2.age << endl;
cout << "s2.score: " << s2.score << endl;
// 方法三
struct Teacher {
string name;
int age;
int score;
}s3;
s3.name = "ww";
s3.age = 40;
s3.score = 999;
cout << "s3.name: " << s3.name << endl;
cout << "s3.age: " << s3.age << endl;
cout << "s3.score: " << s3.score << endl;
system("pause");
return 0;
}
结构体数组
作用:将自定义的结构体放入到数组中方便维护
语法:struct 结构体名称 数组名[元素个数] = { {}, {}, {}, {} }
注意:结构体数组可以在函数中进行修改,并且无论是修改结构体数组(如修改数组中结构体的顺序)还是修改其中的结构体(如修改结构体的属性),都会直接生效于全局变量。因为结构体数组作为形参的时候,会把实参的指针传入进来。而单独的结构体,则依旧是新生成一个结构体。
#include<iostream>
#include<string>
using namespace std;
int main(void)
{
struct Student {
string name;
int age;
int score;
};
Student arr[3] = {
{"zs", 18, 100},
{"ls", 19, 80},
{"ww", 25, 60}
};
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
cout << arr[i].name << endl;
cout << arr[i].age << endl;
cout << arr[i].score << endl;
}
system("pause");
return 0;
}
结构体指针
作用:通过指针访问结构体中的成员
注意:利用操作符 ‘->’ 可以通过结构体指针访问结构体属性
实现方法:通过 &结构体 来获取结构体的地址,并赋值给指针对象。
如:
# 创建结构体对象
1、Student stu = {…};
# 创建结构体指针
2、struct Student * p = &stu;
# 通过结构体指针输出值
3、cout << p->name <<endl;
嵌套结构体
含义:在一个结构体中嵌套另外一个结构体
#include<iostream>
#include<string>
using namespace std;
struct Student {
string name;
int age;
int score;
};
struct Teacher {
string name;
int age;
int score;
struct Student stu;
};
int main(void)
{
// 创建对象方法一
Teacher t1;
t1.name = "teacher";
t1.age = 50;
t1.score = 100;
t1.stu.name = "zs";
t1.stu.age = 18;
t1.stu.score = 60;
// 创建对象方法二
Teacher t2;
t2.name = "teacher";
t2.age = 50;
t2.score = 100;
t2.stu = { "zs", 18, 80 };
// 创建对象方法三
Student s1 = { "zs", 15, 60 };
Teacher t3;
t3.name = "teacher";
t3.age = 60;
t3.score = 20;
t3.stu = s1;
cout << t3.name << endl;
cout << t3.age << endl;
cout << t3.score << endl;
cout << t3.stu.name << endl;
cout << t3.stu.age << endl;
cout << t3.stu.score << endl;
system("pause");
return 0;
}
结构体做函数参数
含义:将结构体作为参数传递给函数
注意:
1、以值的形式传递结构体,即使在函数内部修改了其值也不会影响函数外部的结构体
2、以指针的形式传递结构体,那么若在函数内部修改了结构体,则函数外部的结构体也会被修改
#include<iostream>
#include<string>
using namespace std;
struct Student {
string name;
int age;
int score;
};
// 值传递函数
void print(struct Student stu) {
cout << stu.name << endl;
cout << stu.age << endl;
cout << stu.score << endl;
stu.name = "zs";
stu.age = 30;
stu.score = 60;
cout << stu.name << endl;
cout << stu.age << endl;
cout << stu.score << endl;
};
// 指针传递函数
void print2(struct Student * stu) {
cout << stu->name << endl;
cout << stu->age << endl;
cout << stu->score << endl;
stu->name = "zsssss";
stu->age = 20;
stu->score = 80;
};
int main(void)
{
Student s1 = { "ls", 18, 80 };
print2(&s1);
cout << s1.name << endl;
cout << s1.age << endl;
cout << s1.score << endl;
system("pause");
return 0;
}
结构体中 const 的使用场景
1、在函数的形参中使用 const Student * stu,使用常量指针作为形参,则代表该参数为指针且指针指向的值不可改(注意,形参定义时没有了 struct 关键字)
数学运算
c++ 中的 +、-、* 都与正常的无异,但是 / 比较特别
- 两个整数相除,得到的结果仍为整数,小数部分直接舍弃
操作 | 结果 | 例如 |
---|---|---|
整数 / 整数 | 整数 | 10 / 3 --> 3(int) |
整数 / 浮点数 | 浮点数 | 10 / 2.0 --> 5(float) |
整数 / 双精度 | 双精度 | 10 / 2.0 --> 5(double) |
浮点数 / 整数 | 浮点数 | 10.0 / 2 --> 5 (float) |
双精度 / 整数 | 双精度 | 10.0 / 2 --> 5 (double) |
浮点数 / 双精度 | 双精度 | 10.0 / 2.0 --> 5(double) |
双精度 / 浮点数 | 浮点数 | 10.0 / 2.0 --> 5(double) |
前后++ 的区别:
- 前++ —— 先对值做加法运算
- 后++ —— 先对值做其他操作,操作完成后再进行 ++
如:
int a1 = 10;
int a2 = 10;
// b的值是 11
int b = ++a1;
// c的值是 10
int c = a2++;
逻辑运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
! | 非 | !a | 取 a 的布尔值的反 |
&& | 与 | a && b | 同真为真,支持短路逻辑 |
|| | 或 | a || b | 同假为假,支持短路逻辑 |
数据交互
从键盘获取(cin)
作用:将 cmd 中输入的值赋予变量,数据类型与变量相同
语法: cin >> 变量
char ch;
cout << "请给 ch 赋值: ";
cin >> ch;
cout << "ch = " << ch << endl;
程序运行控制
选择结构
if
if(条件){代码}
三目运算符
表达式1 ? 表达式2 : 表达式3
如:c = a > b ? a : b
当 a > b 时,c = a ,否则 c = b
注意:三目运算符返回的是变量,可以继续进行赋值
如: (a > b ? a : b) = 100;
当 a > b 时,返回 a,并且将 a 的值赋值为 100。否则将 b 的值赋值为 100
switch 语句
switch(表达式){
case 结果1: 执行语句; break;
case 结果2: 执行语句; break;
case 结果3: 执行语句; break;
default: 执行语句; break;
}
在表达式中进行运算,当结果与 case 中的某个匹配时,即执行对应 case 的语句。
注意:若 case 中没有 break,则其下方的 case 也会执行,直到遇到 break 或者 进入 default 并执行完毕
switch 的局限性:只能判断 整型 或者 字符串 型,不可以是一个区间(浮点会有浮点误差)
循环
while
while(循环条件){执行语句}
break
结束循环
for
for( 起始表达式;条件表达式;末尾循环体 ){ 循环体 }
continue
跳过本次循环进入下一次循环
do…while
do{循环体}while(循环条件);
先执行 do ,第二次再判断是否符合 while 的条件
goto语句
作用:直接跳转到指定代码位置
语法:goto 标记、标记:
一般不建议使用
#include<iostream>
using namespace std;
int main(void)
{
cout << 1 << endl;
cout << 2 << endl;
goto FLAG;
cout << 3 << endl;
cout << 4 << endl;
FLAG:
cout << 5 << endl;
system("pause");
return 0;
}
函数
定义步骤:
1、返回值类型
2、函数名
3、参数列表
4、函数体语句
5、return 表达式
如:返回值类型 函数名 (参数列表){ 函数体 return 表达式 }
注意要定义在 main 函数的上方,定义在 main 函数的下方无法通过编译。除非在 main 上方进行函数声明,这样的话可以在 main 之后进行内容的编写
函数声明:只写大括号之前的内容,如:int add(int a, int b);
函数的分文件编写步骤:
1、创建后缀名为 .h 的头文件
2、创建后缀名为 .cpp 的源文件
3、在头文件中写函数的声明
4、在源文件中写函数的定义
5、在源文件中引入头文件,#include “头文件名.h”
6、在调用的文件中,引入头文件即可,#include “math_calc.h”
基本函数的编写
int add(int num1, int num2) {
int num3 = num1 + num2;
return num3;
}
函数的分文件编写
1、头文件的编写
2、源文件编写
3、函数调用
指针
含义:指针是一个变量,该变量存储的是一个内存地址
定义指针:
1、定义一个正常变量
2、定义一个和正常变量相同的类型的指针变量
3、让指针记录正常变量的地址
如:
1、int a = 10;
2、int * p;
3、p = &a;
指针解引用: *p,找到指针指向地址的值,可以取值也可设值
如
#include<iostream>
#include<string>
using namespace std;
int main(void)
{
int a = 10;
int * p;
p = &a;
cout << p << endl;
system("pause");
return 0;
}
指针解地址
#include<iostream>
#include<string>
using namespace std;
int main(void)
{
// 指针定义
int a = 10;
int * p;
p = &a;
cout <<"a: " << a << endl;
cout << "p: " << p << endl;
// 指针解引用取值
int b = *p;
cout << "b: " << b << endl;
// 指针解引用设值
*p = 20;
cout << "a: " << a << endl;
cout << "p: " << p << endl;
cout << "b: " << b << endl;
system("pause");
return 0;
}
指针所占内存空间
32位操作系统下,任何类型的指针均占用 4 个字节。64位操作系统下,占用 8 个字节
空指针
含义:指针变量指向内存中编号为 0 的空间
功能:初始化指针变量
注意:
1、空指针指向的内存是不可以访问的
2、内存地址 0 ~ 255 之间的内存编号是系统占用的,因此不可以访问
定义方式:int * p = NULL;
野指针
含义:指针变量指向非法的内存空间,常见于获取了没有权限访问的内存地址
int main(){
int * p = (int *)0x1100;
cout << *p << endl;
system("pause");
return 0
}
常量指针
形如:const int * p;
指针的指向可以改,但是指针指向的值不可以改。即可以将 p = &a 在后续变为 p = &b,但是不可以 *p = 20
指针常量
形如:int * const p = &a;
指针的指向不可以改,指针指向的值可以改
const既修饰指针,又修饰常量
形如:const int * const p = &a;
指针的指向和指针指向的值都不可以改
指针访问数组
注意事项:
1、指针的 ++ 是将指针向后移动指针的数据类型个字节
2、数组的名称即代表数组的首字节地址
#include<iostream>
#include<string>
using namespace std;
int main(void)
{
int numbers[5] = { 1, 2, 3, 4, 5 };
// 获取数组开始的地址
int * p = numbers;
for (int i = 0; i < sizeof(numbers) / sizeof(numbers[0]); i++) {
cout << (int)p << endl;
*p = i * 10;
// 该指针为 int 类型,每次 p++ 都会将指针向后移 4 个字节
p++;
}
for (int i = 0; i < sizeof(numbers) / sizeof(numbers[0]); i++) {
cout << numbers[i] << endl;
}
system("pause");
return 0;
}
指针和函数
作用:将指针作为函数的参数,可以修改实参的值(类似全局变量,从函数内部修改外部变量的值)
如:函数内通过指针修改函数外部变量的值
#include<iostream>
#include<string>
using namespace std;
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
cout << "a: " << a << endl;
cout << "b: " << b << endl;
}
void swap2(int * a, int * b) {
int temp = *a;
*a = *b;
*b = temp;
cout << "a: " << *a << endl;
cout << "b: " << *b << endl;
}
int main(void)
{
int a = 10;
int b = 20;
swap2(&a, &b);
cout << "a out: " << a << endl;
cout << "b out: " << b << endl;
system("pause");
return 0;
}
利用指针进行冒泡排序
常用函数
sizeof
作用:统计数据所占用的内存的大小,以字节为单位
使用:sizeof(int);
typeid
作用:去获取数据类型,typeid().name() 获取数据类型名
使用:typeid().name()
基础写法
生成随机数
rand() —— 生成 0 ~ 1之间的随机数
rand()%100 —— 生成 0 ~ 100 之间的随机数[0, 100)
注意,rand() 生成的随机数是固定的,每次都相同。若想让随机数每次都未必一样,则需要加入随机数种子,方法如下:
1、创建随机数种子
srand((unsigned int)time(NULL));
2、再调用生成随机数int num = rand() % 100;
低版本 cpp 中需要引入头文件
# include <ctime>
求数字位数
仅适用于整数
方法:通过整数除法是地板除法的特点,将整数除以10并统计一次除法,直到数字小于10时,停止循环
int num = 12345;
int count = 1;
while(num/=10){
count ++;
}
整数每位的值
以数字 123 为例
// 个位
123 % 10 --> 3
// 十位
123 / 10 --> 12
12 % 10 --> 2
// 百位
123 / 100 --> 1
例:求水仙花数
inti = 100;
do {
int num_1 = i % 10;
int num_2 = (i / 10) % 10;
int num_3 = i / 100;
int res = (num_1 * num_1 * num_1) + (num_2 * num_2 * num_2) + (num_3 * num_3 * num_3);
if (res == i) {
cout << "水仙花数:" << i << endl;
}
i++;
} while (i<1000);
基本算法及使用技巧
使用技巧
生成随机数
步骤如下:
1、引入 ctime
2、设置随机数种子
3、生成随机数
// 引入 ctime
#include <ctime>
// 设置随机数种子
srand((unsigned int)time(NULL));
// 生成随机数 ([0, 101)范围内)
rand() % 101;
排序算法
冒泡排序
#include<iostream>
#include<string>
using namespace std;
int main(void)
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
// 冒泡排序
for (int loop = (int)(sizeof(arr) / sizeof(arr[0])); loop > 0; loop--) {
for (int subLoop = 0; subLoop < (loop - 1); subLoop++) {
if (arr[subLoop] > arr[subLoop + 1]) {
int temp = arr[subLoop];
arr[subLoop] = arr[subLoop + 1];
arr[subLoop + 1] = temp;
}
}
}
// 输出值
for (int loop = 0; loop < (sizeof(arr) / sizeof(arr[0])); loop++) {
cout << arr[loop] << endl;
}
system("pause");
return 0;
}
选择排序
#include<iostream>
#include<string>
using namespace std;
int main(void)
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
// 选择排序
for (int loop = (int)(sizeof(arr) / sizeof(arr[0])); loop > 0; loop--) {
int max = 0;
int max_ind = 0;
// 取值
for (int ind = 0; ind < loop; ind++) {
// 获取最大值
if (max < arr[ind]) {
max = arr[ind];
// 保留最大值在数组中的索引
max_ind = ind;
}
}
// 临时保存当前范围内的最后一个值
int temp = arr[loop - 1];
// 将最后一个值设置为 max
arr[loop - 1] = max;
// 将最大值原始位置设置为最后一个值
arr[max_ind] = temp;
}
// 输出值
for (int loop = 0; loop < (sizeof(arr) / sizeof(arr[0])); loop++) {
cout << arr[loop] << endl;
}
system("pause");
return 0;
}
控制台
控制台输出控制
暂停
作用:暂停程序运行,并在控制台中显示 "请按任意键继续"等待用户输入
代码:system(“pause”);
清屏
作用:清空控制台内容
代码:system(“cls”);