欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第4章 复合类型

程序员文章站 2022-07-16 19:43:55
...

创建和使用数组

创建和使用C-风格字符串

创建和使用string类字符串

使用方法getline()和get()读取字符串

混合输入字符串和数字

创建和使用结构

创建和使用共用体

创建和使用枚举

创建和使用指针

使用new和delete管理动态内存

创建动态数组

创建动态结构

自动存储、静态存储和动态存储

vector和array类简介

 

目录

4.1 数组

4.1.1 程序说明

4.1.2 数组的初始化规则

4.1.3 C++11数组初始化方法

4.2 字符串

4.2.1 拼接字符串常量

4.2.2 在数组中使用字符串

4.2.3 字符串输入

4.2.4 每次读取一行字符串输入

4.2.5 混合输入字符串和数字

4.3 string类简介

4.3.1 C++11字符串初始化

4.3.2 辅助、拼接和附加

4.3.3 string类的其他操作

4.3.4 string类I/O

4.3.5 其他形式的字符串字面值

4.4 结构简介

4.4.1 在程序中使用结构

4.4.2 C++11结构初始化

4.4.3 结构可以将string类作为成员吗

4.4.4 其他结构属性

4.4.5 结构数组

4.4.6 共用体

4.5 共用体

4.6 枚举

4.6.1 设置枚举量的值

4.6.2 枚举的取值范围

4.7 指针和*存储空间

4.7.1  声明和初始化指针

4.7.2 指针的危险

4.7.3 指针和数字

4.7.4 使用new来分配内存

4.7.5 使用delete释放内存

4.7.6 使用new来创建动态数组

4.8 指针、数组和指针算术

4.8.1 程序说明

4.8.2 指针小结

4.8.3 指针和字符串

4.8.4 使用new创建动态结构

4.8.5 自动存储、静态存储和动态存储

4.9 类型组合

4.10 数组的替代品

4.10.1 模版类vector

4.10.2 模版类array(C++11)

4.10.3 比较数组、vector对象和array对象

4.11 总结


4.1 数组

存储在每个元素中的值的类型
数组名
数组中的元素数

第4章 复合类型

第4章 复合类型

第4章 复合类型

4.1.1 程序说明

