复合类型
数组
数组是一种书类型,能够存储多个同类型的值。每个值都存储在独立的数组元素中,计算机在内存中依次存储数组的各个元素;
数组的很多用途是基于这样的一个事实,可以单独访问数组元素,方法是使用下标来索引对元素进行编号,C++数组从0开始编号;
编译器不会检查使用的下标是否被使用
int _tmain(int argc, _TCHAR* argv[])
{
using namespace std;
int yams[3]; // creates array with three elements
yams[0] = 7; // assign value to first element
yams[1] = 8;
yams[2] = 6;
int yamcosts[3] = {
20, 30, 5 }; // create, initialize array
cout << "Total yams = ";
cout << yams[0] + yams[1] + yams[2] << endl;
cout << "The package with " << yams[1] << " yams costs ";
cout << yamcosts[1] << " cents per yam.\n";
int total = yams[0] * yamcosts[0] + yams[1] * yamcosts[1];
total = total + yams[2] * yamcosts[2];
cout << "The total yam expense is " << total << " cents.\n";
cout << "\nSize of yams array = " << sizeof yams;
cout << " bytes.\n";
cout << "Size of one element = " << sizeof yams[0];
cout << " bytes.\n";
return 0;
}
如果我们操作一个下标不存在的数字,编译器并不会替我们去检查这个下标的值是否存在,编译器是可以正常编译通过的,但是程序运行会崩溃;
字符串
字符串是存储在内存中连续字节中的一系列字符。存储在连续字节中的一系列字符意味着可以将字符串存储在char数组中,每个字符都位于自己的数组元素中;
字符串一定以\0结尾
char dog[8] = {
'b', 'e', 'a', 'u', 'x', ' ', 'I', 'I' }; //这种初始化方式编译器不会报错,但执行结果可能不是我们预期的结果
char cat[8] = {
'f', 'a', 't', 'e', 's', 's', 'a', '\0' };
char bird[11] = "Mr,Cheeps";
char fish[] = "Bubbles";
string类
C++98标准通过string类扩展了C++库,因此可以使用string类型的变量而不是使用字符数组来存储字符串;
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
using namespace std;
char charr1[20]; // create an empty array
char charr2[20] = "jaguar"; // create an initialized array
string str1; // create an empty string object
string str2 = "panther"; // create an initialized string
cout << "Enter a kind of feline: ";
cin >> charr1;
cout << "Enter another kind of feline: ";
cin >> str1; // use cin for input
cout << "Here are some felines:\n";
cout << charr1 << " " << charr2 << " "
<< str1 << " " << str2 // use cout for output
<< endl;
cout << "The third letter in " << charr2 << " is "
<< charr2[2] << endl;
cout << "The third letter in " << str2 << " is "
<< str2[2] << endl; // use array notation
return 0;
}
字符串初始化
char first_data[] = {
"Le Chapon Dodu" };
char second_data[] = {
"The Elgant Flate" };
string third_data = {
"The Bread Bow" };
其他类型
除char以外,C++还有wchar_t;而C++11新增了char16_t和char32_t;
wchar_t title[] = L"Chinese Boy";
char16_tname[] = u"sYstemk1t";
char32_car[] = U"Humber Super";
结构
C++中结构是一种比数组更加灵活的数据结构,因为同一个结构可以存储多种类型的数据;
struct inflatable
{
char cName[20];
float fVolume;
double dPrice;
};
int _tmain(int argc, _TCHAR* argv[])
{
inflatable hat;
inflatable woopie_cushion;
struct inflatable gooes; //在C++中可以省略struct关键字
return 0;
}
使用.来访问结构体的成员

