【c++基础】2.数据类型、类型转换、变量

变量是存储空间的抽象,而数据类型是变量的一个属性,定义了该变量的存储空间大小,存储结构(主要针对用户自定义类型)以及可以在该变量上进行的操作。


【一】数据类型


1.内置数据类型简介

c++内置数据类型包括分为算术类型和空类型,空类型不对应任何具体的值,常用于一些特殊场合,算术类型包括整型和浮点型.
c++定义的算术类型有多种,如最基本的(整型)int、short、long、long long、char、bool,(浮点型)double、float。
在此基础上的扩展类型包括signed、unsigned修饰的有/无符号数如unsigned int表示无符号整型,还有wchar_t表示宽字符型等。
既然是数据类型,那么能对它的操作自然是进行算术运算咯,如:加减乘数,与或非等,不过也有特殊的操作,比如下面将用到的sizeof(),这个操作是取数据类型长度,这也是一个运算符,不是函数。

内置类型的长度(即大小)与机器相关,如int型在不同机器上可能占2或4个字节,其中最基本的是char型,一个char型和一个机器字节大小相同。但是c++规定:
sizeof(int)>=sizeof(short),
sizeof(long)>=sizeof(int),
sizeof(long long)>=sizeof(long)
想要知道你的机器某个数据类型所占字节数,可以用sizeof来测试:

#include <iostream> 
using namespace std;
int main(){
    cout<<"sizeof(int)="<<sizeof(int)<<endl;
    cout<<"sizeof(short)="<<sizeof(short)<<endl;
    cout<<"sizeof(double)="<<sizeof(double)<<endl;
    cout<<"sizeof(float)="<<sizeof(float)<<endl;
    cout<<"sizeof(char)="<<sizeof(char)<<endl;
    cout<<"sizeof(wchar_t)="<<sizeof(wchar_t)<<endl;
    cout<<"sizeof(bool)="<<sizeof(bool)<<endl;
    return 0;
}

输出如下:

sizeof(int)=4
sizeof(short)=2
sizeof(double)=8
sizeof(float)=4
sizeof(char)=1
sizeof(wchar_t)=2
sizeof(bool)=1

2.自定义数据类型简介

除了内置数据类型,用户可以按自身需要定义数据类型,用户自定义数据类型包括:数组、union(联合)、enum(枚举)、struct(结构)、class(类)等。

union

联合类型在实际应用中很少使用,它是一种特殊的数据类型,一个联合中可以定义多个其他数据类型(包括自定义类型)和函数,在定义union变量时,可以向其中装入任何数据类型,联合中所定义的这些数据类型共享内存,所以联合的长度等于内部定义的数据类型中最大的长度。可以使用
下面用一个例子说明union数据类型的定义、union变量的定义和使用方法:

#include <iostream> 
using namespace std;

//union定义
union my_union{
    int a;
    double b;
};
int main(){
    union my_union test;
    cout<<"sizeof(test)="<<sizeof(test)<<endl;
    test.a=1; //通过“.”访问联合成员
    cout<<"为b赋值前:test.a="<<test.a<<"\ttest.b="<<test.b<<endl;
    test.b=0.5;
    cout<<"为b赋值后:test.a="<<test.a<<"\ttest.b="<<test.b<<endl;
return 0;
}

输出结果为:

sizeof(test)=8
为b赋值前:test.a=1 test.b=4.94066e-324
为b赋值后:test.a=0 test.b=0.5

这个结果说明,当第二次对union赋值时,上一次的旧值将被冲刷掉。

struct

struct和union有很多类似之处,只是struct的大小等于内部成员大小之和(注意字节对齐问题),其定义,成员访问方法和union一样,你只需将关键字改为struct即可,如下:

#include <iostream> 
using namespace std;

struct my_struct{
    int a;
    double b;
};
int main(){
    struct my_struct test;
    cout<<"sizeof(int)="<<sizeof(int)<<endl;
    cout<<"sizeof(test)="<<sizeof(test)<<endl;
    test.a=1;
    cout<<"为b赋值前:test.a="<<test.a<<endl;
    test.b=0.5;
    cout<<"为b赋值后:test.a="<<test.a<<"\ttest.b="<<test.b<<endl;
return 0;
}

输出:

sizeof(int)=4
sizeof(test)=16
为b赋值前:test.a=1
为b赋值后:test.a=1 test.b=0.5

咦,奇怪,sizeof(int)=4,为什么sizeof(test)会是16呢?这就是字节对齐造成的,关于字节对齐,可以参考博文: c/c++ struct内存对齐

enum

枚举类型是一种派生数据类型,是一系列枚举常量的集合,即enum中定义的都是常量。这些常量可以在定义的时候为其赋初值,默认为从0开始,后面的依次加1。
在实际应用中经常会遇到这样的问题,一个变量,它只有几种可能的取值,比如一周有七天,我们定义一个week变量来表示,取值可以为1,2,3,4,5,6,7,你当然可以将它定义为int,但是它们意义不是很明确,你看到1、2、3很难将他们和周几联系起来,而且这存在一个很大的问题,如果一不小心为week赋值100,在编译时完全可以通过,但是它已经不再表示周了。这个问题可以用一个枚举类型来定义周,如下:

enum week{
    sun,mon,tue,wed,thu,fri,sat
};

int main(){
    enum week day=mon;//可以将枚举值赋值给一个枚举变量 
    cout<<"day="<<day<<endl;
    //day=8;
return 0;
}

输出为:

day=1;

代码中注释的那部分,day=8,即给day赋值8的话,就会报错:

[Error] invalid conversion from ‘int’ to ‘week’ [-fpermissive]

class

类是c++面向对象的核心,它由一系列的数据成员和方法成员组成。由于其内容较多且很重要,后面将有一个章节介绍类的内容。

3.复合数据类型

c++有多种复合数据类型,这里主要介绍“引用”和“指针”两种。变量的引用和指针实质相同,都是对变量地址进行操作。
引用就相当于给变量名取了另外一个名字,实质上它们是同一块内存地址,除了名字不同,其他属性都一样,所以对一个名字操作,也就是对另一个名字的操作。
指针则是另外一个变量(指针变量),它指向它初始化的地址,可以多个指针指向同一块地址,这样每个指针对这个地址的操作,都会影响到这块地址的值,也就是影响到其他指针。

引用和指针的定义

int a =9;
int &b=a;//为a取了个别名叫b
int *c=&a;//定义一个指针变量c指向a变量的地址

“&”符号:出现在“=”左边表示引用的定义,出现在“=”右边表示取变量地址。
“*”符号:出现在“=”左边表示指针的定义,出现在“=”右边表示取地址上的值。
关于指针和引用,还有很多知识,但鉴于这是基础篇,就简单介绍下,后面将会有专门的文章介绍指针和引用。

4.类型转换

变量是存储空间,它本身其实是一个二进制串,只有对其赋予了数据类型,它才有意义。而变量的数据类型并不是一成不变的,在程序运行中,可以临时改变变量的类型,使这块内存按照这种数据类型进行“翻译”,从而符合上下文的需求,这就是变量的类型转换。类型转换包括自动类型转换和强制类型转换。

自动类型转换

自动类型转换是编译器自动完成的,如将一个double类型的值赋给一个int类型的值:

int a;
double b=0.5;
a=b;