// arrayone.cpp -- small arrays of integers
#include <iostream>
int main()
{
    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
// NOTE: If your C++ compiler or translator can't initialize
// this array, use static int yamcosts[3] instead of
// int yamcosts[3]

    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";
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ ./a.out 
Total yams = 21
The package with 8 yams costs 30 cents per yam.
The total yam expense is 410 cents.

Size of yams array = 12 bytes.
Size of one element = 4 bytes.

4.1.2 数组的初始化规则

第4章 复合类型

4.1.3 C++11数组初始化方法

新增:
1.初始化数组,省略=
    double earnings[4] {1,2,3,4}
2.大括号不写值,默认设置为0
    float balance[100] {};
3.列表初始化禁止缩窄转换
    long plies[] = {25, 92, 3.0}; 错误
    char splits[4] {'h', 'I', 1122011, '\0'} 错误
    char tiles[4] {'h', 'I', 112, '\0'} 正确

浮点数转化为整型为缩窄操作,即使小数点为0
超出char变量的取值范围

4.2 字符串

C++处理字符串的方式
(1)C-style string
(2)string类库

C-style string
空字符很重要!!
因为饿不应将不是字符串的字符数组当作字符串来处理
char dog[8] = {'b','e','a','u','X','','I','I'}; // not a string
char cat[8] = {'b','e','a','u','X','','I','\0'}; //a string

用双引号括起的字符串隐式地包括结尾的空字符,称为字符串常量,字符串字面值‘
char bird[11] = "Mr. Cheeps";
char fish[] = "Bubbles";
C++输入工具通过键盘输入,将字符串读入到char数组中时,将自动加上结尾的空字符

第4章 复合类型

char a = 'S';//字符常量

“F”='F' + \0
“F”实际表示字符串所在的内存地址
char b = "F";//字符串常量 

4.2.1 拼接字符串常量

C++允许将两个用引号括起来的字符串合并成一个

4.2.2 在数组中使用字符串

// strings.cpp -- storing strings in an array
#include <iostream>
#include <cstring>  // for the strlen() function
int main()
{
    using namespace std;
    const int Size = 15;
    char name1[Size];               // empty array
    char name2[Size] = "C++owboy";  // initialized array
    // NOTE: some implementations may require the static keyword
    // to initialize the array name2

    cout << "Howdy! I'm " << name2;
    cout << "! What's your name?\n";
    cin >> name1;
    cout << "Well, " << name1 << ", your name has ";
    cout << strlen(name1) << " letters and is stored\n";
    cout << "in an array of " << sizeof(name1) << " bytes.\n";
    cout << "Your initial is " << name1[0] << ".\n";
    name2[3] = '\0';                // set to null character
    cout << "Here are the first 3 characters of my name: ";
    cout << name2 << endl;
    // cin.get();
    // cin.get();
    return 0;
}
[aaa@qq.com] chapter_4$ g++ strings.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
Howdy! I'm C++owboy! What's your name?
Basiman
Well, Basiman, your name has 7 letters and is stored
in an array of 15 bytes.
Your initial is B.
Here are the first 3 characters of my name: C++
sizeof运算符指出整个数组的长度
strlen()函数返回存储在数组中的字符串的长度

第4章 复合类型

4.2.3 字符串输入

// instr1.cpp -- reading more than one string
#include <iostream>
int main()
{
    using namespace std;
    const int ArSize = 20;
    char name[ArSize];
    char dessert[ArSize];

    cout << "Enter your name:\n";
    cin >> name;
    cout << "Enter your favorite dessert:\n";
    cin >> dessert;
    cout << "I have some delicious " << dessert;
    cout << " for you, " << name << ".\n";
    // cin.get();
	// cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ instr1.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
Enter your name:
Alistair Drreeb
Enter your favorite dessert:
I have some delicious Drreeb for you, Alistair.

cin使用空白(空格、制表符和换行符)来确定字符串的结束位置

第4章 复合类型

4.2.4 每次读取一行字符串输入

面向行而不是面向单词的方法
istream中的类提供了一些面向行的类成员函数:getline()和get()。
这两个函数读读取一行输入,直到达到换行符。
随后getline()丢弃换行符,而get()将换行符保留在输入序列中
// instr2.cpp -- reading more than one word with getline
#include <iostream>
int main()
{
    using namespace std;
    const int ArSize = 20;
    char name[ArSize];
    char dessert[ArSize];

    cout << "Enter your name:\n";
    cin.getline(name, ArSize);  // reads through newline
    cout << "Enter your favorite dessert:\n";
    cin.getline(dessert, ArSize);
    cout << "I have some delicious " << dessert;
    cout << " for you, " << name << ".\n";
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ ./a.out 
Enter your name:
Dirk Hammernose
Enter your favorite dessert:
Raadish Torte
I have some delicious Raadish Torte for you, Dirk Hammernose.

第4章 复合类型

// instr3.cpp -- reading more than one word with get() & get()
#include <iostream>
int main()
{
    using namespace std;
    const int ArSize = 20;
    char name[ArSize];
    char dessert[ArSize];

    cout << "Enter your name:\n";
    cin.get(name, ArSize).get();    // read string, newline
    cout << "Enter your favorite dessert:\n";
    cin.get(dessert, ArSize).get();
    cout << "I have some delicious " << dessert;
    cout << " for you, " << name << ".\n";
    // cin.get();
    return 0; 
}
aaa@qq.com] chapter_4$ g++ instr3.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
Enter your name:
Mai Parfait
Enter your favorite dessert:
Chocolate Mousse
I have some delicious Chocolate Mousse for you, Mai Parfait.
get()不再读取并丢弃换行符,而是将其留在输入队列中。

cin.get(name,ArSize);
换行符留在输入队列中。
cin.get(dessert.Artsize);
看到第一个字符是换行符,认为get()到达行尾,没有发现任何可读取的内容。

解决方法如上,两个类成员函数拼接

第4章 复合类型

4.2.5 混合输入字符串和数字

// numstr.cpp -- following number input with line input
#include <iostream>
int main()
{
    using namespace std;
    cout << "What year was your house built?\n";
    int year;
    cin >> year;
    // cin.get();
    //( cin >> year).get();
    cout << "What is its street address?\n";
    char address[80];
    cin.getline(address, 80);
    cout << "Year built: " << year << endl;
    cout << "Address: " << address << endl;
    cout << "Done!\n";
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ numstr.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
What year was your house built?
1966
What is its street address?
Year built: 1966
Address: 
Done!
cin,将回车键生成的换行符留在输入队列中,
后面的get.line()看到换行符后,认为是一个空行,将空字符串赋值给address数组

解决方法,读取地址之前丢弃换行符
cin.get() 

4.3 string类简介

string类,头文件string。
位于名称空间std中。
隐藏了字符串的数组性质,处理普通变量那样处理字符串。

与字符数组的区别是,
(1)string对象声明为简单变量,而不是数组。
(2)因为类设计让程序自动处理string的大小

C-风格初始化string对象
cin将键盘输入到string对象
cout显示string对象
数组表示法
// strtype1.cpp -- using the C++ string class
#include <iostream>
#include <string>               // make string class available
int main()
{
    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
    // cin.get();
	// cin.get();

    return 0; 
}
[aaa@qq.com] chapter_4$ g++ strtype1.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
Enter a kind of feline: ocelot
Enter another kind of feline: tiger
Here are some felines:
ocelot jaguar tiger panther
The third letter in jaguar is g
The third letter in panther is n

4.3.1 C++11字符串初始化

4.3.2 辅助、拼接和附加

合并:str1 += str2
// strtype2.cpp �- assigning, adding, and appending
#include <iostream>
#include <string>               // make string class available
int main()
{
    using namespace std;
    string s1 = "penguin";
    string s2, s3;

    cout << "You can assign one string object to another: s2 = s1\n";
    s2 = s1;
    cout << "s1: " << s1 << ", s2: " << s2 << endl;
    cout << "You can assign a C-style string to a string object.\n";
    cout << "s2 = \"buzzard\"\n";
    s2 = "buzzard";
    cout << "s2: " << s2 << endl;
    cout << "You can concatenate strings: s3 = s1 + s2\n";
    s3 = s1 + s2;
    cout << "s3: " << s3 << endl;
    cout << "You can append strings.\n";
    s1 += s2;
    cout <<"s1 += s2 yields s1 = " << s1 << endl;
    s2 += " for a day";
    cout <<"s2 += \" for a day\" yields s2 = " << s2 << endl;

    //cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ strtype2.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
You can assign one string object to another: s2 = s1
s1: penguin, s2: penguin
You can assign a C-style string to a string object.
s2 = "buzzard"
s2: buzzard
You can concatenate strings: s3 = s1 + s2
s3: penguinbuzzard
You can append strings.
s1 += s2 yields s1 = penguinbuzzard
s2 += " for a day" yields s2 = buzzard for a day

4.3.3 string类的其他操作

string对象的技术 和 用于字符数组的技术进行比较
头文件cstring(string.h)提供函数,程序员可以使用C语言库中的函数完成任务
// strtype3.cpp -- more string class features
#include <iostream>
#include <string>               // make string class available
#include <cstring>              // C-style string library
int main()
{
    using namespace std;
    char charr1[20]; 
    char charr2[20] = "jaguar"; 
    string str1;  
    string str2 = "panther";

    // assignment for string objects and character arrays
    str1 = str2;                // copy str2 to str1
    strcpy(charr1, charr2);     // copy charr2 to charr1
 //string具有自动调节大小的功能,
    // appending for string objects and character arrays
    str1 += " paste";           // add paste to end of str1
    strcat(charr1, " juice");   // add juice to end of charr1

    // finding the length of a string object and a C-style string
    int len1 = str1.size();     // obtain length of str1
//str1是一个string对象,而size()是string类的方法
    int len2 = strlen(charr1);  // obtain length of charr1
//接受C-风格字符串作为参数
    cout << "The string " << str1 << " contains "
         << len1 << " characters.\n";
    cout << "The string " << charr1 << " contains "
         << len2 << " characters.\n";
    // cin.get();

    return 0; 
}
[aaa@qq.com] chapter_4$ g++ strtype3.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
The string panther paste contains 13 characters.
The string jaguar juice contains 12 characters.
strcat() 和 strlcpy() 指出目标数组最大允许长度的第三个参数

4.3.4 string类I/O

// strtype4.cpp -- line input
#include <iostream>
#include <string>               // make string class available
#include <cstring>              // C-style string library
int main()
{
    using namespace std;
    char charr[20]; 
    string str;

    cout << "Length of string in charr before input: " 
         << strlen(charr) << endl;
    cout << "Length of string in str before input: "
         << str.size() << endl;
    cout << "Enter a line of text:\n";
    cin.getline(charr, 20);     // indicate maximum length
    cout << "You entered: " << charr << endl;
    cout << "Enter another line of text:\n";
    getline(cin, str);          // cin now an argument; no length specifier
    cout << "You entered: " << str << endl;
    cout << "Length of string in charr after input: " 
         << strlen(charr) << endl;
    cout << "Length of string in str after input: "
         << str.size() << endl;
    // cin.get();

    return 0; 
}
[aaa@qq.com] chapter_4$ g++ strtype4.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
Length of string in charr before input: 0
Length of string in str before input: 0 //未被初始化的string类对象自动设置为0
Enter a line of text:
peanut butter
You entered: peanut butter
Enter another line of text:
blueberry jam
You entered: blueberry jam
Length of string in charr after input: 13
Length of string in str after input: 13
cin.getline(charr,20);
cin是一个istream对象,函数etline()是istream类的类方法

getline(cin,str);
将cin作为参数,指出到哪里去查找输入。也没有指出到哪里去找查找输入,因为string对象根据字符串的长度自动调整大小

第4章 复合类型

4.3.5 其他形式的字符串字面值

P88需要再看

4.4 结构简介

比数组更灵活的数据格式

第4章 复合类型

第4章 复合类型

4.4.1 在程序中使用结构

// structur.cpp -- a simple structure
#include <iostream>
struct inflatable   // structure declaration
{
    char name[20];
    float volume;
    double price;
};

int main()
{
    using namespace std;
    inflatable guest =
    {
        "Glorious Gloria",  // name value
        1.88,               // volume value
        29.99               // price value
    };  // guest is a structure variable of type inflatable
// It's initialized to the indicated values
    inflatable pal =
    {
        "Audacious Arthur",
        3.12,
        32.99
    };  // pal is a second variable of type inflatable
// NOTE: some implementations require using
// static inflatable guest =

    cout << "Expand your guest list with " << guest.name;
    cout << " and " << pal.name << "!\n";
// pal.name is the name member of the pal variable
    cout << "You can have both for $";
    cout << guest.price + pal.price << "!\n";
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ structur.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
Expand your guest list with Glorious Gloria and Audacious Arthur!
You can have both for $62.98!

第4章 复合类型

4.4.2 C++11结构初始化

支持列表初始化用于结构 
=可选

inflatable duck {"Daphe", 0.12, 9.98};
inflatable duck {};

4.4.3 结构可以将string类作为成员吗

可以
std:string name;

4.4.4 其他结构属性

// assgn_st.cpp -- assigning structures
#include <iostream>
struct inflatable
{
    char name[20];
    float volume;
    double price;
};
int main()
{
    using namespace std;
    inflatable bouquet =
    {
        "sunflowers",
        0.20,
        12.49
    };
    inflatable choice;
    cout << "bouquet: " << bouquet.name << " for $";
    cout << bouquet.price << endl;

    choice = bouquet;  // assign one structure to another
    cout << "choice: " << choice.name << " for $";
    cout << choice.price << endl;
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ assgn_st.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
bouquet: sunflowers for $12.49
choice: sunflowers for $12.49
到目前为止讨论的都能用在C结构中,
C++结构除了成员变量外,还有成员函数,通常用于类中。

4.4.5 结构数组

// arrstruc.cpp -- an array of structures
#include <iostream>
struct inflatable
{
    char name[20];
    float volume;
    double price;
};
int main()
{
    using namespace std;
    inflatable guests[2] =          // initializing an array of structs
    {
        {"Bambi", 0.5, 21.99},      // first structure in array
        {"Godzilla", 2000, 565.99}  // next structure in array
    };

    cout << "The guests " << guests[0].name << " and " << guests[1].name
         << "\nhave a combined volume of "
         << guests[0].volume + guests[1].volume << " cubic feet.\n";
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ arrstruct.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
The guests Bambi and Godzilla
have a combined volume of 2000.5 cubic feet.

4.4.6 结构中的位字段

指定使用的位数
struct toggle_register
{
    unsigned int SN : 4;
    unsigned int : 4;
    bool goodIn : 1;
    bool goodTorgle : 1;
}

4.5 共用体

只能同时存储一种类型,只能存储int、long、double。

共用体的用途之一是,当数据项使用两种或更多格式时,可节省空间。

union {

}

4.6 枚举

C++的enum工具提供了另一种创建符号常量的方式,代替const,允许定义新类型。

enum spectrum {red, orange, yellow, green, blue, violet, indigo, ultraviolet};

spectrum为新类型的名称,枚举(enumeration)
符号常量,对应整数0~7 枚举量(enumerator)

spectrum band;
band = blue;
band = blue + 3;错误 blue converted to int
band = spectrum(3);

4.6.1 设置枚举量的值

enum spectrum {red, orange=1, yellow=4, green, blue, violet, indigo, ultraviolet};

4.6.2 枚举的取值范围

4.7 指针和*存储空间

信息存储在何处
存储的值为多少
存储的信息是什么类型
// address.cpp -- using the & operator to find addresses
#include <iostream>
int main()
{
    using namespace std;
    int donuts = 6;
    double cups = 4.5;

    cout << "donuts value = " << donuts;
    cout << " and donuts address = " << &donuts << endl;
// NOTE: you may need to use unsigned (&donuts)
// and unsigned (&cups)
    cout << "cups value = " << cups;
    cout << " and cups address = " << &cups << endl;
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ address.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
donuts value = 6 and donuts address = 0x7ffee08a99d8
cups value = 4.5 and cups address = 0x7ffee08a99d0

先存储cups,再存储donuts
使用常规变量时,值是指定的值,而地址为派生量。
处理存储的策略相反,地址是指定的值,而值为派生量。

第4章 复合类型

指针名表示的是地址
*运算符 为 间接值(indirect velue)或解除饮用(dereferencing)
应用在指针,可以得到该地址出存储的值
#include <iostream>
int main()
{
    using namespace std;
    int updates = 6;        // declare a variable
    int * p_updates;        // declare pointer to an int
    
    p_updates = &updates;   // assign address of int to pointer
    
    // express values two ways
    cout << "Values: updates = " << updates;
    cout << ", *p_updates = " << *p_updates << endl;
    
    // express address two ways
    cout << "Addresses: &updates = " << &updates;
    cout << ", p_updates = " << p_updates << endl;
    
    // use pointer to change value
    *p_updates = *p_updates + 1;
    cout << "Now updates = " << updates << endl;
    // cin.get();
    return 0;
}
Values: updates = 6, *p_updates = 6
Addresses: &updates = 0x7ffeefbff528, p_updates = 0x7ffeefbff528
Now updates = 7

第4章 复合类型

4.7.1  声明和初始化指针

int* a; //a pointer to type int
int*是一种类型--指向int的指针

char的地址与double的地址长度相同,
这取决于计算机系统

第4章 复合类型

// init_ptr.cpp -- initialize a pointer
#include <iostream>
int main()
{
    using namespace std;
    int higgens = 5;
    int * pt = &higgens;

    cout << "Value of higgens = " << higgens
         << "; Address of higgens = " << &higgens << endl;
    cout << "Value of *pt = " << *pt
         << "; Value of pt = " << pt << endl;
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ init_ptr.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
Value of higgens = 5; Address of higgens = 0x7ffee71dc9d8
Value of *pt = 5; Value of pt = 0x7ffee71dc9d8

4.7.2 指针的危险

C++中的创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。

第4章 复合类型

4.7.3 指针和数字

int* pt; 
pt = 0xB8000000; //type mismatch
pt = (int*) 0xB8000000; //types now match

4.7.4 使用new来分配内存

// use_new.cpp -- using the new operator
#include <iostream>
int main()
{
    using namespace std;
    int nights = 1001;
    int * pt = new int;         // allocate space for an int
    *pt = 1001;                 // store a value there

    cout << "nights value = ";
    cout << nights << ": location " << &nights << endl;
    cout << "int ";
    cout << "value = " << *pt << ": location = " << pt << endl;

    double * pd = new double;   // allocate space for a double
    *pd = 10000001.0;           // store a double there

    cout << "double ";
    cout << "value = " << *pd << ": location = " << pd << endl;
    cout << "location of pointer pd: " << &pd << endl;
    cout << "size of pt = " << sizeof(pt);
    cout << ": size of *pt = " << sizeof(*pt) << endl;
    cout << "size of pd = " << sizeof pd;
    cout << ": size of *pd = " << sizeof(*pd) << endl;
    // cin.get();
    return 0;
}
[aaa@qq.com] chapter_4$ ./a.out 
nights value = 1001: location 0x7ffee2d109d8
int value = 1001: location = 0x7f9aabc02aa0
double value = 1e+07: location = 0x7f9aabc02ab0
location of pointer pd: 0x7ffee2d109c8
size of pt = 8: size of *pt = 4
size of pd = 8: size of *pd = 8
C库函数malloc()分配内存
C++:new运算符‘

new运算符根据类型确定需要多少字节的内存。
在程序运行时进行的。

常规变量的值存储在被称为栈(stack)的内存区域中
new从堆(heap)或*存储区(free sotre)的内存区域分配内存。

第4章 复合类型

4.7.5 使用delete释放内存

C++内存管理数据包的一个方面

int* a = new int;
..
delete a;
释放a指向的内存,但不会删除指针a本身,可以将a重新指向另一个新分配的内存快。

警告:只能用delete来释放用new分配的内存,

int a = 5;
int* b = &a;
delete b; 错误

4.7.6 使用new来创建动态数组

静态联编(static binding):在编译时给数组分配内存
动态联编(dynamic binding):数组在运行时创建。动态数组

int* psome = new int [10];
delete [] some;
指向第一个元素
// arraynew.cpp -- using the new operator for arrays
#include <iostream>
int main()
{
    using namespace std;
    double * p3 = new double [3]; // space for 3 doubles
    p3[0] = 0.2;                  // treat p3 like an array name
    p3[1] = 0.5;
    p3[2] = 0.8;
    cout << "p3[1] is " << p3[1] << ".\n";
    p3 = p3 + 1;                  // increment the pointer
    cout << "Now p3[0] is " << p3[0] << " and ";
    cout << "p3[1] is " << p3[1] << ".\n";
    p3 = p3 - 1;                  // point back to beginning
    delete [] p3;                 // free the memory
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ arraynew.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
p3[1] is 0.5.
Now p3[0] is 0.5 and p3[1] is 0.8.
C和C++内部使用指针来处理数组。数组和指针等价时C和C+的优点
将指针当作数组名来使用
C++将数组名解析为地址

4.8 指针、数组和指针算术

// addpntrs.cpp -- pointer addition
#include <iostream>
int main()
{
    using namespace std;
    double wages[3] = {10000.0, 20000.0, 30000.0};
    short stacks[3] = {3, 2, 1};

// Here are two ways to get the address of an array
    double * pw = wages;     // name of an array = address
    short * ps = &stacks[0]; // or use address operator
// with array element
    cout << "pw = " << pw << ", *pw = " << *pw << endl;
    pw = pw + 1;
    cout << "add 1 to the pw pointer:\n";
    cout << "pw = " << pw << ", *pw = " << *pw << "\n\n";

    cout << "ps = " << ps << ", *ps = " << *ps << endl;
    ps = ps + 1;
    cout << "add 1 to the ps pointer:\n";
    cout << "ps = " << ps << ", *ps = " << *ps << "\n\n";

    cout << "access two elements with array notation\n";
    cout << "stacks[0] = " << stacks[0] 
         << ", stacks[1] = " << stacks[1] << endl;
    cout << "access two elements with pointer notation\n";
    cout << "*stacks = " << *stacks
         << ", *(stacks + 1) =  " << *(stacks + 1) << endl;

    cout << sizeof(wages) << " = size of wages array\n";
    cout << sizeof(pw) << " = size of pw pointer\n";
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ addpntrs.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
pw = 0x7ffee46ab9c0, *pw = 10000
add 1 to the pw pointer:
pw = 0x7ffee46ab9c8, *pw = 20000

ps = 0x7ffee46ab9b6, *ps = 3
add 1 to the ps pointer:
ps = 0x7ffee46ab9b8, *ps = 2

access two elements with array notation
stacks[0] = 3, stacks[1] = 2
access two elements with pointer notation
*stacks = 3, *(stacks + 1) =  2
24 = size of wages array
8 = size of pw pointer
使用sizeof运算符,这种情况。C++不会将数组名解释为地址

4.8.1 程序说明

第4章 复合类型

注意:将指针变量加1后,其增加的值等于指向的类型占用的字节数。

stack[1] = *(stack + 1);

第4章 复合类型

4.8.2 指针小结

第4章 复合类型

第4章 复合类型

 

第4章 复合类型

第4章 复合类型

4.8.3 指针和字符串

第4章 复合类型

// ptrstr.cpp -- using pointers to strings
#include <iostream>
#include <cstring>              // declare strlen(), strcpy()
int main()
{
    using namespace std;
    char animal[20] = "bear";   // animal holds bear
    const char * bird = "wren"; // bird holds address of string
    char * ps;                  // uninitialized

    cout << animal << " and ";  // display bear
    cout << bird << "\n";       // display wren
    // cout << ps << "\n";      //may display garbage, may cause a crash

    cout << "Enter a kind of animal: ";
    cin >> animal;              // ok if input < 20 chars
    // cin >> ps; Too horrible a blunder to try; ps doesn't
    //            point to allocated space

    ps = animal;                // set ps to point to string
    cout << ps << "!\n";       // ok, same as using animal
    cout << "Before using strcpy():\n";
    cout << animal << " at " << (int *) animal << endl;
    cout << ps << " at " << (int *) ps << endl;

    ps = new char[strlen(animal) + 1];  // get new storage
    strcpy(ps, animal);         // copy string to new storage
    cout << "After using strcpy():\n";
    cout << animal << " at " << (int *) animal << endl;
    cout << ps << " at " << (int *) ps << endl;
    delete [] ps;
    // cin.get();
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ ptrstr.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
bear and wren
Enter a kind of animal: fox    
fox!
Before using strcpy():
fox at 0x7ffee48599c0
fox at 0x7ffee48599c0
After using strcpy():
fox at 0x7ffee48599c0
fox at 0x7fe242500000

4.8.4 使用new创建动态结构

第4章 复合类型

第4章 复合类型

// newstrct.cpp -- using new with a structure
#include <iostream>
struct inflatable   // structure definition
{
    char name[20];
    float volume;
    double price;
};
int main()
{
    using namespace std;
    inflatable * ps = new inflatable; // allot memory for structure
    cout << "Enter name of inflatable item: ";
    cin.get(ps->name, 20);            // method 1 for member access
    cout << "Enter volume in cubic feet: ";
    cin >> (*ps).volume;              // method 2 for member access
    cout << "Enter price: $";
    cin >> ps->price;
    cout << "Name: " << (*ps).name << endl;              // method 2
    cout << "Volume: " << ps->volume << " cubic feet\n"; // method 1
    cout << "Price: $" << ps->price << endl;             // method 1
    delete ps;                        // free memory used by structure
    // cin.get();
    // cin.get();
    return 0; 
}
[aaa@qq.com] chapter_4$ g++ newstrct.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
Enter name of inflatable item: Fabulous Frodo
Enter volume in cubic feet: 1.4
Enter price: $27.99
Name: Fabulous Frodo
Volume: 1.4 cubic feet
Price: $27.99
// delete.cpp -- using the delete operator
#include <iostream>
#include <cstring>      // or string.h
using namespace std;
char * getname(void);   // function prototype
int main()
{
    char * name;        // create pointer but no storage

    name = getname();   // assign address of string to name
    cout << name << " at " << (int *) name << "\n";
    delete [] name;     // memory freed

    name = getname();   // reuse freed memory
    cout << name << " at " << (int *) name << "\n";
    delete [] name;     // memory freed again
    // cin.get();
    // cin.get();
    return 0;
}

char * getname()        // return pointer to new string
{
    char temp[80];      // temporary storage
    cout << "Enter last name: ";
    cin >> temp;
    char * pn = new char[strlen(temp) + 1];
    strcpy(pn, temp);   // copy string into smaller space

    return pn;          // temp lost when function ends
}
[aaa@qq.com] chapter_4$ g++ delete.cpp 
[aaa@qq.com] chapter_4$ ./a.out 
Enter last name: Fredeldumpkin
Fredeldumpkin at 0x7fa64ed00000
Enter last name: Pook    
Pook at 0x7fa64ed00000

4.8.5 自动存储、静态存储和动态存储

根据分配内存的方法, C++有3种管理数据内存的方式

第4章 复合类型

4.9 类型组合

// mixtypes.cpp --some type combinations
#include <iostream>

struct antarctica_years_end
{
    int year;
 /* some really interesting data, etc. */
};

int main()
{
    antarctica_years_end s01, s02, s03; 
    s01.year = 1998;
    antarctica_years_end * pa = &s02;
    pa->year = 1999;
    antarctica_years_end trio[3]; // array of 3 structures
    trio[0].year = 2003;
    std::cout << trio->year << std::endl;
    const antarctica_years_end * arp[3] = {&s01, &s02, &s03};
    std::cout << arp[1]->year << std::endl;
    const antarctica_years_end ** ppa = arp; 
    auto ppb = arp; // C++0x automatic type deduction
// or else use const antarctica_years_end ** ppb = arp; 
    std::cout << (*ppa)->year << std::endl;
    std::cout << (*(ppb+1))->year << std::endl;
    // std::cin.get();
    return 0;
}
[aaa@qq.com] chapter_4$ g++ mixtypes.cpp 
mixtypes.cpp:22:5: warning: 'auto' type specifier is a C++11 extension [-Wc++11-extensions]
    auto ppb = arp; // C++0x automatic type deduction
    ^
1 warning generated.

4.10 数组的替代品

4.10.1 模版类vector

要使用vector对象,必须包含头文件vector,位于命名空间std种
是使用new创建动态数组的替代品

#include <vector>
using namespace std;
vector <in> vi;
vector<double> vd(n); //create an array of n double.

4.10.2 模版类array(C++11)

vector类的功能强大,但付出的代价效率低。
需要固定长度的数组,使用数组是更佳的选择,array对象长度固定,使用栈(静态内存分配),而不是*存储区

#include <array>
using namespace std;

array <int, 5> a; //create array object of 5 ints;
array <double, 4> ad = {1.2 ,2.3, 2.4, 2.5}

4.10.3 比较数组、vector对象和array对象

// choices.cpp -- array variations
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
int main()
{
    using namespace std;
// C, original C++
    double a1[4] = {1.2, 2.4, 3.6, 4.8};
// C++98 STL
    vector<double> a2(4);   // create vector with 4 elements
// no simple way to initialize in C98
    a2[0] = 1.0/3.0;
    a2[1] = 1.0/5.0;
    a2[2] = 1.0/7.0;
    a2[3] = 1.0/9.0;
// C++0x -- create and initialize array object
    array<double, 4> a3 = {3.14, 2.72, 1.62, 1.41};  
    array<double, 4> a4;
    a4 = a3;     // valid for array objects of same size
// use array notation
    cout << "a1[2]: " << a1[2] << " at " << &a1[2] << endl;
    cout << "a2[2]: " << a2[2] << " at " << &a2[2] << endl;
    cout << "a3[2]: " << a3[2] << " at " << &a3[2] << endl;
    cout << "a4[2]: " << a4[2] << " at " << &a4[2] << endl;
// misdeed
    a1[-2] = 20.2;
    cout << "a1[-2]: " << a1[-2] <<" at " << &a1[-2] << endl;
    cout << "a3[2]: " << a3[2] << " at " << &a3[2] << endl;
    cout << "a4[2]: " << a4[2] << " at " << &a4[2] << endl;
    //  cin.get();
    return 0;
}

第4章 复合类型

4.11 总结

第4章 复合类型

第4章 复合类型