使用结构
struct inflatable
{
char cName[20];
float fVolume;
double dPrice;
};
int _tmain(int argc, _TCHAR* argv[])
{
inflatable guest = {
"sYstemk1t",
1.88,
20.00
};
inflatable pal = {
"pal",
2.88,
22.00
};
cout << guest.cName << " " << guest.dPrice << " " << guest.fVolume << endl;
cout << pal.cName << " " << pal.dPrice << " " << pal.fVolume << endl;
return 0;
}
C++11结构初始化
void test01()
{
inflatable duck{
"sYstemk1t", 0.12, 3.14 };
cout << duck.cName << " " << duck.dPrice << " " << duck.fVolume << endl;
}
struct perks
{
int nKey_number;
char car[12];
}mr_glitz =
{
7,
"sYstemk1t"
};
void test02()
{
cout << mr_glitz.car << endl;
cout << mr_glitz.nKey_number << endl;
}
结构中位字段
struct torgle_register
{
unsigned int SN : 4;
unsigned int : 4;
bool goodIn : 1;
bool goodTorgle : 1;
};
void test03()
{
torgle_register tr = {
14, true, false };
if (tr.goodIn)
{
;
}
}
共用体
共用体是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型;
共用体的用途之一,当数据项使用两种或多种格式时,可以节省空间;
struct widget
{
char brand[20];
int type;
union id
{
long id_num;
char id_char[20];
}id_val;
};
void test02()
{
widget w;
w.type = 1;
if (w.type == 1)
{
cin >> w.id_val.id_num;
}
else
{
cin >> w.id_val.id_char;
}
cout << w.id_val.id_num << endl;
cout << w.id_val.id_char << endl;;
}
由于共用体没有名称,其成员将为位于相同地址处的变量。显然,每次只有一个成员是当前的成员;
枚举
C++的enum关键字提供了另一种创建常量的方式,这种方式可以替代const,它允许定义新类型,但必须严格限制;
enum spectrum
{
red,orange,yellow,green,blue,violet,indigo,ultravlet
};
void test()
{
spectrum band;
band = blue;
//band = 2000; //错误赋值
}
指针和自由存储空间
指针也是一个变量,只不过其存储的是值的地址,而不是值本身;
int _tmain(int argc, _TCHAR* argv[])
{
int donuts = 6;
double cups = 4.5;
cout << "dontus:" << &donuts << endl;
cout << "cups:" << &cups << endl;
return 0;
}
显示地址时,实现是以16禁止表示法,常用内存表示法;
指针用于存储值的地址中表示了我们存储的值,我们需要对指针进行解引用;
void test01()
{
int updates = 6;
int* p_update;
p_update = &updates;
cout << "updates = " << updates << endl;
cout << "updates memory:" << &updates << endl;
cout << "p_update = " << *p_update << endl;
cout << "p_update = " << p_update << endl;
}
声明和初始化指针
指针的初始化,表示计算机需要跟踪指针指向的值的类型;
void test02()
{
int higgens = 5;
int* pt = &higgens;
cout << "higgens = " << higgens << " " << "higgens memory = " << &higgens << endl;
cout << "pt = " << *pt << " " << "pt memory = " << pt << endl;
}
指针的危险
在C++中创建指针的时候,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存;
指针和数字
指针虽然不是整形,但是它在内存中占用4字节;整形我们可以用于运算,但是指针用于没有意义,因为两个地址做运算没有任何意义;
void test03()
{
int* p;
//p = 0x12345678; //错误赋值
p = (int *)0x12345678;
cout << *p << endl; //这个输出没有任何意义,因为0x12345678这个地址也许没有被申请,访问空内存,自然也不会有输出
}
new分配内存
变量是在编译时分配的有名称的内存,而指针至少为可以通过名称直接访问的内存提供了一个别名。真正的指针强大之处在于,在运行阶段分配未命名的内存以存储值;
void test04()
{
int* p = new int; //new一个整形的内存并把地址赋值给变量p
cout << p << endl;
}
new分配的内存对象处于内存的堆区
void test05()
{
int higgens = 1001;
int*p = new int;
*p = 100;
double* pd = new double;
*pd = 3.1415926;
cout << "higgens = " << higgens << "higgens memory = " << &higgens<< endl;
cout << "p = " << *p << "p memory = " << p << endl;
cout << "pd = " << pd << "pd memory = " << &pd << endl;
cout << "psize = " << sizeof(p) << endl;
cout << "pdsize = " << sizeof(pd) << endl;
cout << "psize = " << sizeof(*p) << endl;
cout << "pdsize = " << sizeof(*pd) << endl;
}
delete释放内存
当需要内存的时候,可以使用new来请求分配,但是当这块内存使用完毕后,我们往往需要释放这块内存,计算机内存并不是无穷无尽的,所以我们需要将内存归还给内存池;
void test06()
{
int* ps = new int;
delete ps; //释放ps指向的内存,并不会删除指针变量ps本身,可以将ps重新指向一个分配的内存块;
delete ps; //重复释放
int jugs = 5;
int* pi = &jugs;
delete pi; //错误,只可以使用delete来释放new申请的内存
动态数组
我们在编译初期并不知道我们需要申请多大的一块内存,所以我们希望通过声明来创建数组,使得它在被编译的时候为它分配内存空间。不管程序是否使用,数组都存在,占用内存;
在编译时给数组分配内存被称为静态联编,意味着数组是在编译时加入到程序中去的,使用new时,在运行阶段时选择数组的长度,如果不需要,则不创建;
new创建动态数组
在C++中,创建动态数组很容易,只需将数组的元素类型和元素个数告诉new即可;必须在类型名后加方括号;
void test07()
{
int* psome = new int[10]; //创建10个int元素的数组;
delete[] psome; //释放动态数组
}
- 不要使用delete来释放不是new分配的内存
- 不要使用delete释放同一个内存块两次
- 如果使用new[]为数组分配内存,则使用delete[]来释放
- 如果使用new[]为一个实体分配内存,则使用delete来释放
- 对空指针应用delete是安全的
使用动态数组
void test08()
{
double* p3 = new double[3];
p3[0] = 0.2;
p3[1] = 0.5;
p3[2] = 0.8;
cout << "p3[1] is " << p3[1] << endl;
p3 += 1; //加类型的步长
cout << "p3[1] is " << p3[1] << endl;
p3 -= 1;
cout << "p3[1] is " << p3[1] << endl;
delete[] p3; //释放内存
}
指针算术
指针和数组基本等价的原因在于算术和C++内部处理数组的方式;
void test09()
{
double wages[3] = {
1000.0, 2000.0, 3000.0 };
short stacks[3] = {
3, 2, 1 };
double* pw = wages;
short* ps = &stacks[0];
cout << "pw = " << pw << "," << *pw << endl;
pw += 1;
cout << "pw = " << pw << "," << *pw << endl;
cout << "ps = " << ps << "," << *ps << endl;
ps += 1; //加法是指针的步长,指针的步长是当前类型的长度
cout << "ps = " << ps << "," << *ps << endl;
}
动态结构
在运行时创建数组优于在编译时创建数组,对于结构也是如此。需要在程序运行时为结构分配空间,这也可以使用malloc或new来完成;
struct inflatable
{
char cName[20];
float fVolume;
double dPrice;
};
void test10()
{
inflatable* ps = new inflatable; //将存储inflatable结构的一块内存的地址赋值给ps
strcpy(ps->cName, "sYstemk1t");
ps->dPrice = 3.1415926;
(*ps).fVolume = 6.281234;
cout << ps->cName << endl;
cout << (*ps).fVolume << endl;
cout << ps->dPrice << endl;
}
同样的,结构指针不可以使用(.)来访问了,我们需要使用特定的(->)来访问指针结构成员;但是我们同样也可以使用指针类型点的方式来读取结构内的值;
函数使用指针
char* getname(void);
void test11()
{
char* name;
name = getname();
cout << name << "at" << (int *)name << endl;
delete[] name;
name = getname();
cout << name << "at" << (int *)name << endl;
delete[] name;
}
char* getname(void)
{
char temp[_MAX_PATH];
cout << "Enter last name:";
cin >> temp;
char* pn = new char[strlen(temp) + 1];
strcpy(pn, temp);
return pn;
}