测试编译器并不会报error,只会报一个 warning,说转换可能会损失精度,并且能正确输出结果0(在运行中也确实损失了精度,因为double是8位,int一般只占4位)。自动类型转换规则如下:(参考自博文:链接

1、算术运算式中,低类型能够转换为高类型。 2、赋值表达式中,右边表达式的值自动隐式转换为左边变量的类型,并赋值给他。
3、函数调用中参数传递时,系统隐式地将实参转换为形参的类型后,赋给形参。
4、函数有返回值时,系统将隐式地将返回表达式类型转换为返回值类型,赋值给调用函数。
5、字符必须先转换为整数(C语言规定字符类型数据和整型数据之间可以通用) 。 6、short型转换为int型(同属于整型) 。
7、float型数据在运算时一律转换为双精度(double)型,以提高运算精度(同属于实型) 。
这里写图片描述

强制类型转换

强制类型转换由用户完成,又可分为c风格的转换和c++风格的转换。
c风格的转换即在需转换的变量前加转换后的类型,如下:

//(type) expression;
int a=9;
double b=(double)a;//将a临时转换为double赋值给b,a本身的数据类型不变。

以下小结摘自博文:链接
c风格的类型转换虽然方便但有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型之间转换,比如你可以把一个指向const对象的指针转换成指向非const对象的指针,把一个指向基类对象的指针转换成指向一个派生类对象的指针,这两种转换之间的差别是巨大的,但是传统的c语言风格的类型转换没有区分这些。还有一个缺点就是,c风格的转换不容易查找,他由一个括号加上一个标识符组成,而这样的东西在c++程序里一大堆。
所以c++为了克服这些缺点,引进了4种新的类型转换操作符如下:

static_cast

最常用的类型转换符,在正常状况下的类型转换,如把int转换为float,如:int i;float f; f=(float)i;或者f=static_cast(i);

const_cast

用于取出const属性,把const类型的指针变为非const类型的指针,如:const int *fun(int x,int y){}  int *ptr=const_cast

class C{
  //…C没有虚拟函数
};
class T{
  //…
}
int main(){
  dynamic_cast<T*> (new C);//错误
}

此时如改为以下则是合法的:

class C{
public:
  virtual void m() {};// C现在是 多态
}

reinterpret_cast

interpret是解释的意思,reinterpret即为重新解释,此标识符的意思即为数据的二进制形式重新解释,但是不改变其值。如:int i; char *ptr=”hello freind!”; i=reinterpret_cast(ptr);这个转换方式很少使用。


【二】变量


1.什么是变量

变量是一个或多个对存储单元的抽象,也是直接访问存储单元的一种方式(也可以通过指针和引用间接访问),变量具有变量名、作用域、生存期、值和类型5个属性,其中通过变量类型我们可以知道变量所占用的存储空间大小(几字节)、可以在该变量上的操作。如:

int a;

a表示4字节存储空间,可以对a进行算术运算,输出等操作。
变量名是变量的标识,一般通过变量名对变量进行操作;作用域是指可以方位变量的程序范围;变量的生存期是指一个变量与存储区进行绑定到接触绑定之间的时间区间。

2.变量的定义和初始化

变量定义

//类型说明符 标识符 如:
const int a;

const int 为类型说明符,a为标识符,其中类型说明符可以是任何数据类型和组合类型,标识符可以是除关键字之外的所有由字母和下划线开头,字母,数字和下划线组成的字符串。
初始化
[来自c++primer的强调]变量的初始化不是赋值,而是在变量被创建的时候为其赋初值的过程,而赋值是擦除当前值,以一个新值替代的过程,虽然两者都可以用赋值号”=”进行操作,但这是两种不同的操作,不要混为一谈。
变量的初始化方式有多种,如下:

    int a=1;
    int a={1};
    int a(1);
    int a{1};

这几种方式都可以为a赋初值1,而花括号{}类型的赋值,在c++11中得到了全面应用,这种方式被称为“列表初始化”,具有很多优点。在这个例子中当然看不出任何优点,但当学习到后面的类那部分时,为一个对象初始化时就能体会到它的优点。一般情况下建议定义变量是必须初始化。

3.申明和定义的关系

申明使变量名为程序所知,定义为变量创建关联的实体。申明和定义的相同之处在于他们都规定了变量的名字和类型,但定义还为其申请存储空间和赋初值。
如果需要申明一个变量而不定义它,需要使用extern关键字修饰,并且不要为它初始化(一旦初始化必须申请空间,就是定义,也就抵消了extern的作用,如果在一个函数里对extern修饰的变量初始化,还会引发错误)。
申明变量如下:

extern int  a;//申明了一个变量而为定义它

也许你会问,为什么要申明而不定义呢?这是为了支持“分离式编译”机制,该机制允许将程序分隔为多个文件独立编译。

4.常量

有时我们需要一个常量来存储某个定值,而且要阻止任何情况下被修改,那么我们可以使用const修饰符来定义一个常量。常量必须被初始化,常量一旦定义就不能被修改,其定义如下:

const int a=10;

5.变量的使用

变量有变量名、变量地址、变量类型、变量值等属性,一般通过变量名使用该变量,但需要注意变量名出现在不同的地方所表示的内容有所不同。
一般情况下,变量名表示该变量地址上的内容,但当变量名出现在赋值号左边时,表示的是变量地址,即将右边的内容放到左边的地址上。当变量名出现在赋值号右边,但左边是一个地址时,该变量名表示一个地址,即将自己的地址告诉给左边。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值