准备工具Vscode或者Clion或者Dev C++或者Vs studio 和
MSYS2 是C++跨平台的重要工具链.
基础一
- 准备工作
- 安装MSYS2
- 软件
- 创建文件
- 一、基本介绍
- 1.1C++源文件
- 1.2 代码注释
- 1.3变量与常量
- 1.3.1变量
- 1.3.2 常量
- 1.3.3 二者的区别:
- 1.4 关键字和标识符
- 二、数据类型
- 2.1 基本数据类型:
- 2.1.1整型:
- 2.1.2 浮点型 (实数):
- 保留指定位数的小数
- 2.1.3 字符型 (char 1个字节):
- 2.1.3.(1)转义字符
- 2.1.4 布尔型 (bool):
- 2. 2 用户定义数据类型(后续):
- 2.3 字符串型
- 2.4 数据键入
- 三、运算符
- 四、流程控制语句
- 4.1 选择结构
- 4.1.1 if语句
- 4.1.2 三目运算符
- 4.1.3 switch语句
- 注意事项
- 4.1.4 if和switch的区别【CHAT】
- 4.2 循环结构
- 4.2.1 while循环语句
- 4.2.2 do...while循环语句
- 4.2.3 for循环语句
- 九九乘法表
- 4.3 跳转语句
- 4.3.1 break语句
- 4.3.2 continue语句
- 4.3.3 goto语句:- `goto`关键字。
- 五、数组
- 5.1 一维数组
- CLion中有错误:cast from ‘int*’ to ‘int’ loses precision [-fpermissive]问题解决
- 冒泡排序
- C语言内置的qsort
- 5.2 二维数组
- 六、函数
- 值传递
- 如果想要改变实参 -- 互换地址的内容:
准备工作
安装MSYS2
pacman -S mingw-w64-ucrt-x86_64-gcc
后Y
最后用cmd gcc --version
环境变量添加进去:
软件
CLion
创建文件
右击–New–C/C++ Source File
一、基本介绍
1.1C++源文件
该文件一般是以.cpp 或者 .cxx 后缀结尾的。
#include<iostream>
using namespace std;
// main有且仅有一个
int main() {
cout << "Hello C++__world" << endl;
//system("pause");
return 0;
}
main 函数只包含一行代码:这个单条语句是以 std 开头,然后以一个分号(;)作为结尾
的。
1.2 代码注释
注释是一种编写代码时用来解释程序的作用和用途的特殊语句,编译器会自动检测并忽略,注释并不对程序功能产生任何影响。
格式:
(1)单行注释: // 后接对代码的描述
放置在代码上方,或者代码语句结束的结尾较好。
(2)多行注释:/*多行注释*/
这个由于可能代码篇幅可能较长,所以推荐写在整体的上方。
1.3变量与常量
1.3.1变量
给一段指定的内存空间起名,方便操作这段内存
语法:数据类型 变量名 = 初始值;
注意:最好是在定义的时候,给变量赋初值。因为变量是在操作指定的内存空间,在定义变量的时候,会找某一空间,却不可保证改空间原先的值是没有的。
#include<iostream>
using namespace std;
int main() {
//最好是在定义的时候,给变量赋初值。
int a = 5;
//带有中文输出的内容,需要把编码格式改为GBK
cout << "a 的值= " << a << endl;
system("pause");
return 0;
}
1.3.2 常量
不随任何的行为而改变自身数据
语法:
(1)#define 宏定义 #define 常量名 常量值
源文件的上方定义的
(2)const 修饰的变量 const 数据类型 常量名 = 常量值
被const修饰该变量为常量,不可修改
1.3.3 二者的区别:
虽两种方式都可以用来定义常量,但仍存在一些区别:
-
#define 宏常量:
- 使用预处理指令,简单替换,没有类型检查。
- 不占用内存,直接替换为常量值(是简单的文本替换,它将符号替换成相应的文本; 即:#define 定义的常量没有分配存储空间,没有对应的地址)。
- 可以定义函数、表达式等,不仅仅限于常数(define可以采用表达式作为名称)。
- 宏不受作用域限制,全局可用。
-
const修饰的变量:
- 是真正的变量,具有数据类型,会占用内存。(因为const 定义的常量在内存中分配了存储空间,可以获取其地址)
- 提供类型安全,编译器会进行类型检查。
- 有作用域限制,遵循普通变量的作用域规则。
- 更推荐,因为具有类型信息,易于维护和调试。
通常情况下,推荐使用 const 修饰的变量来定义常量,因为它更具类型安全性和可读性。
1.4 关键字和标识符
C++中的关键字是指具有特殊含义的保留单词,例如"int"和"if"
在给变量或者常量起名称时候,不要用C++得关键字,否则会产生歧义。
标识符是程序员定义的用于命名变量、函数等的名称。 给标识符命名时,争取做到见名知意的效果,方便自己和他人的阅读
- 标识符不能是关键字
- 标识符只能由字母、数字、下划线组成
- 第一个字符必须为字母或下划线
- 标识符中字母区分大小写
二、数据类型
C++中的数据类型可以分为
好的,我会继续介绍C++中常见的基本数据类型和用户定义数据类型。
2.1 基本数据类型:
检验类型大小 ` sizeof(数据类型、变量) `
C++是一种静态类型语言,这意味着在创建变量或常量时必须明确指定其数据类型。编译器需要在编译时确定每个变量的数据类型,以便正确分配内存并执行相应的操作。
如果不指定数据类型,编译器将无法正确处理变量的内存分配和操作,因此必须明确定义数据类型。
2.1.1整型:
用于表示整数类型的数据,可以是正数、负数或零。区别在于存储的空间大小不同
short < int <= long <= long long
short:2字节 -2^15 - 2 ^15 -1
int :4字节 -2^31 - 2 ^31 -1
long:在32位系统上通常4字节, 在64位系统上通常8字节, -2^31 - 2 ^31 -1
long long :8字节 -2^15 - 2 ^63 -1
2.1.2 浮点型 (实数):
用于表示带有小数的数值,其中`float`表示单精度浮点数,而`double`表示双精度浮点数。
-
float:
float
是一种单精度浮点数数据类型,通常占用4字节(32位),可以存储大约7位有效数字。- 使用
f
后缀来明确指定一个浮点数为float
类型,如3.14f
。
-
double:
double
是一种双精度浮点数数据类型,通常占用8字节(64位),可以存储大约15-16位有效数字。
-
科学计数法:
- C++支持科学计数法来表示浮点数,使用形如
aeb
的表示法,其中a
是系数,e
是底数为10的指数,b
是指数的符号。例如,3e2
表示 (3 *10^2),即300;0.03
可以写作3e-2
表示 (3 *10^(-2))。
- C++支持科学计数法来表示浮点数,使用形如
示例:
float pi = 3.14f; // 使用 f 后缀指定 float 类型
double largeNumber = 1.234567890123456789; // 默认为 double 类型
float a = 3e2; // 表示 300
float b = 3e-2; // 表示 0.03
保留指定位数的小数
使用iomanip库中的setprecision函数
fixed和setprecision函数来设置输出的小数精度。fixed用于固定小数点的位置,setprecision用于设置小数的位数。
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double num = 3.1415926;
int precision = 3; // 保留3位小数
cout << fixed << setprecision(precision) << num << endl;
return 0;
}
字符串流(stringstream)
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;
int main() {
double num = 3.1415926;
int precision = 3; // 保留3位小数
stringstream ss;
ss << fixed << setprecision(precision) << num;
string result = ss.str();
cout << result << endl;
return 0;
}
我们使用字符串流(stringstream)来将浮点数转换为字符串,并设置小数的位数。然后,我们可以将结果存储在一个字符串变量中,以便后续使用。
2.1.3 字符型 (char 1个字节):
作用: 用于表示单个字符,以ASCII编码1为基础。
语法: char ch = 'a';
注意:
( 1 )用单引号括起字符,示例:char myChar = 'A';
( 2 )单引号内只能包含一个字符,不能是字符串,示例:char myChar = 'AB';
是不允许的,应该是 char myChar = 'A';
( 3 )字符型变量(char)在C和C++中通常占用1个字节(8位),无论是用于存储字符本身还是对应的ASCII码。
2.1.3.(1)转义字符
用于表示一些不能显示出来的ASCII字符
转义字符是在字符前面加上反斜杠(\)来表示一些特殊字符或操作,通常用于在字符串或字符常量中插入不易直接输入的字符。
常用的转义字符有: \n \\ \t
2.1.4 布尔型 (bool):
布尔类型(bool)是一种用于表示真(true)或假(false)的数据类型,在C++中占用1个字节大小。它是用来做逻辑判断的基本类型。
bool flag = true;
cout << flag << endl; // 1
flag = false;
cout << flag << endl; // 0
cout << "size of bool = " << sizeof(bool) << endl; //1
2. 2 用户定义数据类型(后续):
- 结构体 (struct): 允许创建包含多个不同数据类型的组合体,可以通过结构体定义多个变量来描述一个实体的属性。
- 类 (class): 允许创建具有成员变量和成员函数的自定义数据类型,实现了面向对象编程的概念,包括封装、继承和多态。
- 枚举类型 (enum): 允许创建一个包含一组命名常量的新数据类型。
- 共用体 (union):共用体允许在同一内存位置存储不同的数据类型。这意味着共用体的成员共享内存,修改一个成员会影响到其他成员。
- typedef 定义的类型:typedef 是用来为现有类型定义新的名称,提高代码的可读性和可维护性。
2.3 字符串型
在C++中,字符串类型可以属于两种类型:普通类型和用户定义类型,具体取决于使用的字符串表示方式。
-
普通类型(延续C语言风格):
- 在C++中,可以使用字符数组(char array)或指向字符的指针来表示字符串。这种方式属于普通类型,没有特定的用户定义类型,它们是C和C++的基本字符串表示方式。
char str1[] = "Hello, world!"; // 字符数组表示字符串 char* str2 = "Hello, world!"; // 字针表示字符串
-
用户定义类型:
- 另一方面,C++也提供了标准库中的
std::string
类,这是一个用户定义的字符串类型。std::string
是一个类,提供了丰富的字符串操作功能和方便的字符串管理。
#include <string> std::string str = "Hello, world!"; // 使用 std::string 类型
- 另一方面,C++也提供了标准库中的
std::string
是C++标准库中的一部分,它提供了很多方便的字符串处理方法,例如字符串拼接、查找、替换等操作,使得字符串处理更方便和高效。
因此,字符串可以是普通类型(字符数组或指针)或用户定义类型(std::string
),具体取决于你选择的字符串表示方式。如果需要更多信息或有其他问题,请随时提出。
2.4 数据键入
作用:用于从键盘获取数据
关键字: cin
语法: cin >> 变量
cin
通常与运算符>>
一起使用,用于将输入的数据存储到指定的变量中。这样可以方便地从用户那里接收输入,并在程序中进行处理
int x = 0;
cout << "请输入整型变量x的值:" << endl;
cin >> x;
cout << x << endl;
三、运算符
注意(1) 两个小数不可做取模运算,结果看左边
int a3 = 10;
int b3 = 0;
//报错,除数不可以为0
//cout << a3 / b3 << endl;
// 两个小数不可做取模运算,结果看左边
// 除数不为0
cout << -10 % 3 << endl; //-1
cout << 10 % 3 << endl; // 1
//两个小数可以相除
double d1 = 0.5;
double d2 = 0.25;
cout << d1 / d2 << endl;
(2)赋值是‘=’ 等于是‘==’
算术运算符
赋值运算符
比较运算符
逻辑运算符
基础二
- 准备工作
- 安装MSYS2
- 软件
- 创建文件
- 一、基本介绍
- 1.1C++源文件
- 1.2 代码注释
- 1.3变量与常量
- 1.3.1变量
- 1.3.2 常量
- 1.3.3 二者的区别:
- 1.4 关键字和标识符
- 二、数据类型
- 2.1 基本数据类型:
- 2.1.1整型:
- 2.1.2 浮点型 (实数):
- 保留指定位数的小数
- 2.1.3 字符型 (char 1个字节):
- 2.1.3.(1)转义字符
- 2.1.4 布尔型 (bool):
- 2. 2 用户定义数据类型(后续):
- 2.3 字符串型
- 2.4 数据键入
- 三、运算符
- 四、流程控制语句
- 4.1 选择结构
- 4.1.1 if语句
- 4.1.2 三目运算符
- 4.1.3 switch语句
- 注意事项
- 4.1.4 if和switch的区别【CHAT】
- 4.2 循环结构
- 4.2.1 while循环语句
- 4.2.2 do...while循环语句
- 4.2.3 for循环语句
- 九九乘法表
- 4.3 跳转语句
- 4.3.1 break语句
- 4.3.2 continue语句
- 4.3.3 goto语句:- `goto`关键字。
- 五、数组
- 5.1 一维数组
- CLion中有错误:cast from ‘int*’ to ‘int’ loses precision [-fpermissive]问题解决
- 冒泡排序
- C语言内置的qsort
- 5.2 二维数组
- 六、函数
- 值传递
- 如果想要改变实参 -- 互换地址的内容:
四、流程控制语句
顺序结构、选择结构、循环结构
4.1 选择结构
4.1.1 if语句
用于执行基于条件的代码块。
if语句的三种形式
单行格式if语句
多行格式if语句
多条件的if语句
(1).单行格式if语句:if(条件){ 条件满足执行的语句 }
if条件表达式后不要加分号
if (sum==100)
{
cout<<"sum=="<<100<<endl;
}
( 2 ) .多行格式if语句:
`if(条件){ 条件满足执行的语句 }
else{ 条件不满足执行的语句 };`
( 3 ).多行格式if语句:
`if(条件){ 条件满足执行的语句 }
else{ 条件不满足执行的语句 };`
4.1.2 三目运算符
语法:表达式1 ? 表达式2 :表达式3
int a = 10;
int b = 20;
int c = a > b ? a : b;
cout << "c = " << c << endl;
4.1.3 switch语句
switch - case
每个case标签之后不会自动执行到下一个case标签,除非使用break语句来显式终止switch块。
switch(表达式)
{
case 结果1:执行语句;break;
case 结果2:执行语句;break;
...
default:执行语句;break;
}
举例代码:
#include <iostream>
int main() {
int choice = 2;
switch (choice) {
case 1:
std::cout << "选项1" << std::endl;
case 2:
std::cout << "选项2" << std::endl;
case 3:
std::cout << "选项3" << std::endl;
default:
std::cout << "默认选项" << std::endl;
}
return 0;
}
这是因为没有break语句来终止case标签,导致控制流“直通”到后续的case标签。如果您想要避免这种行为,应在每个case块的末尾使用break语句来显式退出switch块。
注意事项
-
switch
语句中的表达式类型通常只能是整型或字符型。这是因为case
标签中的常量值需要与表达式的类型匹配。 -
如果在
case
标签中没有使用break
语句,程序会继续执行下一个case
标签,这就是所谓的“直通”行为。 -
switch
语句在处理多个条件判断时具有结构清晰和执行效率高的优点。它适用于在一系列离散值中选择执行不同的代码块。 -
一个
switch
语句的缺点是它不能直接判断区间,只能针对离散的值进行判断。要处理区间,通常需要使用一系列if
语句或其他逻辑结构。
这些特点使switch
成为一种适用于某些情况下的有效控制结构,但在其他情况下可能需要使用不同的条件控制方式。
4.1.4 if和switch的区别【CHAT】
`if`更灵活,适用于各种条件逻辑,
`switch`更适用于多个等值条件的情况下,代码更具可读性。
-
用法:
if
语句适用于任何条件判断,可以处理各种复杂的条件表达式,包括比较、逻辑运算等。它可以用来实现灵活的条件控制。switch
语句通常用于根据一个表达式的不同值来选择执行不同的代码块。它适用于多个等值条件的情况。
-
条件:
if
语句可以处理各种条件,包括布尔表达式、比较表达式、逻辑表达式等,可以实现更灵活的条件逻辑。switch
语句通常用于处理整数或字符类型的表达式,用于离散的值判断,而不适用于范围或其他类型的条件。
-
多条件:
if
语句可以轻松处理多个条件,通过嵌套if
语句或使用else if
来实现多个条件分支。switch
语句通过多个case
标签来处理多个等值条件,通常更适用于处理相对简单的多条件情况。
-
可读性:
switch
语句通常在处理多个等值条件时更具可读性,因为所有条件都集中在一起。if
语句用于处理复杂的条件逻辑时可能需要更多的嵌套,可读性可能较差。
-
执行流程:
if
语句是根据条件的真假来决定是否执行某个代码块。switch
语句是基于表达式的值来选择执行哪个case
块,然后执行该块内的代码,之后需要使用break
语句来终止switch
块,否则会"直通"到下一个case
。
综上所述,选择使用if
还是switch
取决于您的需求。
4.2 循环结构
4.2.1 while循环语句
语法: while(循环条件){ 循环语句 }
int num = 0;
while (num < 10)
{
cout << "num = " << num << endl;
num++;
}
执行循环语句时确实必须提供跳出循环的出口,否则可能会陷入死循环,导致程序永远不会停止执行。以下是一些常见的方法来实现循环的退出
4.2.2 do…while循环语句
语法: do{ 循环语句 } while(循环条件);
与while的区别在于do…while会先执行一次循环语句,再判断循环条件
4.2.3 for循环语句
语法: for(起始表达式;条件表达式;末尾循环体) { 循环语句; }
for循环中的表达式,要用分号进行分隔
九九乘法表
4.3 跳转语句
4.3.1 break语句
-
在
switch
语句中:break
语句用于终止当前的case
标签块,并跳出switch
语句。这可以防止"直通"到下一个case
标签。 -
在循环语句中(如
for
、while
、do-while
):break
语句用于提前跳出当前循环,即使循环条件仍然满足。它用于终止循环的执行,使程序流程进入循环后的下一个语句。 -
在嵌套循环中:如果存在多个嵌套循环,
break
语句通常跳出最近的内层循环,而不是整个外层循环。这允许您有选择性地退出嵌套循环中的一个循环,而不必退出所有嵌套层次。
break
语句是控制流的重要工具,用于在满足特定条件时改变程序的执行路径。要注意,滥用break
可能会导致代码难以理解和维护,因此应该慎重使用。
4.3.2 continue语句
continue并没有使整个循环终止,而break会跳出循环
4.3.3 goto语句:- goto
关键字。
语法: goto 标记;
`goto`语句是一种在编程中用来无条件跳转到程序中的标记(label)处的控制语句。
goto 标记;
标记
是在程序中的一个标签,通常是一个带有冒号的标识符,例如label:
。
使用goto
语句可以使程序跳转到指定标记的位置,继续执行代码。这可以在某些情况下用于实现特定的控制流程,但要小心使用,因为滥用goto
可能导致程序难以理解和维护,产生不可预测的行为。
大多数现代编程语言鼓励避免使用goto
,并提供更结构化的控制结构,如条件语句和循环,以更清晰和可维护的方式实现控制流程。在实际编程中,通常不需要使用goto
,并且可以通过其他方法来实现相同的目标。
五、数组
(1)数据类型相同: 数组中的每个数据元素都必须是相同的数据类型。这意味着如果您创建一个整数数组,每个元素都必须是整数;如果是字符数组,每个元素都必须是字符,以此类推。
(2)连续内存: 数组的元素在内存中是连续存储的,这意味着数组中的元素在内存中相邻,没有额外的空间分隔它们。这也是数组的一个重要特点,因为它允许通过索引来快速访问元素,索引值可用于计算元素的内存地址。
5.1 一维数组
一维数组定义的三种方式:
数据类型 数组名[ 数组长度 ];
数据类型 数组名[ 数组长度 ] = { 值1,值2 ...};
数据类型 数组名[ ] = { 值1,值2 ...};
(1). 可以统计整个数组在内存中的长度sizeof(arr) / sizeof(arr[0])
(2)可以获取数组在内存中的首地址(int)arr
CLion中有错误:cast from ‘int*’ to ‘int’ loses precision [-fpermissive]问题解决
该这里是因为基于Linux内核的64位系统上指针类型占用8个字节,而int类型占用4个字节,所以会出现loses precision。
可以先将int* 转成long类型,long类型可以隐式类型转换到int类型。直接修改为long long即可
cout << "数组首地址为:" << (long long)arr << endl;
cout << "数组第一个元素地址为:" << (long long)&arr[0] << endl;
cout << "数组第二个地址为:" << (long long)&arr[1] << endl;
冒泡排序
int main() {
int arr[9] = { 1,7,5,3,4,8,6,2,3};
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;
}
}
}
for (int i = 0; i < 9; i++)
{
cout << arr[i] << endl;
}
system("pause");
return 0;
}
C语言内置的qsort
#include <stdio.h>
#include <stdlib.h>
// 比较函数,用于告诉qsort如何比较元素
int compare(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
int main() {
int arr[] = {5, 2, 9, 1, 5, 6};
int length = sizeof(arr) / sizeof(arr[0]);
// 使用qsort对整数数组进行升序排序
qsort(arr, length, sizeof(int), compare);
// 打印排序后的数组
printf("排序后的数组:");
for (int i = 0; i < length; ++i) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
5.2 二维数组
二维数组定义的四种方式:
数据类型 数组名[ 行数 ][ 列数 ];
数据类型 数组名[ 行数 ][ 列数 ] = { {数据1,数据2 } ,{数据3,数据4 } };
数据类型 数组名[ 行数 ][ 列数 ] = { 数据1,数据2,数据3,数据4};
数据类型 数组名[ ][ 列数 ] = { 数据1,数据2,数据3,数据4};
六、函数
将一段经常使用的代码封装起来,减少重复代码
返回值类型 函数名 (参数列表)
{
函数体语句
return表达式
}
int add(int num1, int num2)
{
//函数体语句
int sum = num1 + num2;
//return表达式
return sum;
}
调用 函数名(参数)
int add(int num1, int num2) //定义中的num1,num2称为形式参数,简称形参(形参列表)
{
int sum = num1 + num2;
return sum;
}
int add(int num1, int num2, int num3) {
int sum = num1 + num2 + num3;
return sum;
}
int main() {
int a = 10;
int b = 10;
//调用add函数
int sum = add(a, b);//调用时的a,b称为实际参数,简称实参
cout << "sum = " << sum << endl;
int sum1 = add(a, b, 10);
cout << "sum1 = " << sum1 << endl;
a = 100;
b = 100;
sum = add(a, b);
cout << "sum = " << sum << endl;
system("pause");
return 0;
}
值传递
值传递时,形参是修饰不了实参的
形参无论发生什么变化都不会影响实参
void swap(int num1, int num2)
{
cout << "交换前:" << endl;
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
int temp = num1;
num1 = num2;
num2 = temp;
cout << "交换后:" << endl;
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
//return ; 当函数声明时候,不需要返回值,可以不写return
}
int main() {
int a = 10;
int b = 20;
swap(a, b);
cout << "mian中的 a = " << a << endl;
cout << "mian中的 b = " << b << endl;
system("pause");
return 0;
}
如果想要改变实参 – 互换地址的内容:
void swap(int num1, int num2)
{
cout << "交换前:" << endl;
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
cout << "&num1="<< &num1<<endl;
cout << "&num2="<< &num1<<endl;
int temp = num1;
num1 = num2;
num2 = temp;
cout << "&temp="<<&temp<<endl;
cout << "交换后:" << endl;
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
cout << "&num1="<< &num1<<endl;
cout << "&num2="<< &num1<<endl;
//return ; 当函数声明时候,不需要返回值,可以不写return
}
int main() {
int a = 10;
int b = 20;
swap(a, b);
cout << "mian中的 a = " << a << endl;
cout << "mian中的 b = " << b << endl;
cout << "&a="<< &a<<endl;
cout << "&b="<< &b<<endl;
system("pause");
return 0;
}
ASCII(American Standard Code for Information Interchange)编码将每个字符映射到一个唯一的整数。例如,字母 ‘a’ 对应的ASCII码是97。因此,当你在C或C++中创建一个字符型变量时,实际上是将该字符对应的ASCII码存储在内存中。 ↩︎