C++ primer知识点总结(基础部分——变量和基本类型六千总结)

一、输入与输出

C++语言并没有定义任何输入输出语句,而提供一个全面的标准库来提供IO机制。

iostream包含两个基础类型:istream和ostream分别表示输入和输出。

cin(istream)为标准输入;cout(ostram)为标准输出;cerr和clog(ostream),cerr用来输出警告和错误信息,clog用来输出程序运行时的一般性信息。

 std::cout<<"ostream:"<<std::endl;//输出
    int i=0;
    std::cout<<"请输入一个数字:";
    std::cin>>i;//输入

cin(>>)和cout(<<)是程序中最常用的。

上面代码段中的endl相当一个换行符 '\n';

上面程序中使用了std::cout而不是cout,前缀std::是指出cout和cin、endl是定义在名为std的命名空间中的,标准库定义的所有名字都在命名空间std中。

全部像这样写太过于烦锁:我们可以使用using namespace std;来声明。

#include "iostream"
using namespace std;
int main(){
    cout<<"ostream:"<<endl;//输出
    int i=0;
    cout<<"请输入一个数字:";
     cin>>i;//输入

}

就可以直接写cout和cin、endl了。

C++算术类型:

它分为两类:整形和浮点型

C++算术类型
类型含义最小尺寸
bool布尔类型未定义
char字符8位
wchar_t宽字符16位
char16_tUnicode字符16位
char32_tUnicode字符32位
short短整形16位
int 整形 16位
long长整形32位
long long长整形64位
float单精度浮点数6位有效数字
double双精度浮点数10位有效数字
long double扩展精度浮点数10位有效数字

上表中的Unicode是用于表示所有自然语言中字符的标准。

布尔类型(bool)的取值只能是真(true)或假(false)。

当我们写程序的时候定义的变量,建议对每一个内置的类型都进行初始化。

带符号类型(signed)和无符号类型(unsigned)

除了布尔型和扩展的字符型之外,其他整形都可以划分为带符号的和不带符号的。带符号的可以表示负数,而不带符号只能表示大于或是等于0的值。

类型 int 、short 、long 、long long 都是带符号的,在它们前面加unsigned就可以成为无符号型,主要记住它们本身是有符号的。其他中无符号整形可以缩写为:unsigned 。

变量声明和定义的关系:

    extern int i;//这是声明i而非定义i
    int j;//这是声明并定义j

变量只能被定义一次在同一个作用域下,但是被声明多次。

建议在定义变量的时候,第一次使用的时候现定义它,不要提前定义它。

C++的标识符由字母、数字、下画线组成,必须以字母或下画线开头。标识符长度没有限制,但是对大小写敏感,命名时不能和C++的关键字一样。

这里也说一下变量名的命名规范:

1.标识符尽量要体现实际含义。

2.变量名一般用小写字母。

3.自己定义的类名一般以大写字母开头。

4.标识符由多个单词组成,则单词间应该有明显区分的标志。

名字的作用域:

作用域:C++语言中的大多数作用域都以花括号分隔,名字的有效区域始于名字的声明语句,以声明语句所在的作用域末端为结束。

#include <iostream>
int main(){
int sum=0;
for(int i=0;i <=10 ; i++){
sum+=i;//等价于sum = sum +i
}
cout<<"sum=  "<<sum<<endl;

return 0;

}

全局作用域(全局变量):就是在代码执行的全过程中都可以访问;局部作用域(局部变量):就像上面代码中的 i 变量,它定义在for循环里,一但出了循环体,就访问不到它了,但是可以又可以在循环体外面,重新定义它。

嵌套作用域:包含着别的作用域的作用域叫外层作用域;被包含的作用域叫做内层作用域。 

建议一下:如果函数有可能用到某个全局变量,就不要再定义一个同名的局部变量。

引用(别名):

引用就是对象起另外一个名字。

int ival =1024;
int &refval = ival;//这个refval就是变量ival的另一个名字,它们两个操作的是同一个空间

当我们作用引用的时候必须初始化它,必须初始化,否则会报错。引用不是一个对象,它只是已经存在的对象的另一个名字。

指针(基础):

指针是指向另外一种类型的复合类型。指针本身是一个对象,指针无须在定义时赋初值。

