从第一个CPP开始写起:
“hello,world”
#include<iostream>
using namespace std;//使用所有命名空间
int main()
{
cout<<"Hello World"<<endl;
return 0;
}
c++的具体结构
简单来说,一个C++程序就是由若干头文件和函数组成。
#include <iostream>
就是一条预处理命令, 它的作用是通知C++编译系统在对C++程序进行正式编译之前需做一些预处理工作,导入头文件下的函数,与类。
函数就是实现代码逻辑的一个小的单元。
必不可少之主函数
一个C++程序有且只有一个主函数,即main函数。
C++程序就是执行主函数里的代码,也可以说这个主函数就是C++中的唯一入口。
而main前面的int就是主函数的类型.
cout 是格式输出函数,这里就记住它的功能就是在屏幕上输出指定的信息
return是函数的返回值,根据函数类型的不同,返回的值也是不同的。
endl是一个函数模板,这里知道是用来换行的即可。
(注意:C++程序一定是从主函数开始执行的)
良好习惯之规范
一个说明或一个语句占一行,例如:包含头文件、一个可执行语句结束都需要换行。
函数体内的语句要有明显缩进,通常以按一下Tab键为一个缩进。
括号要成对写,如果需要删除的话也要成对删除。
当一句可执行语句结束的时候末尾需要有分号。
代码中所有符号均为英文半角符号。
程序解释——注释
注释是写给程序员看的,不是写给电脑看的。
C++注释方法有两种:
多行注释: /* 注释内容 */
单行注释: //注释一行
有名有姓的C(标识符)
C++规定,标识符可以是字母(A~Z,a~z)、数字(0~9)、下划线_组成的字符串,并且第一个字符必须是字母或下划线。在使用标识符时还有注意以下几点:
标识符的长度最好不要超过8位,因为在某些版本的C中规定标识符前8位有效,当两个标识符前8位相同时,则被认为是同一个标识符。
标识符是严格区分大小写的。例如Imooc和imooc 是两个不同的标识符。
标识符最好选择有意义的英文单词组成做到"见名知意",不要使用中文。
标识符不能是C++的关键字。
变量命名规则:传送门
变量及赋值
变量就是可以变化的量,而每个变量都会有一个名字(标识符)。变量占据内存中一定的存储单元。使用变量之前必须先定义变量,要区分变量名和变量值是两个不同的概念。
变量定义的一般形式为:数据类型 变量名;
多个类型相同的变量:数据类型 变量名, 变量名, 变量名…;
注意:在定义中不允许连续赋值,如int a=b=c=5;是不合法的。
变量的赋值分为两种方式:
先声明再赋值
声明的同时赋值
基本数据类型
C++中,数据类型可分为:
基本数据类型
构造数据类型
指针类型
空类型四大类
数据类型分类
最常用的整型, 实型与字符型(char,int,float,double):
整型数据是指不带小数的数字(int,short int,long int, unsigned int, unsigned short int,unsigned long int):
自动类型转换
数据类型存在自动转换的情况.
自动转换发生在不同数据类型运算时,在编译的时候自动完成。
char类型数据转换为int类型数据遵循ASCII码中的对应值.
字节小的可以向字节大的自动转换,但字节大的不能向字节小的自动转换
char可以转换为int,int可以转换为double,char可以转换为double。但是不可以反向。
强制类型转换
强制类型转换是通过定义类型转换运算来实现的。其一般形式为:
(数据类型) (表达式)
其作用是把表达式的运算结果强制转换成类型说明符所表示的类型
在使用强制转换时应注意以下问题:
数据类型和表达式都必须加括号, 如把(int)(x/2+y)写成(int)x/2+y则成了把x转换成int型之后再除2再与y相加了。
转换后不会改变原数据的类型及变量值,只在本次运算中临时性转换。
强制转换后的运算结果不遵循四舍五入原则。
数据类型简单的列举
char :1个字节
char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 4个字节
long long: 8个字节
unsigned long: 4个字节
64位编译器:
char :1个字节
char*(即指针变量): 8个字节
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 8个字节
long long: 8个字节
unsigned long: 8个字节
常用库函数
(1)数学函数
平方根——sqrt
绝对值——fabs
乘幂——第一个参数作为底,第二个是指数double pow(double, double)
实数的余数——两个参数分别是被除数和除数double fmod(double, double)
(2)其他常用函数
ceil(x)求出不小于x的最小整数(返回与这个整数对应的double值)
floor(x)求出不大于x的最大整数(返回与这个整数对应的double值)
modf(x, doubleip)把x分解为小数部分和整数部分,小数部分作为函数返回值,整数部分通过指针ip返回。
Ps:输出小数cout<<fixed<<setprecision(2)<<?
ASCII码
getchar()读入一个ASCII码
putchar()输出一个ASCII码
#include<iostream>
using namespace std;
int main()
{
char c;
int a;
cin>>c;
a=(int)c;
c=(int)a;
return 0;
}
#define 宏常量
定义:#define 标识符 字符串
1.宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。
2.宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。
3.宏定义其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。
简而言之,#define可以理解为起名函数,#define number 999 number就被简单的定义为999。
目前听说但未遇到的用法:
1.有参宏定义
2.宏定义中的特殊操作符
3.宏定义中的多行定义
4.防止重复包含头文件
条件分支结构
1.if分支语句
程序结构 **//第一种**
if(表达式) 分支语句;
else 分支语句; //可以省略
分支后语句
程序结构 **//第二种**
if(表达式)
{
分支语句;
}
分支后语句
程序结构 **//第三种**
if(表达式)
{
分支语句;
}
else
{
分支语句;
}
分支后语句
程序结构 **//第四种**
if(表达式)
{
分支语句;
}
else if(表达式)
{
分支语句;
}
......
else
{
分支语句;
}
分支后语句
2.switch语句
switch ( 条件表达式)
{
case 表达式:
break;
case 表达式:
break;
......
default:
break;
}
通过以上学习C语言(c++)我们能够解决什么问题?
1.从整体上说,可以应对简单的顺学结构、条件分支结构。
2.对于小的方面,
(1)有关ASCII码的计算
(2)浮点数的输入输出
(3)驱魔,取余,取整
(4)简单的数学运算题
(5)倒序输出
(6)中小学的应用题
…
3.生活方面,
(1)解决生活中简单的实际问题,将生活中的问题通过程序,制定出对于一类事情解决方案,可以起到“智慧偷懒”的效果。对于邮费计算,吃饭付款等等各类事情都可以通过写程序得到最优解。
for循环
for(表达式1;表达式2;表达式3)
{
break; //用于跳出当前循环体,结束循环。
continue; //跳过当前循环体continue后面的代码,继续执行下一个循环
return 0; //跳出该函数
}
程序执行顺序,先执行表达式1,验证表达式2是否为真,执行循环体语句,执行表达式3,再验证表达式2是否为真,若为真继续执行上述操作,直至表达式2不成立,跳出循环体,执行后续语句。
特殊用法
for()中可以不加语句也可以添加部分语句,语句不存在时跳过执行,参考while循环。
参考例题
描述
孙老师讲授的《计算概论》这门课期中考试刚刚结束,他想知道考试中取得的最高分数。因为人数比较多,他觉得这件事情交给计算机来做比较方便。你能帮孙老师解决这个问题吗?输入
输入两行,第一行为整数n(1 <= n <
100),表示参加这次考试的人数.第二行是这n个学生的成绩,相邻两个数之间用单个空格隔开。所有成绩均为0到100之间的整数。输出
输出一个整数,即最高的成绩。
#include<iostream>
#include<cmath>
#include<iomanip>
using namespace std;
int main()
{
int i,a=0,b=0;
int score[100];
cin>>a;
for(i=0;i<a;i++)
{
cin>>score[i];
b=max(b,score[i]);
}
cout<<b;
return 0;
}
while循环-适合不确定循环次数时使用
while循环
while (条件表达)
{
break; //用于跳出当前循环体,结束循环。
continue; //跳过当前循环体continue后面的代码,继续执行下一个循环
return 0; //跳出该函数
}
运行顺序:首先检验条件语句是否为真若为真,执行循环体,直至条件不成立,跳出循环。
参考例题 金币 描述
国王将金币作为工资,发放给忠诚的骑士。第一天,骑士收到一枚金币;之后两天(第二天和第三天)里,每天收到两枚金币;之后三天(第四、五、六天)里,每天收到三枚金币;之后四天(第七、八、九、十天)里,每天收到四枚金币……这种工资发放模式会一直这样延续下去:当连续N天每天收到N枚金币后,骑士会在之后的连续N+1天里,每天收到N+1枚金币(N为任意正整数)。
你需要编写一个程序,确定从第一天开始的给定天数内,骑士一共获得了多少金币。 输入 一个整数(范围1到10000),表示天数。 输出
骑士获得的金币数 样例输入 6 样例输出 14
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int a,i=1,sum=0;
cin>>a;
while (a>0)
{
a=a-i;
sum=sum+i*i;
if(a<0) sum=sum+a*i;
i++;
}
cout<<sum;
return 0;
}
do-while()循环
do
{
//循环体
}while()
执行
顺序大体与while循环一样,但程序至少执行一遍。 将上述程序改写为do-while()循环
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int a,i=1,sum=0;
cin>>a;
do
{
a=a-i;
sum=sum+i*i;
if(a<0) sum=sum+a*i;
i++;
}while(a>0)
cout<<sum;
return 0;
}
循环体可以用来解决的问题
从上述题目中可以看到
如果程序中存在需要连续反复执行多次的操作,就可以采用。
另外针对操作次数已经,建议使用计数循环方式。
如果操作次数未知,要求达到指定目标才停止,就采用条件循环。
很多函数大都是循环体。
字符串与数组
数组的操作
1°memcpy函数(头文件<cstring)
数组不能直接复制,可利用memcpy函数
void *memcpy(void *dest, void *src, unsigned int count);
memcpy 函数用于 把资源内存(src所指向的内存区域) 拷贝到目标内存(dest所指向的内存区域);一个size变量控制拷贝的字节数;
使用方式memcpy(b,a,sizeof(int)*k) 从a中赋值k个元素到b数组。
sizeof(int)k表示计算int型所占字节数,然后再乘以k。
类比sizeof(intk),表示计算指向整型的指针变量k所占的字节数。
再浅显讨论sizeof的作用
sizeof(int)*k之所以用sizeof(int)*k而不是用k,因为sizeof(int)*k返回的是字节数,因为数组是int 型的sizeof计算每个元素的字节长度,在乘以k既k个元素的字节,因为memcyp需要知道拷贝内存的字节数。所以拷贝是从开头开始计算,即k个元素是从a[0]开始计算。由此可以推出将a中元素全部拷贝到b数组中,memcpy(b,a,sizeof(a))。
2°memset函数(头文件<cstring)
void *memset(void *s , int ch , size_t n ) 在一段内存块中填充某一个给定的值,常用于较大的对结构体和数组的清零操作。
memset(结构体/数组名 , "用于替换的字符“ , 前n个字符 );
用法可以参考memcpy,也要用sizeof来计算字节。
总结内存复制需要计算字节。
字符串操作String
用法跟char []没有太大区别,但是功能更加强大
strcpy(p, p1) 复制字符串
strncpy(p, p1, n) 复制指定长度字符串
strcat(p, p1) 附加字符串
strncat(p, p1, n) 附加指定长度字符串
strlen§ 取字符串长度
strcmp(p, p1) 比较字符串
strcasecmp忽略大小写比较字符串
strncmp(p, p1, n) 比较指定长度字符串
strchr(p, c) 在字符串中查找指定字符
strrchr(p, c) 在字符串中反向查找
strstr(p, p1) 查找字符串
strlwr§将大写字母全部换为小写字母
strupr§将小写字母全部换为大写字母
相对于字符型数组,字符串还可以有以下操作
s.empty(); // s为空串 返回true
s.size(); // 返回s中字符个数 类型应为:string::size_type
s[n]; // 从0开始相当于下标访问
s1+s2; // 把s1和s2连接成新串 返回新串
s1=s2; // 把s1替换为s2的副本
v1==v2; // 比较,相等返回true
!=, <, <=, >, >=
函数
概念:组成C语言源程序的基本单位,完成特定功能的代码段.
例如main()为主函数:程序入口
函数定义到使用分三步:
1.声明
2.定义函数
3.调用函数。
一、函数的声明:
在调用函数之前,进行该函数的声明 ,由于程序是由上到下执行,编译器不知道我们是否已经定义了某个函数,为了防止编译器编译的时候报错(函数调用)所以,要告诉编译器,我已经定义了哪些函数。
二、函数的定义:
返回值类型 函数名(形式参数类型 参数名1,……)
{
函数体;
//return (返回值)
}
返回值类型有两种:
有参无返回值:void test(int x,float y){ }
有参有返回值: int max(int x,int y){ return x>y?x:y; }
函数的调用
定义:函数名(实参列表);
1)形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。
2)实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值 。
3)实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配的错误。
实参一定是确定值 不需要类型!!!
1.函数的参数
1)形参和实参
形参:在定义函数的时候,函数名后面小括号中的参数 , 格式: 数据类型 变量 如:int x;
形参的作用域:只能在本函数中使用
实参:调用函数的时候传递的参数
2)参数的传递的过程
实参的值拷贝一份放到函数形参中
3)函数传参有三种传参方式:传值、传址、传引用
①按值传递
ⅰ形参和实参各占一个独立的存储空间。
ⅱ形参的存储空间是函数被调用时才分配的,调用开始,系统为形参开辟一个临时的存储区,然后将各实参传递给形参,这是形参就得到了实参的值。
②地址传递
地址传递与值传递的不同在于,它把实参的存储地址传送给形参,使得形参指针和实参指针指向同一块地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。
③引用传递
引用传递是以引用为参数,则既可以使得对形参的任何操作都能改变相应数据,又使函数调用方便。引用传递是在形参调用前加入引用运算符“&”。引用为实参的别名,和实参是同一个变量,则他们的值也相同,该引用改变则它的实参也改变。
2.函数的返回值
概念:执行函数体中的程序段,最后获取的值并返回给主调函数,函数的返回值只能通过return 关键字进行返回
格式:return 表达式;/ return (表达式);
返回值类型要与返回值相同。
是否要定义形参看是否有未知内容参与运算,调用时实参必须对应.参数传递的是值。
函数中可以有多个return ,但是只有一个起作用,因为函数会结束后会带回一个值。
函数调用和返回
函数调用会使程序的控制权传递给被调函数而当前活动会被挂起。
当前函数执行完成后主函数从调用语句之后的语句恢复执行。
函数在执行完函数体的最后一条语句或或遇到return语句时返回。
返回类型和return语句
return 语句形式
return;
return表达式;
非void函数必须返回一个与声明类型匹配的值否则会引起编译错误。
返回值 默认情况下,函数的返回值是按值传递的,得到控制权的函数将接受return语句中指定的表达式值得副本。
返回引用(我觉得特别重要)
函数声明为返回引用,则不需要对return语句中的表达式进行复制,而是返回对象本身。
函数返回引用仅是它所指向对象的一个别名。
//找出s1和s2中比较短的一个并返回其引用
const string& shorter(const string& s1, const string& s2)
{
return (s1.size() <= s2.size()) ? s1 : s2;
}
//函数返回结果时不会真正复制对象,返回的就是s1或s2本身。
string a=hello;
string b=word;
shorter(a,b)=“Hello”;//返回值为引用。
cout<<a<<’ '<<b;//Hello word;
注:对引用返回值的修改会改变实际返回的对象,为了避免这种情况,可以将返回值声明称const。
不能返回自动局部对象的指针或引用:函数执行结束后,函数占用的栈存储空间被释放,原本位于这段存储空间中的局部对象和临时变量都被释放,返回的局部对象引用或指针指向不再有效的内存区域
重载函数
如果同一个作用域内的几个函数名字相同但形参列表不同,则他们是重载函数
形参列表不同的概念:
1.形参数量不同
2.形参类型不同
3.常指针与指针不同,常引用与引用不同。
调用函数时如果存在多个重载函数,编译器将根据函数调用中指定的实参进行选择。
存储类别 static静态存储
static对象在控制流程第一次到达其定义点时被初始化,如果没有提供初始值就被自动初始化为0;
在函数的后续调用中,初始化语句被跳过
静态对象的值在函数被多次调用之间保持有效,生存期会延续到整个程序结束但他的作用于仍然是局部的,因此需要在同一函数的两次调用之间保留某些数据时可以使用局部static对象。
素数的判断
1定义法
除了1与自身外无其他因数。
int main()
{
int a;
char b='y';
cin>>a;
for(int i=2;i<a;i++)
{
if(a%i==0&&a!=i)
{
b='N';
break;
}
}
if(b=='N') cout<<"不是";
else cout<<"是";
return 0;
}
2.对定义法的改进
若a不是素数则在2到sqrt(a)的范围内一定存在其因数。所以
int main()
{
int a;
char b='y';
cin>>a;
for(int i=2;i<=sqrt(a);i++) //等号必须存在
{
if(a%i==0)
{
b='N';
break;
}
}
if(b=='N') cout<<"不是";
else cout<<"是";
return 0;
}
最大公约数最小公倍数
a,b最小公倍数=a*b/最大公约数
最大公约数用辗转相除法
int main()
{
int a,b;
int mid;
int x,y;
cin>>a>>b;
x=a,y=b;
while(b>0)
{
mid=a%b;
a=b;
b=mid;
}
cout<<a<<x*y/a<<endl;
}
指针的基本概念
1.每个变量都被存放在某个内存地址(以字节为单位)开始的若干个字节中。若干个字节(根据类型确定字节)
2.指针,也称作“指针变量“,大小为4个字节(或8个字节)的变量,其内容代表一个内存地址。
3.通过指针能够对任意地址的内存区域进行读写。
4.将内存比作房间,则指针内存储的是房间号。
指针的定义
类型名*指针变量名
int *p; //p是一个指针变量,变量p类型是int *
char * q; //q是一个指针变量,变量q的类型是char *
double *r; //r是一个指针变量,变量r的类型是 double *
void *s; //s是一个指针变量,变量s无类型。
指针的内容
int * w=(int *) 40000;
w的内容,w是指向的地址40000。*w的内容,*w是w地址40000起始的若干字节(sizeof(int))的所储存的内容。
通过指针访问指向的内存空间
int*p=int *40000;//指向向地址40000;
*p =123; 将123存入p所指向的地址后的若干字节(sizeof(int))的内存空间。
int n=*p,将p所指向的地址后的若干字节(sizeof(int))的内存空间赋值给 n;
补充
1. 上述*和&的区别
(1)*p是指指针p指向地址的那个变量,例如int a=5;int p=a;那么p的值是a的地址,也就是指针p指向a,p则等于a的值,即p=5。
(2)&,则是引用,比如说有定义int a=5;再定义int b=&a;那么这里的b则引用a的值,即b=5,而再给b赋值:b=10,a的值也会变为10。
(3)函数定义里的参数和&的区别:
int x=0;
int *w=x;
定义函数: int a1(int a);
{
a=5;
return 1;
}
定义函数: int a2(int &a);
{
a=5;
return 1;
}
定义函数: int a3(int *a);
{
a=5;
return 1;
}
(1) 调用 int a1(x)后x的值还是等于0;int a其中a为形参,x为实参,函数调用的过程实际上是一种传参过程。将x的值赋给a后,函数操作与x无关,即a=x;a=5;
(2)调用 int a2(x)后,x的值等于5;因为这里a引用了x的值。
(3)调用 int a3(x)后,x的值也得等于5;此时不再是传参,而是传址,相当于w=a,w与a所指向地址相同。改变*a所指内容就改变 * w所指向的内容
指针的赋值(用法)
指针的用法
char a=‘A’;
char * p=&a;
char *m;
m=p;
int *t;
t=(int) p;类型不匹配,编译出错,但可以使用强制类型转换。
cout<<*p;
可以使用char * a=6161(地址)但容易运行出现问题,因为地址不明确,不知道是本程序的内存地址,还是系统内存地址,或者某进程的地址。一般使用方式如上述。
指针的运算
- 两个同类型的指针变量,可以比较大小
地址p1<地址p2,->p1< p2 值为真。
地址p1=地址p2,->p1== p2 值为真
地址p1>地址p2,->p1 > p2 值为真 - 两个同类型的指针变量,可以相减
两个T * 类型的指针p1和p2
p1 – p2 = ( 地址p1 – 地址p2 ) / sizeof(T)
例:int * p1, * p2;
若p1 指向地址100,p2 指向地址60, 则
p1 – p2 = (1000 – 600)/sizeof(int) = (100 – 60)/4 = 10
3)指针变量加减一个整数的结果仍是指针
int p;
int n=a(a为某常数);
p+n:地址p+asieof(int)
则类型为char或其他时,n+p、n-p时, (n+p)、(n-p)时都应该明白其含义。
4)自增运算自减运算
int *p=n;
p++,++p;表达n=n+sizeof(int)
$ ¥ $ ¥指针运算可以使用下标运算符[ ]
int *p;
int n;
p[n]等价于 *[p+n]这不就是数组吗?
例题
访问int型变量a前面一字节
int a;
char *p=(char*)&a;
--p;
*p='M';
cout<<*p;
空指针
地址0不能访问。指向地址0的指针就是空指针
可以用“NULL”关键字对任何类型的指针进行赋值。NULL实际上
就是整数0,值为NULL的指针就是空指针:
int * pn = NULL; char * pc = NULL; int * p2 = 0;
指针可以作为条件表达式使用。如果指针的值为NULL,则相当于为
假,值不为NULL,就相当于为真
if§=== if(p!=NULL) <----------> ensp if(!p)=== if( p==NULL )
常量表达式和constexpr与const
常量表达式概念:值不会改变并且在编译过程中就能计算出结果的表达式。
ps:constexpr int a=20;
constexpr int b=20+a;
constexpr必须用常量表达式初始化,也就是说必须在编译过程就能计算出结果(若要用函数作为constexpr的初始值那么该函数应该是constexpr类型的函数)。
constexpr函数必须满足下述限制:
函数返回值不能是void类型 函数体不能声明变量或定义新的类型
函数体只能包含声明、null语句或者一条return语句
在形参实参结合后,return语句中的表达式为常量表达式
const 不要求在编译过程中就能计算出结果 (强调运行时不可改变) 大多数情况下并没有区别。
const限定指针和引用。
指向const对象的指针 const type 指针
const int a=1; //const地址无法赋给非const指针所以应该定义一个指向const的指针
const int * b=&a; //指向常量的指针,而非常指针。
const int c=2;
b=&c; //指向对象可以改变,指向对象内容不能改变。
int d=10;
b=&d; //也可以将一个非const地址赋给 指向const的指针 但是不能通过该指针改变该变量的内容。
*b=15;//错误
指向非const对象地const指针(常指针 ) type const 指针
int num =10;
int * const poi =&num;// type const 指针 指针的值初始化后不能改变指向固定的单元(只能指一次)
*poi=99;//const限定的是poi的值;可以对指向内容修改,但不可以对指针指向对象修改。
int member=10;
poi=&member;//错误
指向const对象的const指针
/*const type const 指针(第一个const限定int表示指针指向的单元是常量,
第二个const限定‘指针’表示指针的值也是常量,因此该指针所在的内存值不允许改变它所指向内存的值也不能改变)*/
int demo=10;
const int *const pi=&demo;对象及内容都不能改变
const限定引用,与const指针相似
const int a=1;
int 7b=a;// const type &引用名(不能用非const引用指向const对象)
const int& b=a;//right
b=10;//错误,const引用不能用来修改他所绑定的对象。
a=10;//const引用仅对自己可参与的操作进行了限定对所指向的对象本身是不是常量未作限定。因为指向的对象也可能不是const,所以允许通过其他途径改变它的值。
const int &c=a*10;//可以用任意表达式初始化const引用,只要表达式的结果能转换成引用的类型即可。
auto和decltype
由auto声明变量的类型由编译器去自动分析表达式的类型,推断出变量的实际类型(很好用)
auto x=5
auto x=1,c=3.14;//一个int 一个double错!当auto后定义多个变量时类型要一致
auto poi=Set.begin()//很好用,省了set<type>::iterator
decltype 可以通过表达式推断出定义的变量的类型但是不用该表达式初始化。
int i = 4;
decltype(i) a; //推导结果为int。a的类型为int。
引用
左值与右值
区别 左值 右值
赋值表达式 出现在赋值号左边 在赋值号右边的
地址与名字 可以取地址的有名字 不能取地址的没有名字
生成的表达式 返回左值引用的函数 赋值 下标 解引用和前缀自增自减运算符 返回非引用类型的函数 连同算术、关系、位运算、后缀自增自减运算符、字面值常量、要求转换的表达式。
左值引用 (定义 类型 &引用名=目标变量名)
int a=100;
int &b=a;/*&是标识符(引用必须被初始化并且初始化完成之后引用将会和初始值对象一直绑定在一起)。*/
b=10;//又称别名,它可以作为对象的另一个名字,通过引用可以间接的操纵对象,对引用的操作和对对象的直接操作一样。
int *poi=&a;
int *pi=&b;//此时a==b
/* 声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。故:对引用求地址,就是对目标变量求地址。引用本身不是对象所以不能定义引用的引用。*/
右值引用(必须要绑定到右值的引用)定义 类型 &&右值引用变量=右值表达式;
int &&a=10;//正确
int &&b=10*5;//正确10*5是右值
int &&c=a;//a的类型是int是左值
调用标准库中定义的函数std::move() move()函数返回给定对象的右值引用, 可以显式的将一个左值转换为对应的右值引用类型。
int &&c=move(a);//但是过程是销毁a,a的右值由c接管。此后不能使用a,但可以给它赋新右值。
文件的输入输出
文件的读写
如果想以输入方式打开,就用ifstream来定义;
如果想以输出方式打开,就用ofstream来定义;
如果想以输入/输出方式来打开,就用fstream来定义
ofstream demo("demotest.txt"); 可以分成两步
demo<<"demoout";
demo.close(); //完成操作后要关闭文件
ifstream demo("test.txt");
char dchar;
demo>>dchar;//从文件中读取一个字符
char dworld[80];
demo>>dworld;//从文件中读取一个单词
demo.getline(dworld,80);//从文件中读取一行
string line;
getline(demo,line);//读取一行转换成字符串
fin.close();
区别
ifstream ifile;
ofstream ofile;
ofile<<"I Love You";//向文件写入字符串"I Love You"
int i;
ifile>>i;//从文件输入一个整数值。
字符串流stringstream是 C++ 提供的一个字符串流(stream),和iostream、fstream有类似的操作方式
istringstream 从string中读取数据 定义 istringstream is(strs);
ostringstream 向string对象写入格式化的内容。
stringstream 即可以读取也可以写入。
stringstream ss;
ss << "hello ";
ss << "world!"; // 对stringstream而言,operator<< 是一直往字符串流中写字符,而不是覆盖之前输入的字符
cout << ss.str() <<endl;
/*str()函数创建的是一个临时的string对象这个string对象在函数str()语句结束就会被销毁,一般使用时应先声明一个string对象s,将str()赋值给sconst string s=ss.str();或者const string& s=ss.str();这样就“延长了临时变量ss.str()的生命周期”,使得ss.str()生命结束时刻和s一样*/
与容器一样流不会降低自己空间,即使用了ss.clear()😭 清空操作如下 😦
ss.clear();//清空流
ss.str("");
六.range -for
for(int ele :{2,3,44,5,6,77})
{
cout<<ele<<endl;
}
int arr []={1,2,3,4}
for(int ele :arr)
{
cout<<ele<<endl;
}
vector<int > demo={1,2,3,4};//结合auto关键字可以方便地遍历STL容器
for(auto ele:demo)
{
cout<<ele<<endl<<;
}
for(auto& ele:demo) 如果需要修改其中元素可以引用;
{
ele+=2;
}
切记!!!!! 不能在遍历容器时,改变容器的Size,即增删元素。
转载来源: https://blog.csdn.net/weixin_43627118/article/details/106363301