C++布尔类型,三目运算符,new和delete详解
一、c++布尔类型
- bool的两种内建的常量
true(1)和 false(0)
表示状态。这三个名字都是关键字。 - 给 bool 类型赋值时,非 0 值会自动转换为 true(1),0 值会自动转换 false(0);
- bool 类型占 1 个字节大小 。
- C语言并没有彻底从语法上支持“真”和“假”,只是用 0 和非 0 来代表。
代码演示:
#include <iostream>
using namespace std;
void test01()
{
bool mybool;
cout<<sizeof(bool)<<endl;
mybool=false;
cout<<"false="<<false<<endl;
cout<<"true"<<true<<endl;
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
任何数字值或指针值都可以被隐式转换为bool值。任何非零值都被转换为true,而零被转换成false:
bool a=-100;//true
bool b=0;//false
二、三目运算符a>b?a>b
1.c语言三目运算表达式返回值为数据值,为右值,不能赋值。
代码演示:
#include <iostream>
using namespace std;
int main()
{
int a=40;
int b=50;
printf("结果:%d\n",a>b?a:b)//50
//a>b?a:b整体结果为右值不能被赋值
//a>b?a:b=100;//error
}
2.c++经常用三目运算(?:)符取代if~else,通用·格式如下:
expression1?expression2:expression3
如果expression1
为true
,则表达式的值为expression2
,反之表达式值为expression3
.代码演示:
#include <iostream>
using namespace std;
int main()
{
int a,b;
cout<<"Enter a b:";
cin>>a>>b;
cout<<"The larger of"<<a<<"and"<<b;
int c =a>b?a:b;
cout<<"is"<<c;
return 0;
}
当你输入25和28两个数,通过a>b?a:b时,表达式不满足输出b,满足时输出a。
三、new 和delete运算符介绍
- 栈:在函数内部声明的所有变量都将占用栈内存
- 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
- 项目3
在c语言可以用库函数malloc()
来分配空间;在c++中也可以,但是在c++更好的方法用——new运算符。
代码演示:
int *p=(int *)malloc(sizeof(int)*8);//分配8个int的内存空间
free(p);//算法内存
在C++中,这两个函数仍然可以使用,但是C++又新增了两个关键字,new 和 delete
:new 用来动态分配内存,delete 用来释放内存。
int *pn = new int; //分配1个int型的内存空间
delete pn; //释放内存;不会删除pn本身
不要释放已经释放的内存块,这样做什么情况都能发生。不要使用delete来释放声明变量所获得的内存:
int * ps = new int;
delete ps;//ok
delete ps;//on
int jugs = 5;
int * pi = &jugs;
delete pi;//on
使用delete的关键在于,将它用于new分配的内存,并意味着要使用用于new的指针,而是用于new的地址:
int * ps =new int;
int * pq= ps;
delete pq;
4.不要创建两个指向同一个内存块的指针,因为这将增加错误地删除同一个内存块两次的可能性。
1.用new创建动态数组
int *pt= new int[10]; //分配10个int型的内存空间
delete[] pt;
通常 new 和 delete、new[] 和 delete[]
操作符应该成对出现,不能和C语言中 malloc()、free()
一起使用,对空指针使用delete是安全的。
使用动态数组:
#include <iostream>
using namespace std;
int main()
{
double *p3= new double [3];
p3[0]=0.2;
p3[1]=0.5;
p3[2]=0.8;
cout<<"p3[1] is"<<p3[1]<<".\n";
p3=p3+1;
cout<<"Now p3[0] is"<<p3[0]<<"and";
cout<<"p3[1] is"<<p3[1]<<".\n";
p3=p3-1;
delete [] p3;
return 0;
}
程序中将·指针p3数组名来使用,p3[0]为第一个元素,依次类推。下面的代码指出数组名和指针的区别:
p3=p3+1;
不能修改数组名的值,但指针是变量,因此可以修改值。
2.new创建动态结构
-
在运行时创建数组优于在编译时创建数组,对于结构也是如此。
-
需要在程序运行时为结构分配所需的空间。这也可以使用new运算符来完成。通过new,可以创建动态结构。
-
动态表示内存在运行时,而不是在编译时。
-
将new用于结构由两步完成:创建结构和访问其成员。要创建结构,需要同时使用结构类型和new。
例如:要创建一个未命名的inflatable
类型,并将其地址赋给一个指针:
inflatable * ps = new inflatable;
这将把足以存储inflatable
结构的一块可用内存的地址赋给ps。
访问成员时,创建动态结构时,不能将成员运算符句点用于结构名,因为这种结构没有名称,只知道地址。所以c++提供了箭头运算符(->)
提供访问;另一种如果ps是指向结构的指针,则*ps
就是被指向的值:结构本身。由于*ps
是个结构,因此(*ps).price
时该结构的price成员。
例:
#include <iostream>
using namespace std;
struct inflatable//结构定义
{
char name[20];
float volume;
double price;
};
int main()
{
inflatable * ps = new inflatable;//new分配
cout<<"Enter name of inflatable item:";
cin.get(ps->name,20);
cout<<"Enter volume in cubic feet:";
cin>>(*ps).volume;
cout<<"Enter prive:$";
cin>>ps->price;
cout<<"Name:"<<(*ps).name<<endl;
cout<<"Volume:"<<ps->volume<<"cublic feet\n";
cout<<"Price:$"<<ps->price<<endl;
delete ps;
return 0;
}
3.new和delete的示例
使用new和delete来存储通过键盘输入的字符串的示例。
#include <iostream>
#include<cstring>
using namespace std;
char * getname(void);//函数原型
int main()
{
char * name;//创建指针没有存储
name = getname();
cout<<name<<"at"<<(int *)name<<"\n";
delete [] name;
name=getname();
cout<<name<<"at"<<(int*)name<<"\n";
delete [] name;
return 0;
}
char * getname()//返回指向新字符串的指针
{
char temp[80];//暂时储存
cout<<"Enter lst name:";
cin>>temp;
char * pn = new char[strlen(temp)+1];//计算字符串长度,1表示:\0 存储字符
strcpy(pn,temp);//复制字符串到更小的空间
return pn;//函数结束,temp丢失
}
四、自动存储、静态存储和动态存储
根据用于分配内存的方法。c++有3种管理数据内存的方式:自动存储、静态存储和动态存储。在存在时间的长度方面,以这三种方式分配的数据对象各不相同。
1.自动存储
- 在函数内部定义的常规变量使用自动存储空间,被称自动变量,意味着在所属的函数被调用时自动产生,在该函数结束时消灭。
- 实际上,自动变量是个局部变量,其作用域为包含的代码块。代码块是被包含在花括号中的一段代码。
- 自动变量通常存存储在栈中。意味着执行代码块时,其中的变量将依次加入到栈中,而在离开代码块时,将按相反的顺序释放这些变量,这倍称为后进先出。
2.静态存储
- 静态存储是整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种:一种是在函数外面定义;另一种是在声明变量时使用关键字static:
static double fee = 56.50;
- 在K&R C中。只能初始化静态数组和静态结构,而c++有的部分也可以初始化自动数组和自动结构。但有些c++实现还不支持自动数组和自动结构的初始化。
- 自动存储和静态存储的关键在于:这些方法严格的限制了变量的寿命。变量可能存在程序的整个生命周期(静态变量)。也可能只是特定函数被执行时存在(自动变量)。
3.动态存储
- new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理一个内存池,在c++中被称为自由存储空间或堆。
- 该内存池同用于静态变量和自动变量的内存时分开的。new和delete能够在一个函数中分配空间,而在另一个函数中释放。因此,数据的生命周期不完全受程序或函数的生存时间控制。
- 与使用常规变量相比,使用new和delete能够对使用内存有更大的控制权。但内存管理更复杂。
- 在栈中,自动添加和删除机制使得占用的内存总是连续的,但new和delete的相互影响可能导致占用的自由存储区不连续,这使得跟踪新分配内存的位置更困难。
五、栈、堆和内存泄漏
-
若使用new没有调用delete,包含指针的内存由于内存由于作用域规则和对象生命周期的原因而被释放,在自由存储空间上动态分配的变量或结构也将继续存在。实际上,将无法访问自由存储空间的结构,因为指向这些内存的指针无效,将导致内存泄漏。
-
泄漏的内存将在整个生命周期不可使用。内存被分配出去,但无法收回。严重的话,以至于程序可用的内存被耗尽,出现内存耗尽错误,导致程序崩溃。也会给相同内存空间运行的应用程序带来影响,导致它们崩溃。
-
避免内存泄漏方法是,即同时使用new和delete运算符,在自由存储空间上动态分配内存,随后释放。
六、auto声明
auto能够根据初始值的类型推导·变量的类型。使用auot,而不指定变量的类型,编译器将把变量的类型设置成为与初始值相同:
auot n = 100;//int
auot x = 1.5;//double
auot y = 1.3e12L;//long double
然而,自动推导类型并非为这种简单情况而设计的;事实上,如果将其用于这种简单情形,甚至可能误入歧途。例如:假设要将x、y和z都指定为double类型,如下代码:
auto x = 0.0;//ok
double y = 0.0;//ok,o自动转换0.0
auto z = 0;//o为int
显示地将声明类型时,将变量初始化0不会导致任何问题,但采用自动类型推断时,这却会导致问题。
处理复杂类型,如标准模板库中的类型时,自动类型推断才能显现出来。:
vector<double> scores;
vector<double>::iterator pv = scores.begin();
c++11允许重写为下面形式:
vector<double> scores;
auot pv = scores.begin();