int *p1,*p2; //p1和p2都是指向int型对象的指针
double dp , *dp1; //dp是一个正常的double型的对象,*dp1是一个指向double型对象的指针

int ival = 42;
int *p = &ival; //p存放变量ival的地址,或者说p是指向变量ival的指针
//指针指向的类型必须和所指向内容的类型相同。下面的是错误的:
int ival1 =43;
char * p1 =&ival1;//它们的类型不匹配

空指针:就是指针没有指向任何对象。

int *p1 = nullptr;//C++11的新标准引入的一种方法
int *p2 = 0;
int *p3 = NULL;
//以上三种都是空指针,它们不指向任何对象

C++程序员最好使用nullptr去初始化空指针,同时避免使用NULL;

利用指针访问对象:如果指针指向了一个对象,则我们可以使用解引用符(*)来访问指针所指向的对象。

int ival =42;
int *p   =&ival;
cout<<   *P;//能过指针P的解引用就可以输出ival的值42;
*P  =0;//可通过指针改变指针所指对象的值
cout<< *p;//输出0

建议初始化所有指针,使用未经初始化的指针是引发运行时错误的一大原因。

当指针做条件时:

任何非0指针对应的条件都是true。

int ival  = 1024;
int *pi   = 0 ;//是一个空指针,它的值为0
int *pi2  = &ival;
if(pi)//条件为false,因为pi的值是0
//...
if(pi2) //pi2指向对象的值不为0,因些条件为true
//...

void* 是一种特殊的指针类型,它可以存放任意对象的地址。我们不能直接操作它所指向的对象,因为不知道它所指向对象的类型是什么,并且它能做的事比较有限。以void*的视角来看内存空间也就仅仅是内存空间,没办法访问内存空间中所存的对象。(这个作为了解就行了)

double obj =3.14 , *pd = &obj;
void * pv =&obj;//void* 能存放任意类型对象的地址;obj可以是任意类型的对象
pv= pd;  //pv可以存放任意类型的指针

复合类型的声明:

int i =1024 , *p =&i , &r =i ;
//i是一个整形的数,p是一个int型的指针,r是一个 int 型引用

int* p; // p是int型的指针,而不是int*型的

int* p1 , p2;
//p1是指向int 型的指针, p2 是int型的变量

指向指针的指针:**表示指向指针的指针,***表示指向指针的指针的指针。 以此类推

int ival =1024;
int *p =&ival;//p指向一个Int型的数
int **pp=&pi;//pp指向一个Int型的指针

指向指针的引用:

引用本身不是一个对象,所以不能定义指向引用的指针。但是指针是对象,所以存在对指针的引用

int i =42;
int *p; //p是一个int型的指针
int *&r = p ;//r是一个对指针p的引用
r= &i;//r引用了一个指针,给r赋值&i就是令p指向i
*r =0;//解引用r得到i,也就是p所指向的对象,将i的值改为0

我们理解r的类型是什么,最简单的方法是从右向左阅读r的定义。当我们遇到比较复杂的时候

const限定符:

当我们想要定义一种变量的值不能被改变,就可以用const限定符加于限制(整形常量)

const int du = 520;
du = 520; //这是错误的,du的值是不能被改变的。

const对象一旦创建它的值就不能被更改,所以const对象必须初始化。

int i= 42;
cin>>i;
const int ci =i; //i的值被拷贝给了ci
int j = ci; //ci 的值被拷贝给了j

可以使用定义好的对象去初始化一个const对象。当我们输入i的值后,拷贝给了ci,那么ci的值就不可以改变了。

在默认情况下,const对象仅在文件内有效,就是只在声明并定义它的那个文件内有效,其他文件无法使用它,我们可以利用extren来实现:

extern const int i=1100;

要在多个文件之间共享const对象,必须在变量的定义之前添加extren关键字。

const的引用(常量引用):

可以把引用绑定到const对象上(对常量的引用)。与普通引用不同,对常量的引用不能被修改它所绑定的对象:

const int ci = 1024;
const int &ri =ci;//正确的:引用的对象是常量
ri = 42;  // 错误:ri是对常量的引用
int &r2= ci; //不能让一个非常量引用指向一个常量对象

引用的类型必须和所引用对象的类型一致。但是有两个例外:

