文章目录:
一:软件安装环境
第一种:vc2012
第二种:Dev-C++
第三种:小熊猫C++
二:语法基础
1.相关
1.1 注释
1.2 换行符
1.3 规范
1.4 关键字
1.5 ASCll码表
1.6 转义字符
2.基本框架
2.1 第一种(万能头文件)
2.2 第二种(自己写头文件)
3.数据类型
3.1 分类
3.2 基本数据类型(整型 浮点型 字符型 字符串型 布尔型)
3.3 非基本数据类型
3.3.1 数组array
3.3.1.1 一维数组
3.3.1.2 二维数组
3.3.1.3 字符数组char
3.3.2 指针*
3.3.2.1 指针定义
3.3.2.2 指针数组
3.3.3 结构体struct
3.3.3.1 结构体定义
3.3.3.2 结构体数组
3.3.3.3 结构体函数
3.3.3.4 结构体指针
4.输入输出
4.1 语句 输入cin输出cout
4.2 格式化 输入scanf输出printf函数
4.2.1 scanf格式字符串
4.2.2 printf格式化输出
4.3 单个字符 输入getchar输出putchar函数
4.4 标准输入fgets输出puts函数
5.常量和变量
5.1 命名规则
5.2 变量
5.3 常量
5.3.1 #define 宏常量
5.3.2 const 修饰的变量
6.运算符
6.1 算术运算符
6.2 赋值运算符
6.3 比较运算符/关系运算符
6.4 逻辑运算符
6.5 位运算符
6.6 运算符优先级
7.程序流程结构
7.1 选择结构
7.1.1 if语句
7.1.2 三目/元运算符
7.1.3 switch语句
7.2 循环结构
7.2.1 while循环语句
7.2.2 do...while循环语句
7.2.3 for循环语句
7.2.4 嵌套语句
7.3 跳转语句
7.3.1 break语句
7.3.2 continue语句
7.3.3 goto语句
8.函数
8.1 函数的定义
8.2 函数的声明
8.3 函数的调用
8.4 形参和实参
8.5 函数的常见形式
8.6 分文件编写
8.7 Lambda函数
8.8 函数递归
8.9 内置函数
三:语法进阶
1.文件
1.1 文本文件第一种 方法
1.1.1 写ofstream
1.1.2 读ifstream
1.1.3 判断打开文件is_open
1.2 文本文件第二种方法
1.2.1 写ofstream
1.2.2 读ifstream
1.3 二进制文件
1.3.1 写ofstream write
1.3.2 读ifstream read
一:软件安装环境
第一种:vc2012
官网:Visual Studio: 面向软件开发人员和 Teams 的 IDE 和代码编辑器
第二种:Dev-C++
提取码:1f9a
文件——>新建——>源文件 菜单栏、工具栏、代码编辑区、编译结果展示 修改语言:工具——>环境选项——>基本——>语言——>简体中文
第三种:小熊猫C++
提取码:kq1m
文件——>新建——>新建c/c++文件
二:语法基础
1.相关
1.1 注释
单行注释:// 多行注释:/**/ 快捷键:ctrl + /
1.2 换行符
endl:换行符
1.3 规范
加上分号";"的 声明 int x; using namespace std; 执行函数或方法 cout << "Hello, World!"; 表达式 x = 5; 类 class MyClass { }; 结构体 struct MyStruct { }; 不加上分号";"的 在定义函数或方法时,参数列表后不需要分号 void myFunction() { } 控制语句 if (x > 0) { }
1.4 关键字
什么是标识符? 关键字是C++中预先保留的单词(标识符) 注意事项 在给变量/常量命名的时候,不要用C++的关键字,否则会产生歧义 int int = 10;
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 protexted this wchr_t continue for public throw while dedfault friend register true delete goto reinterpret_cast try
1.5 ASCll码表
ASCll码大致可以由以下两部分组成: ASCll非空打印控制字符:ASCll表上的数字0-31分配给了控制字符,用于控制像打印机等一些外围设备 ASCll打印字符:数字32-126分配给了能在键盘上找到的字符,当查看或打印文档时就会出现 A~B:65~90 a~b:97~122 0~9:48~57 '':32 标准的ASCll:0~127 26个英文字母,大写和小写之间相差32
#include <bits/stdc++.h> //万能头文件:包含了目前c++所包含的所有头文件 using namespace std; //标准命名空间 int main(){ //程序入口 char a; cout<<"请输入:"; cin>>a; 大写——>小写 a=a-'A'+'a'; //第一种 a=a-65+'a'; //第二种 a=a-65+97; //第三种 a=a+32; //第四种 cout<<a; //小写——>大写 a=a-'a'+'A'; //第一种 a=a-97+'A'; //第二种 a=a-97+65; //第三种 a=a-32; //第四种 cout<<a; int a='a'; //97 //char a='a'; //a cout<<a; //字母变ASCII码 char num1 = 'A'; //int num_1 = static_cast<int>(num1); int num_1 = (int)(num1); cout <<num_1 <<endl; //66 char c="A"; cout<<c+1<<endl; //66 //字母递增 char c="A"; c=c+1; cout<<c+1<<endl; //B char c="A"; cout<<char(c+1)<<endl; //B //ASCII码变字母 int num2 = 65; //char num2_2 = static_cast<char>(num2); char num2_2 = (char)(num2); cout <<num2_2<<endl; //A return 0; //程序正常结束 }
1.6 转义字符
作用:用于表示一些不能显示出来的ASCll字符
转义字符 意义 ASCll码值(十进制) \a 响铃(BEL) 007 \b 退格(BS),后退一格 008 \f 换页(FF),将当前位置移到下页开头 012 \n 换行(LF),将当前位置移到下一行开头 010 \r 回车(CR),将当前位置移到本行开头 013 \t 水平制表(HT),跳到下一个TAB位置 009 \v 垂直制表(VT) 011 \\ 代表一个反斜线字符 “\” 092 \' 代表一个单引号(撇号)字符 039 \'' 代表一个双引号字符 034 \? 代表一个问号 063 \0 空字符(NULL) 000 \ooo 1到3未八进制数所代表的任意字符 三位八进制 \xhh 1到2未十六进制数所代表的任意字符 二位十六进制
2.基本框架
2.1 第一种(万能头文件)
#include <bits/stdc++.h> //万能头文件:包含了目前c++所包含的所有头文件 using namespace std; //标准命名空间 int main(){ //程序入口主函数 return 0; //程序正常结束 }
解释
#:表示声明语言开始 #include <bits/stdc++.h>:包含了C++标准库中的所有头文件 bit/: 这是一个非标准的目录,用于存放这个特殊的头文件。 stdc++.h: 这是文件的名称,它暗示了这个头文件包含了C++标准库的大部分(或全部)内容 using namespace std;:想使用std命名空间中的所有名称,这样我们就可以直接使用如cout、cin、vector等名称,而无需每次都加上std::前缀 声明,它告诉编译器你想使用std命名空间中的所有名称而不需要在每次引用它们时都加上std::前缀 std(standard)是C++标准库的命名空间。C++标准库中的大部分函数、对象和类型(如cout, cin, vector, map等)都位于这个命名空间中 如果你没有使用using namespace std;,那么你需要这样写代码: std::cout << "Hello, World!" << std::endl; cout << "Hello, World!" << endl; std::vector<int> numbers; vector<int> numbers; int main(){ ... }:每个C++程序都必须有一个main函数,当程序开始执行时,它从这里开始 return 0;:表示main函数的结束,并返回一个值0。main函数返回0通常表示程序成功执行,而非零值表示出现了某种错误
2.2 第二种(自己写头文件)
#include <iostream> //包含头文件iostream using namespace std; //使用c++的命名空间std int main(){ //在程序执行结束后暂停控制台窗口,以便用户能够看到程序的输出,而不是立即关闭窗口 system("pause"); return 0; }
3.数据类型
3.1 分类
分类
基本数据类型包括: 整型(short int long long long) 布尔值类型(bool) 浮点数类型(float double long double) 字符类型(char) 字符串类型(string) void类型 非基本数据类型包括: 数组类型(type[]) 指针类型(type*) 数据结构(struct) 引用类型(double&) 类(class) 枚举类型(enum)
sizeof
为什么要指明数据类型呢:c++规定在创建一个变量或者常量时,必须要指明相应的数据类型,否则无法给变量分配内存 sizeof关键字 作用:利用sizeof关键字可以统计数据类型所占内存大小 语法:sizeof (数据类型/变量) char a = 10; short b = 10; int c = 10; long d = 10; long long e = 10; cout <<"a:" <<sizeof(a)<<endl; cout <<"a:" <<sizeof(char)<<endl; cout <<"b:" <<b <<endl; cout <<"c:" <<c <<endl; cout <<"d:" <<d <<endl; cout <<"e:" <<sizeof(e) <<endl; cout <<"e:" <<sizeof(long long) <<endl;
3.2 基本数据类型(整型 浮点型 字符型 字符串型 布尔型)
数据类型 占用空间 取值范围 其他 整型 short 短整型 2字节 -2^15 ~ 2^15-1 int 整型 4字节 -2^31 ~ 2^31-1 %d long 长整型 windows为4字节
linux为4字节(32位)、8字节(64位)
-2^31 ~ 2^31-1 long long 长长整型 8字节 -2^63 ~ 2^63-1 %lld 浮点型 float 单精度 4字节 7位有效数字
-3.4 x 10^38 ~ 3.4 x 10^38
%f double 双精度 8字节 15~16位有效数字 %lf
默认long double 16字节 -3.4 x 10^4932 ~
3.4 x 10^4932
%Lf 字符型 char 1字节 0~255 %c 字符串型 string 布尔型 bool 1字节 true
false
1==2
//---------------------------------------------------------------------------//整型 short b = 10; int c = 10; long d = 10; long long e = 10; cout <<"b:" <<b <<endl; cout <<"c:" <<c <<endl; cout <<"d:" <<d <<endl; cout <<"e:" <<e <<endl; //---------------------------------------------------------------------------//浮点型 float b=0.00001; float b=1.0E-5; float b=1.0e-5; double a=8000000000; double a=8E+9; double a=8E9; double a=8e9; double a=8e+9; //---------------------------------------------------------------------------//字符型 char ch = 'a'; 作用:字符型变量用于显示单个字符 本质:并不是把字符本身放在内存中存储,而是将对应的ASCll编码收入到存储单元中 注意事项 在显示字符型变量时:用单引号将字符括起来,不要用双引号 单引号之内只能有一个字符:不可以是字符串 //---------------------------------------------------------------------------//字符串类型 c++风格字符串 string 变量名 = "字符串值"; // #include <string> C语言风格字符串 char 变量名[] = "字符串值"; 作用:用于表示一串字符 ------------------------------------------------------ C++标准库中的std::string类型 ------------------------------------------------------ #include <string> string s; cout << "请输入一行文本: "; getline(cin, s); cout << "你输入的是: " << s << std::endl; string s1; cin>>s1; int n=s1.size() //得到字符串的长度 int n = s1.length(); //获取字符串长度 for(int i=0;i<s1.size();i++){ //字符串的遍历 cout << s1[i]; } char firstChar = s1[0]; //访问字符串中的字符 //在s1中查找s2出现的位置,如果查不到返回无符号整数的最大值(转换成int以后等于-1) s1.find(s2) s1.replace(0, 1, "H"); //替换第一个字符 s1[0] = 'h'; //修改字符串中的字符 s1.insert(pos,s2); //在pos的前面插入s2 s1.append(" again!"); //在字符串末尾添加文本 s1.substr(pos,n); //返回从pos开始的长度为n的一段 s1.erase(pos,n) ; //删除从pos开始的长度为n的一段 s=s1+s2; //将s2拼接到s1,然后赋值给s reverse(s,begin(),s.end()); //翻转整个字符串 int k=stol(s); //将字符串转换为数字 string s=to_string(k); //将数字转换成字符串 ------------------字符串函数 swap(a,b):交换a,b字符串 s.insert(id,str) :s字符串的第id个下标后面插入str字符串 size(),length() 找字符串长度 erase() : 删除字符 clear() : 删除全部字符 replace() : 替换字符 empty() : 判断字符串是否为空 begin() end() : sort(s.begin(),s.end()) find : 查找(a.find(b))如果可以找到返回下标,否则返回-1 rfind : 从后查找 c_str: strcpy(a,s.c_str()) 把字符串复制到字符数组 ------------------------------------------------------ C语言风格字符串(C风格字符串) ------------------------------------------------------ // C风格字符串示例 char s1[] = "Hello, World!"; // 注意:上面的声明创建了一个字符数组,其中包含13个字符(包括结尾的'\0') // 访问字符串中的字符 char firstChar = s1[0]; // 'H' char lastChar = s1[12]; // '!' // 修改字符串中的字符 s1[0] = 'h'; // 现在字符串以'h'开头 //---------------------------------------------------------------------------//布尔型 bool d = true; 作用:布尔数据类型代表真或假的值 返回值 true:...真(本质是1) false:...假(本质是0) //---------------------------------------------------------------------------//
3.3 非基本数据类型
3.3.1 数组array
什么是数组:数组就是一个集合,里面存放了相同类型的数据元素
特点
数组中的每个数据元素都是相同的数据类型
数组是由连续的内存位置组成的
数组中下标是从0开始索引的
3.3.1.1 一维数组
定义方式:如果在初始化时候,没有全部填写完,会用0来填补剩下的数据 数据类型 数组名[数组长度]; int a[100]; const int N=100; int a[N]; 数组名[index]=值; int a[0]=1; int a[1]=4; int a[2]=2; 数据类型 数组名[数组长度]={值1,值2...}; int a[100]={1,4,2}; 数据类型 数组名[]={值1,值2...}; int a[]={1,4,2}; 数组名的用途 可以通过数组名统计整个数组占用的内存大小 int arr[10]={1,2,3,4,5,6,7,8,9,10}; cout<<"整个数组占用内存空间为:"<<sizeof(arr)<<endl; cout<<"每个元素占用内存空间为:"<<sizeof(arr[o])<<endl; cout<<"数组中元素个数为:"<<sizeof(arr)/sizeof(arr[o]<<endl; 可以通过数组名查看数组首地址 cout<<"数组首地址为:"<<arr<<endl; cout<<"数组第一个元素地址为:"<<&arr[0]<<endl; cout<<"数组第二个元素地址为:"<<&arr[1]<<endl; 注意 数组名是常量,不可以进行赋值操作 数组名代表的是数组首元素的地址,是一个地址常量,不可改变 通过数组名可以修改数组中的元素,但是数组名本身不可改变,即数组名指向的地址不可改变 输入n个元素的数组 for(int i;i<=n;i++){ cin>>a[i]; } 数组的遍历(输出) int arr[5] = {300,350,200,400,250}; for (int i = 0; i < 5; i++) { cout << arr[i] << endl; } int arr[5] = {300,350,200,400,250}; for (int i = 1; i <= 5; i++) { cout << arr[i-1] << endl; } int arr[5] = {300,350,200,400,250}; for (int i = 4; i >=0; i--) { cout << arr[i] << endl; }
举例
数组元素逆置
#include <bits/stdc++.h> using namespace std; int main(){ int arr[5] = {1,2,3,4,5}; 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--; } //打印输出逆置后的结果 cout << "原数数组逆置后的结果:" << endl; for (int i = 0; i < 5; i++) { cout << arr[i] << endl; } return 0; }
冒泡排序
//比较相邻的元素:如果第一个比第二个大,就交换他们两个 //对每一对相邻元素做同样的工作:执行完毕后,找到第一个最大值 //重复以上操作:每次比较次数-1,直到不需要比较 #include <bits/stdc++.h> using namespace std; //冒泡排序 int main(){ int arr[9] = {4,2,8,0,5,7,1,3,9}; cout << "排序前的结果:"; for (int i = 0; i < 9; i++) { cout << arr[i] << " "; } cout << endl; //排序总轮数 = 元素个数 - 1 //每轮比较次数 = 元素个数 - 排序轮数 - 1 for (int i = 0; i < 9 - 1; i++) { for (int j = 0; j < 9 - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; //swap(arr[j],arr[j + 1]); } } } cout << "排序后的结果:"; for (int i = 0; i < 9; i++) { cout << arr[i] << " "; } cout << endl; return 0; }
3.3.1.2 二维数组
二维数组的定义方式 数据类型 数组名[行数][列数]; 数组名[index][index]=值; 数据类型 数组名[行数][列数]={{数据1,数据2},{数据3,数据4}}; 数据类型 数组名[行数][列数]={数据1,数据2,数据3,数据4}; 数据类型 数组名[][列数]={数据1,数据2,数据3,数据4}; 二维数组的数组名称 cout<<"整个二维数组大小:"<<sizeof(arr)<<endl; cout<<"二维数组每一行的大小:"<<sizeof(arr[0])<<endl; cout<<"二维数组每个元素的大小:"<<sizeof(arr[0][0])<<endl; cout<<"二维数组的行数:"<<sizeof(arr)/sizeof(arr[0])<<endl; cout<<"二维数组的列数:"<<sizeof(arr[0])/sizeof(arr[0][0])<<endl; cout<<"二维数组首地址为:"<<arr<<endl; cout<<"二维数组第一行地址为:"<<arr[0]<<endl; cout<<"二维数组第一个元素为:"<<&arr[0][0]<<endl; 二维字符数组 char strs[2][5] = {"abcd", "1234"}; for (int i = 0; i < 2; ++i) { cout << strs[i] << endl; } 输入一个n行m列,以(1,1)开始的变量名为a的二维数组 for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>a[i][j]; } } 输出一个n行m列,以(1,1)开始的变量名为a的二维数组 for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cout<<a[i][j]<<""; } cout<<endl; //每输出完一行,就换行 }
3.3.1.3 字符数组char
字符常量 'a' 1 'a' 字符串窗帘 "a" 2 'a' '\0' 声明和初始化字符数组:以空字符('\0')结尾 char str1[] = "Hello"; //大小是6,包括5个字符和一个空字符 char str2[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; 字符数组输入:cin.get(s,30)、cin.getline(s,30)、getchar cin.get()成员函数用于从输入流中读取一个字符 char s[30]; cin.get(s, 30); cout<<s; cin.getline()成员函数用于从输入流中读取一行,直到遇到换行符 char s[30]; cin.getline(s, 30); cout<<s; char s[256]={0}; int len=0; cin.getline(s,256); len=strlen(s); for(int i=0;i<len;i++){ cout<<s[i]; } getchar()是一个C标准库函数,也可以用于从标准输入读取一个字符 它不属于cin对象,而是属于C标准I/O库 char s[30]; int i = 0; while ((s[i] = getchar()) != '\n' && i < 29) { ++i; } s[i] = '\0'; 输入打印字符数组 cout << "请输入一个字符串: "; cin.getline(str, sizeof(str)); cout << "你输入的字符串是: " << str << endl; 访问字符数组中的元素 char letter = str1[0]; // letter 现在是 'H' 修改字符数组中的元素 str1[0] = 'h'; // 将 'Hello' 改为 'hello' 长度 #include <cstring> // 包含 strlen 函数的头文件 //size_t 是一个无符号整数类型,通常用于表示对象的大小或计数 size_t length = strlen(str1); // 计算 str1 的长度,不包括空字符'\0' cout<<lemgth; char s[100]; cin>>s; int n=strlen(s); cout<<n; char s[10]="ab d"; cout<<strlen*(s); 字符数组与字符串常量 const char *const str3 = "World"; // 指向常量字符串的常量指针 第一个 const(在 char 前面):这表示 str3 所指向的字符数组(即字符串)是不可修改的 第二个 const(在 * 后面):这表示 str3 本身是一个指针常量,它的值(即它所指向的地址)在初始化之后不能被改变 字符数组的遍历 // 声明并初始化一个字符数组(字符串) char s[] = "Hello, World!"; ------------------------------------- for(int i=0;i<strlen(s);i++){ cout << s[i]; } // 获取字符串的长度(不包括结尾的空字符) int length = sizeof(s) / sizeof(s[0]) - 1; // 使用for循环遍历字符数组 for (int i = 0; i < length; ++i) { // 打印每个字符 cout << s[i]; } -----------------------------------------------------------------------字符串数组函数 将s2的内容拷贝到s1 strcpy(s1,s2) 将s2的内容添加到s1 strcat(s1,s2) 用于比较两个字符串 s1 和 s2 strcmp(s1,s2) strcasecmp(s1,s2) 如果s1的字典序 > s2的字典序则返回整数 如果s1的字典序 = s2的字典序则返回0 如果s1的字典序 < s2的字典序则返回负数 strstr:在串中查找指定字符串的第一次出现 char *position = strstr("Hello, world!", "world"); strrchr:这个函数在一个字符串中从后往前查找第一次出现指定字符的位置 char *position = strrchr("Hello, world!", 'o'); strtod:将字符串转换为double型值 char str[] = "123.456"; double num; char *endptr; num = strtod(str, &endptr); strtol:将串转换为长整数 char str[] = "1234567890"; long num; char *endptr; num = strtol(str, &endptr, 10); strupr:将串中的小写字母转换为大写字母 char str[] = "Hello, world!"; strupr(str); strlwr:该函数用于将字符串中的所有大写字母转换为小写字母 char str[] = "HELLO, WORLD!"; strlwr(str); strnset:将一个串中的所有字符都设为指定字符 char str[] = "Hello, world!"; //如果字符串的长度小于n,则整个字符串将被设置为该字符 strnset(str, '*', 5);
3.3.2 指针*
3.3.2.1 指针定义
什么是指针? 指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址 就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明 --------------------------------------------------------- int a[10]={1,2,3,4,5,6,7,8,9,10}; int *p = &a[3]; cout<<p<<endl; //0x70fdec cout<<*p<<endl; //4 指针即地址,所以输出p得到是地址 *是间接寻址运算符,作用是得到内存地址里存放的值 *P:得到的是这个地址内存放的值 --------------------------------------------------------- 当指针指向的是字符串数组时,cout<<p 不再输出一个地址值,而是p为首地址的整个字符串 char ar[20]={"All-Dream"}; char *p=ar+4; cout<<p<<endl; //Dream cout<<*p<<endl; //D //如果需要输出字符数组的地址 printf("%p",p); //00000000006ffe04 cout<<(void *)p; //0x6ffe04 --------------------------------------------------------- 指针的作用:可以通过指针间接访问内存 内存编号是从0开始记录的,一般用十六进制数字表示 可以利用指针变量保存地址 指针的声明:类型说明符号 *变量名 int *p; 指针的赋值 int num=5; p=# 指针的访问 cout<<*p; //5 指针变量的定义:数据类型 *指针变量 int *p=# int *p=&a; int a=10; //变量 int *p; //指针 p=&a; //指针变量 cout<<*p; 间接寻址运算符*:通过指针访问内存地址里的值 int num=5; int *p; p=# cout<<*p<<end; //5 int num=5; int *p=# *p=6; //把6赋值给指针p指向的变量 cout<<*p<<endl; //6 cout<<num<<endl; //6 指针所占内存空间 sizeof(int *) sizeof(float *) sizeof(double *) sizeof(char *) ------------------------------------------ char ch='A'; int i=99; double x=66.6; int ar[3]={0}; cout<<sizeof(ch)<<endl; //1 cout<<sizeof(i)<<endl; //4 cout<<sizeof(x)<<endl; //8 cout<<sizeof(ar)<<endl; //12 ------------------------------------------指针变量的大小只和操作系统有关 在 32 位系统中,一个指针变量在内存中占据 4 个字节的空间 在 64 位系统中,一个指针变量在内存中占据 8 个字节的空间 char ch='A'; int i=99; double x=66.6; int ar[3]={0}; char *pch=&ch; int *pi=&i; double *px=&x; int *par=&ar; cout<<sizeof(pch)<<endl; //8 cout<<sizeof(pi)<<endl; //8 cout<<sizeof(px)<<endl; //8 cout<<sizeof(par)<<endl; //8 空指针:指针变量指向内存中编号为0的空间/定义在标准库中的值为零的常量 int *p=NULL; 用途:初始化指针变量 注意:空指针指向的内存是不可以访问的 野指针:指针变量指向非法的内存空间 常见原因:未初始化的指针、释放后的指针、越界访问、内存泄漏、函数返回局部变量的地址 int* ptr1 = new int; // 分配内存,ptr1指向一个有效的内存地址 int* ptr2 = ptr1; // ptr2也指向同一块内存 delete ptr1; // 释放内存,ptr1不再有效 ptr1 = nullptr; // 将ptr1置为空指针,避免野指针 // 此时ptr2成为一个野指针,因为它仍然指向已释放的内存 cout << *ptr2; // 这将导致未定义行为,可能崩溃 const修饰指针:看const右侧紧跟的是指针还是常量(是指针就是常量指针 是常量就是指针常量) int a =10; int b = 10; const修饰指针(常量指针 ):const修饰的是指针,指针指向可以改,指针指向的值不可以更改 const int *p1=&a; p1 = &b; *p1 = 100; //报错 const修饰常量(指针常量):const修饰的常量,指针指向不可以改,指针指向的值可以更改 int *const p2 = &a; *p2 = 100; p2 = &b; //报错 const即修饰指针又修饰常量 const int *const p3 = &a; p3 = &b; //报错 p3 = 100; //报错 指针作为函数参数 void inc(int *px){ *px += 2; } int x=3; inc(&x); cout<<x; //5
3.3.2.2 指针数组
指针数组 int main(){ int arr[] = {1,2,3,4,5,6,7,8,9,10}; int *p = arr; //指向数组的指针 cout<<"第一个元素的地址:"<<&arr[0]<<endl; //0x6ffdd0 cout<<"第一个元素的地址:"<<arr<<endl; //0x6ffdd0 cout<<"第一个元素:"<<arr[0]<<endl; //1 cout<<"指针访问第一个元素(首地址):"<<*p<<endl; //1 for(int i=0;i<10;i++){ //利用指针遍历数组 cout<<*p<<endl; //1 2 3 4 5 6 7 8 9 10 p++; } return 0; } int ar[10]={2,4,7,9,0,1,6,47,33,6}; 数组指针一般是指向数组(首地址) int *p=ar; //数组名即代表数组地址 int *p=&ar[0]; 指向数组的某个元素 int *p=ar+3; int *p=&ar[3]; 用指针访问数组元素 int ar[10]={1,2,3,4,5,6,7,8,9,10}; int *p=ar; 下表法:用数组名[下标]、指针[下标]的形式访问数组元素 数组名[下标]:cout<<ar[2]; 指针[下标]:cout<<p[2]; 指针法:用*(ar+i)、*(p+i)的形式访问数组元素 *(ar+i):cout<<*(ar+2); *(p+i):cout<<*(p+2); 指针的运算 可以:+ - ++ -- 不可以:* / int ar[10]={1,2,3,4,5,6,7,8,9,10}; int *p=&ar[0]; p=p+1; //P++ 指针指向下一个数组元素 int *p=&ar[3]; p=p-1; //p-- 指针指向上一个数组元素 cout<<*p<<endl; 用指针遍历数组 方法一:数组下标作为循环变量 int ar[10]={1,2,3,4,5,6,7,8,9,10}; int *p=ar; //指针不动,下标增加 for(int i=0;i<10;i++){ cout<<*(P+i)<<endl; cout<<p[i]<<endl; } 方法二:指针作为循环变量 int ar[10]={1,2,3,4,5,6,7,8,9,10}; int *p=NULL; //每循环一次,指针+1(移动) for(p=ar;p<(ar+10);P++){ cout<<*p<<endl; } 方法三:循环控制变量i作为循环次数的控制用,不作为数组下标用 int ar[10]={1,2,3,4,5,6,7,8,9,10}; int *p; p=ar; for(int i=0;i<10;i++){ cout<<*p<<endl; p++; } 除开for循环之外,还可以用:while do..while
3.3.3 结构体struct
3.3.3.1 结构体定义
结构体的人基本概念:结构体属于用户自定义的数据类型,允许用户存储不同的数据类型 结构体定义 struct 结构体名{ 数据类型 成员名1; 数据类型 成员名2; 数据类型 成员名3; }; 访问结构体成员的方式 结构体变量名.成员名 Student stu1; stu1.num=32; 结构体数组[下标].成员名 Student ar[3]; ar[2].num=98; 结构体指针——>成员名 Student *p=&stu1; p->num=100; 结构体变量的声明和初始化 struct Student{ string name; int age; float score; }st1={'张三',18,100},st2={'李四',18,100},stu3; stu3.name="王五" stu3.age=18; stu3.score=80; struct student stu4; stu4.name="张三"; stu4.age=18; stu4.score=100; Student st5={'张三',18,100}; ------------------------ struct Student{ string name; int age; float score; }; ------------------------ struct{ string name; int age; float score; }st1,st2; ------------------------ 结构体嵌套结构体:在结构体中可以定义另一个结构体作为成员,来解决实际问题 struct student{ string name; int age; int score; }; struct teacher{ int id; string name; int age; struct student stu; }; struct teacher t1; t1.id=1; t1.name="老王"; t1.age=40; t1.stu.name="张三"; t1.stu.age=18; t1.stu.score=100; 定义别名 typedef 原名 别名; typedef int size; size i=2;
3.3.3.2 结构体数组
结构体数组:将自定义的结构体放入到数组中方便维护 struct 结构体名 数组名[元素个数] = {{},{}...{}} struct Student { string name; int age; float score; }; // 创建一个包含3个Student结构体的数组 Student students[3]; // 初始化结构体数组 Students group1[3]={{"Alice",20,85.5},{"Bob",21,92.0},{"Charlie",19,78.5}}; students[0].name = "Alice"; students[0].age = 20; students[0].score = 85.5; students[1].name = "Bob"; students[1].age = 21; students[1].score = 92.0; students[2].name = "Charlie"; students[2].age = 19; students[2].score = 78.5; // 遍历结构体数组并输出内容 for (int i = 0; i < 3; ++i) { cout << "Name: " << students[i].name << ", Age: " << students[i].age << ", Score: " << students[i].score << endl; }
3.3.3.3 结构体函数
结构体作为参数向函数中传递 struct student{ string name; int age; int score; }; 值传递 void printStudent(student stu){ stu.age=28; cout<<stu.age<<endl; } student stu = {"张三",18,100}; printStudent(stu); 地址传递 void printStudent(student *stu){ stu->age=28; cout<<stu->age<<endl; } student stu = {"张三",18,100}; printStudent(&stu); 数组传值 void printStudent(student stu){ for(int i=0;i<n;i++){ cout<<stu[i].age<<endl; } } student stu[2] = {{"张三",18,100},{"李四",18,100}}; printStudent(stu);
3.3.3.4 结构体指针
结构体指针:通过指针访问结构体中的成员 利用->可以通过结构体指针访问结构体属性 struct student{ string name; int age; int score; }; struct student stu = {"张三",18,100}; struct student *p = &stu; p->score = 80;
4.输入输出
4.1 语句 输入cin输出cout
输入 cin :c++输入流对象,绑定的是键盘【>>】 int a = 0; //要先定义 cin >> a; 输出 cout:c++的输出流对象,绑定标准输出设备显示器【<<】 cout <<"整型变量a=" <<a <<endl;
举例
手动赋值输出
#include <bits/stdc++.h> //万能头文件 using namespace std; //标准命名空间 int main(){ //程序入口 int a = 0; cout <<"请给整型变量a赋值:" <<endl; cin >> a; cout <<"整型变量a=" <<a <<endl; float b = 3.14f; cout <<"请给浮点型变量b赋值:" <<endl; cin >> b; cout <<"浮点型型变量b=" <<b <<endl; return 0; //程序正常结束 }
精确保留位数
int x; cin>>x; cout<<x; cout<<fixed<<setprecision(k)<<x; //保留k位小数 cout<<setw(k)<<x; //如果小于k位,则占k个字符位置,否则就按实际的长度占位置 int n=99; cout<<fixed<<setprecision(2)<<sqrt(n)<<x; 来源于头文件:#include <iomanip>
4.2 格式化 输入scanf输出printf函数
4.2.1 scanf格式字符串
scanf格式字符串 一般形式为: %[*][输入数据宽度][长度]类型 其中有方括号[]的项为任选项 %:表示一个格式指定符的开始 [*]:这是一个可选的星号,用于表示跳过该输入项,不将其存储在变量中 这通常与 * 修饰符一起使用,如 %*d,表示读取一个整数但不保存它 [输入数据宽度]:这是一个可选的整数值,用于指定输入数据的最小宽度。 如果输入的数据宽度小于这个值,scanf 会继续读取直到达到指定的宽度或遇到空白字符 [长度]:这是一个可选的长度修饰符,用于指定输入数据的大小。常见的长度修饰符有: h:短整型(short)或单字符(char) l:长整型(long) ll:长长整型(long long) L:用于 scanf 中不常见,但在 printf 中用于 long double 类型 j:intmax_t 类型(C99 中定义) z:size_t 类型(C99 中定义) t:ptrdiff_t 类型(C99 中定义) 类型:指定输入数据的类型。常见的类型指定符有: d:有符号十进制整数 u:无符号十进制整数 o:无符号八进制整数 x 或 X:无符号十六进制整数(x 为小写,X 为大写) c:单个字符 s:字符串,直到遇到空白字符或达到指定的宽度为止 f:浮点数 e、E、g、G:浮点数的科学计数法表示 p:指针地址 %:读取一个 % 符号
例子
#include <stdio.h> int main() { int a; float b; char c; printf("请输入一个整数、一个浮点数和一个字符,用空格分隔:\n"); // 读取一个整数、一个浮点数和一个字符 scanf("%d %f %c", &a, &b, &c); printf("您输入的整数是:%d,浮点数是:%f,字符是:%c\n", a, b, c); return 0; }
4.2.2 printf格式化输出
printf格式字符串 一般形式为: %[标志][输出最小宽度][.精度][长度]类型 其中方括号[]中的项为可选项 %[flags][Width][.Precision][Length]Type %:格式字符串的开头,表示一个格式指定符的开始 [Flags]:标志,用于控制输出的格式。常见的标志有: -:左对齐输出 +:输出正数时显示符号 空格:输出正数时前面加空格(默认情况下,正数不加任何符号) #:对于 o(八进制)、x 或 X(十六进制)转换,输出前导零;对于 e、E、f、g 或 G 转换,输出小数点;对于 g 或 G 转换,输出尾随零 0:用零填充空白处(与宽度指定符一起使用) [Width]:输出最小宽度。如果输出的数据小于这个宽度, 则输出会左对齐或右对齐(取决于是否使用了 - 标志) 并用适当的字符(通常是空格或 0,取决于是否使用了 0 标志)填充至指定宽度 [.Precision]:精度。对于某些转换类型,它指定了输出的最大字符数或小数点后的数字个数 对于 d、i、o、u、x、X 转换,它指定了输出的最小字符数 对于 e、E、f 转换,它指定了小数点后的数字个数 对于 g、G 转换,它指定了最大的有效数字个数 对于 s 和 c 转换,它指定了最大字符数 [Length:长度修饰符,用于指定输出数据的大小。常见的长度修饰符有: h:短整型(short)或单字符(char) l:长整型(long) ll:长长整型(long long) L:长双精度(long double),用于 e、E、f、g 或 G 转换 j:intmax_t 类型(C99 中定义) z:size_t 类型(C99 中定义) t:ptrdiff_t 类型(C99 中定义) [Type]:类型指定符,用于指定如何格式化输出数据。常见的类型指定符有: d 或 i:有符号十进制整数 o:无符号八进制整数 u:无符号十进制整数 x:无符号十六进制整数(小写字母) X:无符号十六进制整数(大写字母) f:十进制浮点数 e:科学计数法表示的浮点数(小写 e) E:科学计数法表示的浮点数(大写 E) g:根据数值大小自动选择 %f 或 %e 格式,但不输出尾随零 G:与 g 类似,但使用大写字母 E c:字符 s:字符串 p:指针地址 n:不输出任何内容,只将已写入的字符数存入相应的参数中 %:输出一个 % 字符
例子
#include <stdio.h> int main() { int num = 12345; printf("整数:%d\n", num); // %d 用于输出十进制整数 printf("%-10d\n", num); // 输出整数,宽度为 10,左对齐,右边用空格补齐 printf("%10d\n", num); // 输出整数,宽度为 10,右对齐(默认),左边用空格补齐 printf("%010d\n", num); // 输出整数,宽度为 10,左边用0补齐 float f = 3.14159; printf("单精度浮点数:%f\n", f); // %f 用于输出浮点数(单精度) printf("双精度浮点数:%lf\n", f); // %lf 用于输出浮点数(双精度),l 表示 long printf("%.2f\n", f); // 保留小数点后面2位 printf("%10.2f\n", f); // 输出浮点数,保留两位小数,宽度为 10,右对齐 printf("%06.2f\n", 3.14159265) ; // 保留小数点后面2位同时让结果占6个空格,左边用空格补齐 char str[] = "Hello, World!"; printf("字符串:%s\n", str); // %s 用于输出字符串 printf("%10s\n", str); // 输出字符串,宽度为 10,右对齐(默认),如果字符串长度小于宽度,则左侧填充空格 printf("-%10s\n", str); // 输出字符串,宽度为 10,左对齐,如果字符串长度小于宽度,则右侧填充空格 int num1,num2; scanf("%d%d",&num1,&num2); printf("%d+%d=%d/n",num1,num2,num1+num2); return 0; }
4.3 单个字符 输入getchar输出putchar函数
#include <stdio.h> int main() { char c; // 使用 getchar() 从用户那里读取一个字符 c = getchar(); // 使用 putchar() 将该字符输出到控制台 putchar(c); return 0; }
4.4 标准输入fgets输出puts函数
#include <cstdio> int main() { char str[100]; // 定义一个足够大的字符数组来存储输入的字符串 // 使用 fgets 从标准输入读取字符串 // 注意:fgets 会读取换行符,并将其存储在字符串中 fgets(str, sizeof(str), stdin); // 使用 puts 将字符串输出到标准输出 // puts 会自动在字符串后添加换行符 puts(str); return 0; }
5.常量和变量
5.1 命名规则
1.标识符不能是关键字 2.标识符只能由字母(A~Z a~z)、数字(0~9)、下划(_)线组成 3.第一个字符必须是字母或下划线 4.标识符中字母区分大小写 5.变量名的长度一般不超过8个字符 建议:给标识符命名时,争取做到见名知其意的效果,方便自己和他人阅读
5.2 变量
作用:方便我们管理内存空间 数据类型 变量名称 = 变量初始值; int a = 10;
名称 在何处声明/定义 作用域 全局变量 在函数外部 进行定义
一般在源代码文件的顶部
从变量定义的位置起,直至本源文件结束为止 局部变量 在函数内部 进行定义 只能在当前定义它们的函数中使用
函数调用结束后该变量就无效
形参也是局部变量 当全局变量与局部变量同名时,遵循局部优先的规则 也就是说,在局部变量的作用域内,局部变量有效,全局变量被屏蔽 不同函数内部的变量,即使同名,由于作用域不同,所以互不影响
5.3 常量
作用:用于记录程序中不可更改的数据 定义常量的两种方式 #define 宏常量:#define 常量名 常量值 通常在文件的上方定义,表示一个常量 const修饰的变量:const 数据类型 常量名=常量值 通常在变量定义前加关键字const,修饰该变量为常量,不可修改
5.3.1 #define 宏常量
通常定义在文件的上方
#include <bits/stdc++.h> using namespace std; #define day 7 int main(){ //day = 10; 错误:day是常量,一修改就会报错 cout <<"一周总共有多少天:" <<day <<"天" <<endl; return 0; }
5.3.2 const 修饰的变量
#include <bits/stdc++.h> using namespace std; int main(){ const int month = 12; //month = 24; 错误:const修饰的变量也称为常量 cout <<"一年有多少个月份:" <<month <<"个" <<endl; return 0; }
6.运算符
6.1 算术运算符
用于处理四则运算
运算符 术语 实例 结果 + 正号 +3 3 - 负号 -3 -3 + 加 10+5 15 - 减 10-5 5 * 乘 10*5 50 / 除 10/5 2 % 取余(取模) 10%3 1 ++ 前置递增 a=2;
b=++a;
a=3;
b=3;
++ 后置递增 a=2;
b=a++;
a=3;
b=2;
-- 前置低贱 a=2;
b=--a;
a=1;
b=1;
-- 后置递减 a=2;
b=a--;
a=1;
b=2;
余数的正负:由被除数决定 浮点数没有取余运算 如果a和b都是整数,则a/b会得到a除以b的商
6.2 赋值运算符
用于将表达式的值赋给变量
运算符 术语 实例 结果 = 赋值 a=2;
b=3;
a=2;
b=3;
+= 加等于 a=0;
a+=2;
a=2; -= 减等于 a=5;
a-=3;
a=2; *= 乘等于 a=2;
a*=2;
a=4; /= 除等于 a=4;
a/=2;
a=2; %= 模等于 a=3;
a%2;
a=1;
6.3 比较运算符/关系运算符
用于表达式的比较,并返回一个真值或假值
运算符 术语 实例 结果 == 相等于 4==3 0 != 不等于 4!=3 1 < 小于 4<3 0 > 大于 4>3 1 <= 小于等于 4<=3 0 >= 大于等于 4>=1 1
6.4 逻辑运算符
用于根据表达式的值返回真值或假值
运算符 术语 实例 结果 ! 非 !a 如果a为假,则!a为真
如果a为真,则!a为假
&& 与 a&&b 如果a和b都为真,则结果为真,否则为假 || 或 a||b 如果a和b有一个为真,则结果为真
二者都为假时,结果为假
6.5 位运算符
进制转换【最全进制转换汇总】(整数_小数_正数_负数)任意进制之间的相互转换
加法口诀:先把数位对齐,从低位到高位,依次进行加法,进位规则“逢二进一” 1 1 0 1 + 1 1 0 ___________ 1 0 0 1 1 减法口诀:先把数位对齐,同一数位不够减时,从高一位借位,借位规则是“借一0当二” 1 1 0 1 0 1 - 1 1 1 1 0 _______________ 1 0 1 1 1 乘法口诀:先把数位对齐,从低位到高位,依次进行乘法,运算规则“一一得一,其他都得零” 1 1 0 1 x 1 1 0 _______________ 1 0 1 1 0 0 0 0 + 1 0 1 1 _______________ 1 1 0 1 1 1 除数和被除数的高位对齐,做减法,够减时商为 1,不够减时商为0 10010 ____________________ 1001/ 10100010 1001 ____________________ 1001 1001 ____________________ 0
位运算符 作用 运算规则(整型 字符型) 实例 & 按位与 两位同时为1,结果为1 A&B | 按位或 两位只要有一个1,结果为1 A|B ~ 按位非/取反 取反:0变1,1变0 ~A ^ 按位异或 两位不同时,结果为1 A^B << 向左位移 向左移动,右侧补0 A<<2 >> 向右位移 向右移动,左侧补符号位 A>>2
6.6 运算符优先级
类型 运算符 括号运算 () 非 逻辑非(!)的优 > 按位取反(~) 算术运算 +、-、*、\、% 位运算符 <<、>> 关系运算 >、>=、<、<=、==、!= 位运算符 位与& > 位或| > 位异或^ 逻辑运算 逻辑与&& > 逻辑或|| 赋值运算 = 、+= 、-= 、*= 、/= 、%=
7.程序流程结构
C/C++支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构 顺序结构:程序按顺序执行,不发生跳转 选择结构:依据条件是否满足,有选择的执行相应功能 循环结构:依据条件是否满足,循环多次执行某段代码
7.1 选择结构
7.1.1 if语句
单分支语句 if(条件) { 条件满足执行的语句块; } 双分支语句 if(条件) { 条件满足执行的语句块; }else{ 条件不满足执行的语句块; } 多分支语句 if(条件1) { 条件1满足执行的语句块; }else if(条件2){ 条件1满足执行的语句块; } ... else{ 都不满足执行的语句块; }
举例
分数和最重的猪
#include <bits/stdc++.h> //万能头文件:包含了目前c++所包含的所有头文件 using namespace std; //标准命名空间 int main(){ //程序入口 //------------------------------------------------------------------------------------------// int score1 = 0; cout << "请输入分数:" << score1 <<endl; cin >> score1; if (score1 >=600) { cout <<"你输入的分数为:" << score1 << "分" <<endl << "恭喜你考试重本" <<endl; } else { cout <<"你输入的分数为:" << score1 << "分" <<endl << "很抱歉,别灰心加油!" <<endl; } //------------------------------------------------------------------------------------------// int score2 = 0; cout << "请输入分数:" << score2 <<endl; cin >> score2; cout <<"你输入的分数为:" << score2 << "分" <<endl; if (score2 >=600) { cout << "恭喜你考试一本" <<endl; if (score2 >700) { cout << "恭喜你考上清华大学" <<endl; }else if (score2 > 650) { cout << "恭喜你考上北大" <<endl; }else { cout << "恭喜你考上人大" <<endl; } } else if(score2 >=500){ cout << "恭喜你考试二本" <<endl; }else if (score2 >=400) { cout << "恭喜你考试三本" <<endl; }else { cout << "很抱歉你没有考上本科" <<endl; } //------------------------------------------------------------------------------------------// int a = 0; int b = 0; int c = 0; cout << "请输入小猪a的体重" << endl; cin >> a; cout << "请输入小猪a的体重:" << a << "斤"<<endl; cout << "请输入小猪b的体重" << endl; cin >> b; cout << "请输入小猪b的体重:" << b << "斤"<<endl; cout << "请输入小猪c的体重" << endl; cin >> c; cout << "请输入小猪c的体重:" << c << "斤"<<endl; if (a>b) { if (a>c) { cout <<"小猪a最重" <<endl; }else { cout <<"小猪c最重" <<endl; } }else { if (b>c) { cout <<"小猪b最重" <<endl; }else { cout <<"小猪c最重" <<endl; } } //------------------------------------------------------------------------------------------// return 0; //程序正常结束 }
绝对值
第一种 if(x<0){ x=x*-1 } 第二种 x=abs(x)
奇偶判断
//偶数 if(n%2==0){ } //奇数 if(n%2!=0){ }
字符类型判断
if(ch>='a'&&ch<='z'){ } if(ch>='A'&&ch<='Z'){ } if(ch>='0'&&ch<='9'){ }
闰年判断
if(year%4==0 && year%100!=0 || year%400==0){ }
虫吃草问题
int x,y,n,d; cin>>n>>x>>y; d=y/x; if(y%x==0) cout<<n-d; else cout<<n-d-1;
7.1.2 三目/元运算符
单目运算:+= -- ! 双目运算:= - * \ % > >= < <= == != && ||
三目运算
语法 表达式1?表达式2:表达式3; 如果表达式1的值为真,执行表达式2,并返回表达式2的结果 如果表达式1的值为假,执行表达式1,并返回表达式1的结果 在c++中三目运算返回的是变量,可以继续赋值 (a<b?a:b)=100 cout<<"a="<<a<<endl; cout<<"b="<<b<<endl;
7.1.3 switch语句
执行多条件分支语句
case的大小不一定按照顺序、同组的case顺序可以调换 :但是建议按照顺序写
switch(表达式) { case 结果1: 执行语句; break; case 结果2: 执行语句; break; case 结果3: 执行语句; break; ... default: 执行语句; break; }
举例
int score; cin>>score; switch(score) { case 10: case 9: cout<<"经典"<<endl; break; case 8: cout<<"非常好"<<endl; break; case 7: case 6: cout<<"一般"<<endl; break; default: cout<<"烂片"<<endl; break; }
7.2 循环结构
7.2.1 while循环语句
满足循环条件,执行循环语句;只要循环条件为真就执行循环语句;写循环一定要避免死循环的出现
while(循环条件) { 循环语句 }
举例
遍历m到n之间的所有数(包括m和n)
int t=m while(t<=n){ t++; }
拆书模板
while(t){ //对当前各位进行操作 int ge=t%10; t/=10; }
反转数模板
int res=0; while(t){ int ge=t%10; res=res*10+ge; //res是翻转以后的结果 t/=10; }
7.2.2 do...while循环语句
满足循环条件,执行循环语句;与while的区别在于do...while会先执行一次循环语句 再判断循环条件
do { 循环语句 }while(循环条件);
举例
水仙花数
#include <bits/stdc++.h> //万能头文件:包含了目前c++所包含的所有头文件 using namespace std; //标准命名空间 int main(){ //程序入口 //水仙花数 :一个3位数,每个位置上的数的3次幂之和等 于本身 int num = 100; do { int a = 0; int b = 0; int c = 0; a = num%10; b = num/10%10; c = num/100; if (a*a*a+b*b*b+c*c*c == num) { cout << num <<endl; } num++; }while(num <1000); return 0; //程序正常结束 }
7.2.3 for循环语句
满足循环条件,执行循环语句
for(起始化;条件判断;更新) { 循环语句; }
举例
组成的n层的等腰三角形
#include <iostream> using namespace std; int main() { int n; cin>>n; for(int i=1;i<=n;i++){ for(int j=1;j<=n-i;j++){ cout<<" "; } for(int j=1;j<=2*i-1;j++){ cout<<"*"; } cout<<"\n"; } return 0; }
敲桌子
#include <bits/stdc++.h> using namespace std; //敲桌子:从1~100,如果数字个位、十位含有7、或者数字是7的倍数。我们打印敲桌子,其他数直接打印输出 int main(){ int b = 0; for (int i = 1; i < 101; i++) { if (i%10 ==7|| i/10%10==7 ||i%7 ==0) { cout << "敲桌子" <<endl; }else { cout << i <<endl; } } return 0; }
求和模板
int s=0; for(int i=1;i<=n;n++){ int x; cin>>x; s+=i; }
最大值模板
//maxv初始化 int maxv=-1 for(int i=1;i<=n;i++){ int x; cin>>x; if(x>maxv){ maxv=x; } } //maxv不初始化 int maxv= for(int i=1;i<=n;i++){ int x; cin>>x; if(i=1 || x>maxv){ maxv=x; } }
统计出现的次数
int cnt=0; int m; cin>>m; //需要统计的值 for(int i=1;i<=n;i++){ int x; cin>>x; if(x==m){ cnt++; } }
a^b
int s=1; for(int i-1;i<=b;i++){ s=s*a; }
质数判断
bool st=true; int n; cin>>n; if(n<2){ st=false; } for(int i=2;i<=n/i;i++){ if(n%i==0){ st=false; } } if(st==true){ //满足质数需要执行的内容 }else{ //不满足质数需要执行的内容 }
百钱百鸡:公鸡每只5文钱,母鸡每只3文钱,小鸡3只共1文钱
for(int i=0;i<20;i++){ for(int j=0;i=j<33;j++){ for(int k=0;k<100;k++){ if(i+j+k==100 && 5*i+3*j+k/3==100){ cout<<i<<""<<j<<""<<k<<endl; } } } }
7.2.4 嵌套语句
在循环体中再嵌套一层循环,解决一些实际问题
10*10正方形
#include <bits/stdc++.h> using namespace std; int main(){ for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { cout << "* "; } cout << endl; } return 0; }
九九乘法表
#include <bits/stdc++.h> using namespace std; int main(){ for (int i = 1; i < 9; i++) { for (int j = 1; j <= i; j++) { cout << "i*j=" <<i*j << " "; } cout << endl; } return 0; }
7.3 跳转语句
7.3.1 break语句
作用:用于跳出选择结构 或者 循环结构 break使用的时机: 出现在switch条件语句中:作用是终止case并跳出switch 出现在循环语句中:作用是跳出当前的循环语句 出现在嵌套循环中:跳出最近的内层循环语句 for(int i=1;1<=5;i++){ cout<<i<<endl; //1 2 3 4 5 } for(int i=1;1<=5;i++){ if(i==3) break; cout<<i<<endl; //1 2 }
7.3.2 continue语句
作用:在循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环 可以筛选条件,执行到此就不在向下执行,执行下一次循环 for(int i=1;1<=5;i++){ cout<<i<<endl; //1 2 3 4 5 } for(int i=1;1<=5;i++){ if(i%==0) continue; cout<<i<<endl; //1 3 5 }
7.3.3 goto语句
作用:可以无条件跳转语句 语法:goto 标记; 解释:如果标记的名称存在,执行到goto语句时,会跳转到标记的位置
举例
int main(){ #输出 1 5 cout<<"1"<<endl; goto a; cout<<"2"<<endl; cout<<"3"<<endl; cout<<"4"<<endl; a: cout<<"5"<<endl; }
8.函数
作用:将一段经常使用的代码封装起来,减少重复代码
一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能
基本顺序:先声明、再调用、再定义
8.1 函数的定义
函数定义一般主要有5个步骤: 返回值类型:void bool int double string char float 返回值是void时,函数体无需return语句 函数名:需要满足c++标识符命名规则(最好见名知意) 形式参数:若没有参数,则参数列表为空,直接写() 参数类型 参数名 多个参数之间用逗号","间隔开来 函数体语句:花括号内的代码,函数内需要执行的语句 return表达式:和返回值类型挂钩,函数执行完后,返回相应的数据 返回值类型 函数名(形式参数列表) //函数头 { //函数体 函数体语句; return 表达式; } int sum(int a,int b){ int sum = a + b; return sum; }
8.2 函数的声明
函数的声明:声明可以多次,但是定义只能有一次 返回值类型 函数名(参数列表); int sum(int a,int b);
8.3 函数的调用
调用:函数名(实际参数列表) 值传递调用:传递值——不会改变实参 适合那些不需要在函数内部修改的数据,或者对于小型数据类型来说,复制开销可以接受 int sum(int a,int b){ int sum = a + b; return sum; } int a = 1; int b = 2; int c = sum(a,b); 指针调用:转递地址——会改变实参 适合需要修改原始数据或者传递大型数据结构的情况,但需要更多的编程技巧和对指针的深刻理解 int sum(int *a,int *b){ int sum = *a + *b; return sum; } int a = 1; int b = 2; int c = sum(&a,&b); 引用调用:传递引用——会改变实参 传递的是对实参的引用(即实参的别名) 在大多数情况下是首选,因为它结合了指针和值传递的优点,语法更加直观,并且减少了出错的可能性 int sum(int &a,int &b){ int sum = a + b; return sum; } int a = 1; int b = 2; int c = sum(a,b);
8.4 形参和实参
实参和形参 // 函数定义,这里的x和y是形参 void addNumbers(int x, int y) { int sum = x + y; cout << "The sum is: " << sum << endl; } int main() { int a = 5; int b = 10; // 函数调用,这里的5和10是实参 addNumbers(a, b); // 再次函数调用,这次直接使用字面量作为实参 addNumbers(7, 3); return 0; }
8.5 函数的常见形式
函数的常见样式 无参无返 void test01(){ cout<<"666"<<endl; } 有参无返 void tets02(int a){ cout<<a<<endl; } 无参有返 int tets03(){ int sum=1+2; return sum; } 有参有返 int test04(int a,int b){ int sum=a+b; return sum; }
8.6 分文件编写
函数的分文件编写 创建后缀名为.h的头文件:在头文件中写函数的声明 swap,h #include<bits/stdc++.h> using namespace std; void swap(int a, int b); 创建后缀名为.cpp的源文件:在源文件中写函数的定义 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; }
8.7 Lambda函数
Lambda函数(也叫 Lambda 表达式) Lambda 表达式把函数看作对象:可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值 Lambda 表达式本质上与函数声明非常类似:[capture](parameters)->return_type{body} [capture] 是捕获子句,用于指定Lambda函数体内可以访问的外部变量 []:默认不捕获任何变量 [=]:默认以值捕获所有变量 [&]:默认以引用捕获所有变量 [x]:仅以值捕获x,其它变量不捕获 [&x]:仅以引用捕获x,其它变量不捕获 [=, &x]:默认以值捕获所有变量,但是x是例外,通过引用捕获 [&, x]:默认以引用捕获所有变量,但是x是例外,通过值捕获 [this]:通过引用捕获当前对象(其实是复制指针) [*this]:通过传值方式捕获当前对象 (parameters) 是参数列表,用于指定 Lambda 函数的参数 -> return_type 是返回类型,用于指定 Lambda 函数的返回类型 如果省略此部分,编译器将自动推导返回类型 {body} 是 Lambda 函数的主体,包含要执行的代码 第一个例子:有参数 // 定义一个Lambda函数,接受两个整数参数并返回它们的和 auto add = [](int a, int b) -> int { //使用auto关键字让编译器自动推断其类型 return a + b; }; // 使用Lambda函数 int sum = add(5, 3); 第二个例子:无参数 int counter = 0; auto increment = [&counter]() { ++counter; }; // 调用Lambda函数几次 increment();
8.8 函数递归
什么是递归算法? 通过函数调用自身,将问题转化为本质相同但规模较小的子问题,是“分而治之”策略的具体体现 将问题划分成若干个子问题 以同样的方式分别去处理各个子问题 把各个子问题的处理结果综合起来,形参最终的处理结果 递归算法的两个必要条件: 递归表达式(找规律——“分而治之”) 递归出口(找出口——使递归“有去无回”) 分析递归问题的步骤 明确函数的功能(利用这个函数来求什么) 根据递归的基本思想(把规模大的问题转化为规模小的相似的子问题来解决)来找 出等价关系式 寻址递归结束条件(找边界、临界) 函数直接或间接地调用自己,称为递归调用 直接递归:直接调用自己 间接递归:A调用B,B又调用A的递归 递归函数一般符合以下格式: 数据类型 递归函数名(形式参数){ if(递归结束的条件){ 递归出口代码 return 返回值; }else{ 调用递归函数名(实参列表)进行处理 return 返回值; } } 基本逻辑 ——>从外到内调用 <——从内到外输出
举例
阶乘
/* 阶乘(factorial)的定义: 一个正整数的阶乘是所有小于及等于该数的正整数的积 n! = n * (n-1) * (n-2) *... * 2 * 1 输入一个正整数n,输出n!的结果 */ #include<iostream> using namespace std; int fac(int n){ if(n==1) return 1; return n*fac(n-1); } int main(){ int num; cin>>num; cout<<fac(num); return 0; }
汉诺塔问题
/* 【课堂编程】汉诺塔问题:输入汉诺塔层数n,输出移动步骤。汉诺塔的算法思路: 如果只有一个圆盘,则把该圆盘从A柱到C柱,结束。 如果有n个圆盘,则把前n-1个圆盘移动到B,然后把自己移动到C,最后再把前n-1个移动到C。 【输入】一个整数n,表示A柱上有n个圆盘(0<n<=10) 【输出】若干行,一行是一次移动步骤 */ #include<iostream> using namespace std; void hanoi(int,char,char,char); /* 主函数 */ int main(){ int n; printf("输入汉诺塔的层数:"); scanf("%d",&n); hanoi(n,'A','B','C'); return 0; } /* 汉诺塔递归函数 n-层数,A-起始柱,B-辅助柱,C-目标柱 */ void hanoi(int n,char A,char B,char C){ // 递归出口 if(n==1){ // 圆盘从A移动到C printf("%c To %c\n",A,C); }else{ // 上面n-1层汉诺塔(从A移到B) // 此时,A为起始柱, B为目标柱,C为辅助柱 hanoi(n-1,A,C,B); //A——>B // 将A上遗留的最后一个圆盘移动到C上 printf("%c To %c\n",A,C); //A——>C // B上n-1层汉诺塔移回C // 此时,B为起始柱, C为目标柱,A为辅助柱 hanoi(n-1,B,A,C); //B——>C } }
斐波那契数列
/* 【课堂编程】斐波那契数列:斐波那契数列(Fibonacci)是指这样的数列:1,1,2,3,5,8,13…… 这个数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和。 【编程挑战 】输入正整数n,输出斐波那契数列第n项 【输入】一个正整数n,表示第n项 【输出】第n项是多少 【输入样例】4 【输出样例】3 */ #include<iostream> using namespace std; int fibo(int n){ if(n<=2) return 1; else return fibo(n-1)+fibo(n-2); } int main(){ int x; cin>>x; cout<<fibo(x); return 0; }
打印直角三角形
/* 输入三角形的行数n,输出*组成的三角形图案。要求用递归函数实现整个三角形图案的输出。 【输入】输入一个整数n 【输出】*组成的三角形 【输入样例】7 【输出样例】 * ** *** **** ***** ****** ******* */ #include<iostream> using namespace std; // 输出n行的*三角形 void draw(int n){ if(n==1){ // 递归出口 cout<<"*"<<endl; } else{ // 递归 draw(n-1); // n-1的三角形 for(int i=1;i<=n;i++)// 一行n个* cout<<"*"; cout<<endl; } } int main(){ int x; cin>>x; draw(x); return 0; } // 如果输入3 // 从外到内进行调用:draw(3) draw(2) draw(1) // 从内到外进行输出:draw(1) draw(2) draw(3)
爬楼梯
/* 【编程挑战 】有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶或2阶。输入楼梯的级数,求有小孩有多少种不同的走楼梯方式。 【输入】一个整数n代表楼梯总级数(1≤n≤30) 【输出】不同的楼梯走法数 【输入样例1】5 【输出样例1】8 【输入样例2】10 【输出样例2】89 */ #include<iostream> using namespace std; // n阶楼梯的走法数 int F(int n) { if (n == 1) return 1; else if (n == 2) return 2; else // 递归关系 return F(n - 1) + F(n - 2) ; } int main(){ int x; cin>>x; cout<<F(x); return 0; }
/* 【编程挑战 】某个上班族正在上楼梯,楼梯有n阶台阶,他一次可以上1阶、2阶、3阶。输入楼梯的级数,求有多少种不同的上楼方式。 【输入】一个整数n代表楼梯总级数(1≤n≤30) 【输出】不同的楼梯走法数 【输入样例1】5 【输出样例1】13 【输入样例2】10 【输出样例2】274 */ #include<iostream> using namespace std; // n阶楼梯的走法数 int F(int n) { if (n == 0 || n == 1) return 1; else if (n == 2) return 2; else // 递归关系 return F(n - 1) + F(n - 2) + F(n - 3); } int main(){ int x; cin>>x; cout<<F(x); return 0; }
约瑟夫问题:画出来看
/* 【编程挑战 】n个人围成一圈,编号依次为 1,2,3,…,n。从第一个人开始报数, 数到 m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈。 以此类推,直到所有的人都出列。请输出最后一个出列人的编号。 【输入】两个整数 n,m(1≤n,m≤100)。 【输出】一个整数,表示最后一个人的编号。 【输入样例1】10 3 【输出样例1】4 【输入样例2】41 3 【输出样例2】31 */ #include<iostream> using namespace std; /* ysf(n,m) 表示 n 个人进行报数时,每报到 m 时淘汰那个人,最终胜利者的编号; ysf(n-1,m) 表示,n-1 个人报数,每报到 m 时淘汰那个人,最终胜利者的编号; 所有编号都从1开始; */ int ysf(int n,int m){ if(n==1) return 1; else return (ysf(n-1,m) -1 + m)%n + 1; } int main(){ int n,m; cin>>n>>m; cout<<ysf(n,m); return 0; }
/* 约瑟夫环(编号从0开始) 【编程挑战 】n个人围成一圈,编号依次为 0,1,2,3,…,n-1。 从第一个人开始报数,数到 m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈。 以此类推,直到所有的人都出列。请输出最后一个出列人的编号。 【输入】两个整数 n,m(1≤n,m≤100)。 【输出】一个整数,表示最后一个人的编号。 【输入样例1】10 3 【输出样例1】3 【输入样例2】41 3 【输出样例2】30 */ // 用前面的递归公式(针对编号从1开始的情况),需要把函数最终返回值-1 #include<iostream> using namespace std; /* ysf(n,m) 表示 n 个人进行报数时,每报到 m 时淘汰那个人,最终胜利者的编号; ysf(n-1,m) 表示,n-1 个人报数,每报到 m 时淘汰那个人,最终胜利者的编号; 所有编号都从1开始; */ int ysf(int n,int m){ if(n==1) return 1; else return (ysf(n-1,m) + m -1)%n + 1; } int main(){ int n,m; cin>>n>>m; // 函数返回的编号从1开始,最终输出的编号要从0开始 // 只要把返回值-1即可 cout<<ysf(n,m)-1; return 0; }
/* 约瑟夫环(编号从0开始) 【编程挑战 】n个人围成一圈,编号依次为 0,1,2,3,…,n-1。 从第一个人开始报数,数到 m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈。 以此类推,直到所有的人都出列。请输出最后一个出列人的编号。 【输入】两个整数 n,m(1≤n,m≤100)。 【输出】一个整数,表示最后一个人的编号。 【输入样例1】10 3 【输出样例1】3 【输入样例2】41 3 【输出样例2】30 */ // 用新的递归公式(针对编号从0开始的情况) #include<iostream> using namespace std; /* ysf(n,m) 表示 n 个人进行报数时,每报到 m 时淘汰那个人,最终胜利者的编号; ysf(n-1,m) 表示,n-1 个人报数,每报到 m 时淘汰那个人,最终胜利者的编号; 所有编号都从0开始; 函数返回的编号也从0开始; */ int ysf(int n,int m){ if(n==1) return 0; else return (ysf(n-1,m) + m)%n ; } int main(){ int n,m; cin>>n>>m; cout<<ysf(n,m); return 0; }
机器人行走路径
/* 【编程挑战 】有一个网格横向x格,纵向y格,一个机器人一次只能一格,而且只能向右或向下走。 机器人总是从最左上角的格子出发,要走到最右下角的格子。 请问机器人有多少种不同的走法? 给定两个正整数x、y,返回机器人的走法数目。 【输入】两个正整数x,y(1≤x,y≤10) 【输出】机器人的走法数目 【输入样例】3 4 【输出样例】10 到达它左边格子的路径数量加上到达它上边格子的路径数量 到达右下角的不同路径数量是机器人:之和 选择向右走到达 倒数第二列的所有路径数量 选择向下走到达 倒数第一行的所有路径数量 */ #include<iostream> using namespace std; int f(int x, int y) { if (x == 1 || y == 1) return 1; return f(x - 1, y) + f(x, y - 1); // 左 上 } int main(){ int x,y; cin>>x>>y; cout<<(f(x,y)); return 0; }
8.9 内置函数
取整 向下取整 floor(x) double类型 向上取整 ceil(x) double类型 四舍五入 round(x) double类型 #include<cmath> int i = ceil(3.1); //对3.1进行向上取整
随机数
#include <iostream> using namespace std; //time系统时间头文件包含 #include <ctime> //系统生成随机数;玩家进行猜测;判断玩家的猜测;猜对 结束游戏;猜错 提示猜测的结果过大或者过小,重新返回第二步 int main(){ //添加随机种子:作用利用当前系统时间生成随机数,防止每次随机数都一样 srand((unsigned int)time(NULL)); int a = rand()%100+1;//生成一个0~99+1的随机数 cout << "系统生成一个随机数为:" << a <<endl; return 0; }
三:语法进阶
1.文件
文件类型分为两种: 文本文件:文件以文本的**ASCII码**形式存储在计算机中 二进制文件:文件以文本的**二进制**形式存储在计算机中,用户一般不能直接读懂它们 操作文件的三大类: fstream :读写操作 ofstream:写操作 ifstream:读操作 ofs.open("文件路径",打开方式); | 打开方式 | 解释 | | ----------- | -------------------------- | | ios::in | 为读文件而打开文件 | | ios::out | 为写文件而打开文件 | | ios::ate | 初始位置:文件尾 | | ios::app | 追加方式写文件 | | ios::trunc | 如果文件存在先删除,再创建 | | ios::binary | 二进制方式 | 注意:文件打开方式可以配合使用,利用|操作符 例如:用二进制方式写文件 `ios::binary | ios:: out`
1.1 文本文件第一种 方法
1.1.1 写ofstream
输出文件流:ofstream(output file stream)可以把数据从程序中写入(输出到)文件 写入数据到文件:程序——>文件 基本操作流程: 1.包含C++文件流头文件 2.用ofstream打开文件 3.向文件写入内容 4.关闭文件 #include <iostream> #include <fstream> //包含文件流头文件 using namespace std; int main(){ //创建ofstream对象 打开文件 ofstream myFile("E:\小猫故事.txt"); //使用<<流出操作符向文件写入内容 myFile<<"在一个阳光明媚的下午"<<endl; myFile<<"有一只可爱的小猫在花园里玩耍"<<endl; myFile<<"它跑的非常快,就像一阵风"<<endl; //关闭文件 myFile.close(); //向文件E输出了hello18 ofstream fout("E:\out.txt"); fout<<"hello"; fout<<2*3+12<<endl; fout.close(); return 0; }
1.1.2 读ifstream
输入文件流:ifstream(input file stream)可以帮助程序从文件读取如数据 读取文件中的数据:程序<——文件 基本操作流程: 1.包含C++文件流头文件 2.用ifstream打开文件 3.读取文件内容 4.关闭文件 #include <iostream> #include <ifstream> //包含文件流头文件 using namespace std; int main(){ //创建ifstream对象 打开文件 ifstream myFile("E:\小猫故事.txt"); //使用>>流入操作符向文件读入内容 int age=0; char name[40]={0}; char s[200]; myfile>>name>>age; //从文件读取 myfile.getline(s,200); cout<<name<<age<<endl; //输出到屏幕 //关闭文件 myFile.close(); return 0; }
1.1.3 判断打开文件is_open
文件流对象名.is_open #include <fstream> ofstream myFile("E:\x.txt"); ifstream myFile("E:\x.txt"); if(文件流对象名.is_open()){ //读写文件 //关闭文件 myFile.close(); }else{ //错误提示(输出到屏幕) cout<<"无法打开文件"<<endl; }
举例
/* 【编程挑战 】编程求100以内所有整数(1,2,3......99,100)的平方根,并将结果保存在文本文件sqrt.txt中。 使用数学库函数sqrt(n)求平方根。要求平方根结果精确到小数点后2位。 【输入】无 【输出】sqrt.txt文件 */ #include <iostream> #include <fstream> #include <cmath> // 使用 sqrt(n)需要这个头文件 #include <iomanip> // 使用 setprecision(n)需要这个头文件 using namespace std; int main() { // 创建ofstream对象,准备写入文件 ofstream fout("E:\sqrt.txt"); // 检查确认文件已经成功打开 if(fout.is_open()) { for(int n=1; n<=100; n++){ // 使用<<操作符向文件写入内容 fout<<n<<"的平方根:"; fout<<fixed<<setprecision(2)<<sqrt(n)<<endl; } // 关闭文件 fout.close(); cout << "已经写入文件啦!" << endl; }else{ cout << "无法打开文件" << endl; } return 0; }
/* 【编程挑战 】编写一个程序,统计 characters2.txt 文件中数字字符的个数。 【输入】从characters2.txt读取输入。不确定characters2.txt有多少行内容。 (每行长度不超过100,行内没有空格) 【输出】数字字符个数:32 */ /*逐个读取字符,直到读完*/ #include <iostream> #include <fstream> // 使用文件流需要这个头文件 #include <cstring> // 使用 strlen()需要这个头文件 using namespace std; int main() { char c; int total=0; // 创建一个输入流,用于从文件读取 ifstream fin("E:\characters2.txt"); // 检查确认文件已经成功打开 if(fin.is_open()) { while(fin >> c){// 逐个读取字符,直到读完 // 检查并统计 if( c >= '0' && c <= '9') { total++; } } // 输出统计结果 cout<<"数字字符个数:"<<total; // 关闭文件 fin.close(); }else{ cout << "无法打开文件" << endl; } return 0; }
1.2 文本文件第二种方法
1.2.1 写ofstream
写文件 1.头文件 #include <fstream> 2.创建流对象 ofstream ofs; 3.打开文件 ofs.open("文件路径",打开方式); | 打开方式 | 解释 | | ----------- | -------------------------- | | ios::in | 为读文件而打开文件 | | ios::out | 为写文件而打开文件 | | ios::ate | 初始位置:文件尾 | | ios::app | 追加方式写文件 | | ios::trunc | 如果文件存在先删除,再创建 | | ios::binary | 二进制方式 | 注意:文件打开方式可以配合使用,利用|操作符 例如:用二进制方式写文件 `ios::binary | ios:: out` 4.写数据 ofs << "写入的数据"; 5.关闭文件 ofs.close(); ----------------------------------------------------------------------- 举例 #include <fstream> void test01() { ofstream ofs; ofs.open("test.txt", ios::out); ofs << "姓名:张三" << endl; ofs << "性别:男" << endl; ofs << "年龄:18" << endl; ofs.close(); } int main() { test01(); system("pause"); return 0; }
1.2.2 读ifstream
读文件步骤如下: 1.包含头文件 #include <fstream> 2.创建流对象 ifstream ifs; 3.打开文件并判断文件是否打开成功 ifs.open("文件路径",打开方式); 4.读数据 四种方式读取 5.关闭文件 ifs.close(); ----------------------------------------------------------------------- 举例 #include <fstream> #include <string> void test01() { ifstream ifs; ifs.open("test.txt", ios::in); if (!ifs.is_open()) { cout << "文件打开失败" << endl; return; } //第一种方式:使用 ifstream 的输入运算符 >> 来读取文件 //这种方式会按照空白字符(如空格、制表符或换行符)来分割字符串 char buf[1024] = { 0 }; while (ifs >> buf) { cout << buf << endl; } //第二种方式:使用 ifstream 的 getline 成员函数来读取文件 //getline 函数会读取直到遇到换行符或达到指定的最大字符数(这里是1024)为止的字符串 //这种方式会保留每行的换行符,并将其打印到控制台 char buf[1024] = { 0 }; while (ifs.getline(buf,sizeof(buf))) //a.getline(输出的对象,大小) { cout << buf << endl; } //第三种方式:使用标准库函数 getline,该函数接受一个 ifstream 对象和一个 string 对象作为参数 //这种方式与第二种方式类似,但它使用 string 来存储读取的每一行,而不是字符数组 //这种方式不会保留每行的换行符 string buf; while (getline(ifs, buf)) //getline(输入流对象,输出的对象) { cout << buf << endl; } //第四种方式:使用 ifstream 的 get 成员函数来逐个字符地读取文件 //这种方式会一直读取文件直到达到文件末尾(EOF) //与第二种和第三种方式相比,这种方式不会按行分割内容,而是直接打印出文件的每一个字符,包括换行符 char c; while ((c = ifs.get()) != EOF) //EOF end of file { cout << c; } ifs.close(); } int main() { test01(); system("pause"); return 0; }
1.3 二进制文件
1.3.1 写ofstream write
#include <fstream> #include <string> class Person { public: char m_Name[64]; int m_Age; }; //二进制文件 写文件 void test01() { //1、包含头文件 //2、创建输出流对象打开文件 ofstream ofs("person.txt", ios::out | ios::binary); //ofs.open("person.txt", ios::out | ios::binary); //3、写文件 Person p = {"张三" , 18}; ofs.write((const char *)&p, sizeof(p)); //4、关闭文件 ofs.close(); } int main() { test01(); system("pause"); return 0; }
1.3.2 读ifstream read
#include <fstream> #include <string> class Person { public: char m_Name[64]; int m_Age; }; void test01() { //1、包含头文件 //2、创建输入流对象打开文件 ifstream ifs("person.txt", ios::in | ios::binary); if (!ifs.is_open()) { cout << "文件打开失败" << endl; } //3、读文件 Person p; ifs.read((char *)&p, sizeof(p)); cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl; //4、关闭文件 ofs.close(); } int main() { test01(); system("pause"); return 0; }