三、C++数据类型
2、变量
变量为我们提供有名字的储存区,可以通过程序访问,对其进行读写。
· 变量有特定的数据类型,决定了内存分配的布局、大小、储存值的范围以及操作集。
int student_count;
double salary;
bool on_loan;
string street_address; //需要引入头文件
char delimiter;
变量有两个属性,一个是数据值【右值】,另一个是它的地址【左值,文字常量一般不能作为左值】。右值被读取【在其内存中将数据值读出】,左值被覆写【把右值写到左值相关内存区中】。注意:左值不能是文字常量,不能是算术表达式,不能为空。
C++在使用对象之前必须要知道该对象【声明或者定义一个对象】。一个好建议:在头文件中声明好对象,在使用时包含头文件。
变量名:字母、数字、下划线_组成,不能以数字开头。不能是关键字。一般用小写。
变量分为全局变量和局部变量,全局变量在定义时如果不给它赋初值,那么初值默认为0;但是局部变量在定义时如果没有赋初值,它的初值是【未初始化的】,值可能是一个随机的位串。动态变量分配的对象也是【未初始化的】。
初始值可以在对象的定义中实现,在声明时如果有初始值那也是被初始化的。
初始化的两种方式:显式:= ;隐式:();
合法但有病的初始化方式:
int bizarre = bizarre;
特殊的构造函数语法:
// 设置 ival 为 0 dval 为 0.0
int ival = int();
double dval = double();
对象的初始化也可以通过复杂的表达式,包括使用函数初始化。
3、指针类型
指针的典型用法:构建一个链接的数据结构,管理动态分配的对象,作为函数的参数来传递大型的数组或者类的对象。
因为每个数据类型相关的存储大小不同,所以指针也要声明一个相关的数据类型,用来指示编译器解释地址内容。
int *ip1, *ip2;
complex<double> *cp;
string *pstring;
vector<int> *pvec;
double *dp;
通过*(解引用符号)来定义指针。
注意事项:
1、如果没赋初值,指针会被初始化为“没有指向任何对象的指针”。
2、使用&来获取变量的地址赋值给指针,不能够将变量的值赋值给指针。
3、指针的赋值一定要注意数据类型。
4、如果想要仅仅持有地址,但是不需要编译器对储存布局和内容进行解释,可以使用空指针(void*),可以支持任意的数据类型,但是不支持对这个地址进行操作。
对于一个指针来说,它也是一个变量,所以理所当然的,它也需要一个地址去储存它的数值【即它指向的地址】。
int *p1;
p1; //包含了它指向的地址
&p1; //储存它的地址
int **p2=&p1;
p2; //p1的地址
&p2; //p2的地址
使用指针访问变量的值:
*pi = ival2;
// 对于右边的实例, 读取 pi 所指对象的值
// 对于左边的实例 则把右边的表达式赋给对象
*pi = abs( *pi ); // ival = abs(ival);
*pi = *pi + 1; // ival = ival + 1;
一个实例:
int *pi = &ival; //pi中储存了ival的地址
int **ppi = π //ppi中储存了pi的地址
int *pi2 = *ppi; //pi2中储存了ppi的解引用,即pi存的内容,是ival的地址,而这个地址中存的是int类型的值,所以只需要用一个int*
int val = **ppi; //两次解引用能够获得ival的值
指针的加减运算:
pi = pi + 2;
虽然看上去加了2,但是加的2取决于指针的数据类型,C++会自动加上2*数据类型所占字节数的地址。
Q:下面的小程序的行为是未定义的,可能在运行时失败:int foobar( int *pi ) {*pi = 1024;return *pi;}int main() {int *pi2 = 0;int ival = foobar( pi2 );return 0;}怎么修正它呢?因为刚开始给指针赋初值的时候,分配的内存是随机的,未被定义的,所以会产生这样的后果。要在main函数中分配一个明确的地址。int main(){ int ival = 0; int *pi = &ival; ival = foobar(pi); return 0; }