就是在初始化常量引用时允许用任意表达式作为初始值,只要这个表达式的结果能转换成引用的类型就可以。
double dval = 3.14;
const int &ri1 =dval;
//上面的代码编译器会改变成下面这样:
const int temp = dval;
const int &ri1 =temp;//这样ri1绑定了一个临时量

如果上面的代码中ri1不是一个常量时,就是把引用绑定到临时量上,这种行为在C++中会归为非法,下面的代码是错误的,会报错,不允许像这样写!!!


double dval =3.14;
int &ri=dval;

对const的引用可能引用一个并非const的对象:

//对const的引用可能是一个非const的对象
int i = 42;
int &fi= i; //把引用fi绑定对象i
const int &rh=i;// rh也绑定对象i,但是不允许通过rh去改变i的值
i=0;//i并非一个常量,所以可以更改它的值
rh=0; //错误,rh是一个常量引用,不能直接改变它的值
cout<<"i=   "<<i<<endl;
cout<<"rh=  "<<rh<<endl;

指针和const:

要想存放常量对象的地址,只能使用指向常量的指针;

const double pi = 3.14;
double *ptr = &pi;//错误,因为Ptr是一个普通的指针
const double *cptr = &pi; //正确的,它们的类型相同
*cptr = 42;//错误,不能给*cptr赋值

允许令一个指向常量的指针指向一个非常量对象。和常量引用一样,指向常量的指针也没有规定其所指的对象必须是一个常量。指向常量的指针仅仅是要求不能通过这个指针去改变对象的值,而没有规定那个对象的值不能通过其他途径改变。

const 指针(常量指针):

指针是一个对象,所以允许将一个指针本身定义为常量。常量指针也必须初始化。一旦初始化后,它的值(它存放的地址)就不能再更改了。

把*放在const关键字之前用以说明指针是一个常量(不变是的指针本身的值而不是指向的那个值)。

int nub= 0;
int *const cur = & nub;//cur将会一直指向nub,不会改变
cosnt double pi = 3.124;
const double *const pip =&pi;//pip是一个指向常量对象的常量指针

遇到复杂的定义用我们前面讲过的方法:从右向左阅读。

上面代码中的cur为例:cur旁边是const(从右向左)说明cur本身是一个常量,然后下一个符号是*,表示是一个指针,最后综合得到cur是一个常量指针。(如果看到这里,请利用这种方法说出pip的类型打在评论区)

顶层const:

顶层const:表示指针本身是个常量。

底层const:表示指针所指的对象是一个常量。

指针可以是顶层const的同时也是底层const。

int i  = 0;
int *const p1 =&i; //不能改变P1的值,这是一个顶层const 
const int ci = 42; //不能改变ci的值,这是一个顶层const
const int *p2 =&ci;//允许改变p2的值,这是一个底层const
const int *const p3 = p2; //靠右的const是顶层const ,靠左的是底层const 
const int &r =ci ; //用于声明引用的const都是底层const

当执行对象的拷贝操作时,常量是顶层const还是底层const区别明显,但是顶层const不受影响:

i =ci ;//正确的:拷贝ci的值,ci是一个顶层const,这个作用无影响
p2 = p3;//正确的:p2和p3指向的对象类型相同,p3顶层const的部分不影响。
//执行拷贝操作并不会改变拷贝对象的值,拷入和拷出的对象是否是常量都没有什么影响。

而底层const的限制不能忽视:

当执行拷贝操作时,拷贝的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。一般来说:非常量可以转换成常量,反过来则不行:

int *P = p3;// 错误:p3有底层const的定义,但是P没有
p2 = p3;//正确:p2 和p3都是底层const
p2 = &i; //正确:int*能够转换成const int*
int &r =ci;//错误:普通的int&不能绑定到Int常量上
const int &r2= i;//正确:const int&可以绑定到一个普通Int上

上面的代码中,p3是顶层const同时也是底层const,拷贝p3的时候可以不在乎它是一个顶层const,但是必须清楚它指向的对象是一个常量(要注意它的底层const)。p3的值可以赋给p2,是因为它们两个都具有底层const的性质,虽然p3同时也具有顶层const的性质,就这次赋值不会有什么影响。


 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

syhk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值