【第四章|复合数据类型】

作者在 2016-11-03 16:19:04 发布以下内容

4.1 数组

数组array是一种能够存储多个同类型的值的数据格式。每个值都存储在一个独立的数组元素中,计算机在内存中依次存储数组的各个元素,即连续内存(关于内存的知识请看计算机组成与体系结构)。由此,可以单独地访问数组元素,使用下标或者索引对元素进行编号即可(自0开始)。

注意:在调用数组元素时,下标不要溢出,否则程序异常。

创建数组需要声明三点:存储在每个元素中地值的类型;数组名称;数组中的元素个数。


typeName arrayName[arraySize]
arraySize指定元素数目,必须是整型常数或const值,也可以是常量表达式。总而言之其值是已知的,这点将在后面的代码中解释。



// 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; 
}
该段代码展示了数组的声明,初始化,赋值。


上面有两种初始化方式,一种是在声明时不进行初始化之后对每个元素进行赋值;第二种是使用{}进行初始化,但这种初始化方式只有在定义数组时才能使用。PS:无法将一个数组赋值给另一个数组。

若只对数组的一部分进行初始化,则其他元素设置为0.

若初始化数组时[arraySize]为[],则C++编译器根据元素个数计算长度。

ps: 数组的初始化也要考虑基础数据类型的赋值规则,对于不同类型与表示范围,要谨慎考虑数组的类型。


4.2 字符串

字符串时存储在内存的连续字节中的一系列字符,其意味着可以将字符串存储在char数组中,在C-风格字符串中,以空字符 null character 结尾,空字符被写作  \0 ,其ASCII码为0,用于标记字符串的结尾。


char dog[8] = {'a','b','c','d','e','f','g','h','i'};
char cat[8] = {'a','b','c','d','e','f','g','h','\0'};
两个都是char数组,但是只有第二个数组时字符串。空字符对于C-风格字符串而言至关重要。因为C++有很多处理字符串的函数都是逐个地处理字符串中地字符,直至空字符为止。


上述代码的初始化很冗杂,因此有一种更方便的方法:使用引号括起字符串(字符串常量/字符串字面值):


char bird[8]="Mr.Liu";
char fish[]="BuleFish";
用引号括起的字符串隐式地包括结尾的空字符,处理字符串的函数根据空字符的位置而不是数组长度。(请测试“Blue Fish”)


测试结果:在进行字符串初始化时,“Blue Fish”是可行的。通过观察局部变量,在字符串中的空格是ASCII码32,而空字符是ASCII码0。

但是在调试窗口输入时,即被cin获取时,空格被认为是空字符。(留做思考)

PS:""表示的是字符串常量; '  ' 表示的是字符常量。

/*******拼接字符串常量&在数组中使用字符串*******/


// 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;
}
 任何两个有空白(空格,制表符tab、换行符)分隔的字符串常量都将自动拼接为一个;拼接是不会在被链接的字符串之间添加空格,第二个字符串的第一个字符紧跟第一个字符串的最后一个字符——不包括\0,\0将会被第二个字符串的第一个字符取代——后面。


要将字符串存储到字符数组中,第一种是将数组初始化为字符串常量;第二种是将键盘或文件输入读入到数组中,请看上述代码。

cin通过空白(空格、制表符、换行符)来确定字符串的结束位置。

/*****为此,下面介绍getline()*******/


// 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; 
}
getline函数读取整行,通过回车键键入的换行符来确定输入结尾。该函数有两个参数:第一个参数用于存储输入行的数组的名称;第二个参数是要读取的字符数(若此参数为20,则函数最多读取19个字符,余下一个空间用于存储自动在结尾处添加的空字符)。


/*****与之类似,还有一个函数get******/


// 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; 
}
get函数有很多变体,其中一种变体的工作方式与getline类似,参数相同,但是不能读取并丢弃换行符,而是将其留在了输入队列中,即第二次调用时直接看见换行符,无法进行后续的读取。


get的另一种变体——cin.get()可以读取下一个字符。

参考上述代码。

getline与get函数的区别:getline使用更简单,而get哈市农户使得检查错误更加方便(为何停止,是因为换行符还是因为数组空间满了?)

PS:还有两个问题——读取空行、输入字符串比分配空间长。将在后面讨论。这类问题我平时也没碰到,希望诱人指点。

/******混合输入字符串与数字******/


// 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();
    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; 
}

00.png (上传于2016-11-03 16:19:04)
00.png

由此可见,输入数字之后,未能输入地址。why?当cin读取年份是,将回车键申城的换行符留在了输入队列中,其后的cin.getline()看到换行符后认为其是一个空行。应该在读取地址前读取并丢弃换行符,可以使用没有参数的get()与接受一个char参数的get()。


cin>>year;
cin.get;
//或者使用 cin.get(char);
也可以使用表达式cin>>year返回cin对象



(cin>>year).get();
//或者 (cin>>year).get(chr)


关于字符串

C++程序通常使用指针而不是数组来处理字符串



4.3 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; 
}
由上述代码可知:可以使用C-风格字符串来初始化string对象;可以使用cin将键盘输入存储到string对象中;可以使用cout显示string对象;可以使用数组表示法来访问存储在string对象中的字符。


string类的设计能自动处理string的大小,例如str1声明时是一个长度为0的string对象,但程序将输入读取到str1中时,将自动调整str1的长度。

string对象使用更方便安全。


// 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; 
}
赋值,拼接,附加都变得简洁。



// 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
 
    // 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
    int len2 = strlen(charr1);  // obtain length of charr1
 
    cout << "The string " << str1 << " contains "
         << len1 << " characters.\n";
    cout << "The string " << charr1 << " contains "
         << len2 << " characters.\n";
    // cin.get();

    return 0; 
}
该段代码对比了string类对string对象的操作与原本C-风格字符串的操作函数。


函数strcopy()将字符串复制到字符数组中;函数strcat()将 字符串 加到字符数组末尾。

而在string类的语法中,则方便简单。

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; 
}
无需赘言。


其他形式的字符串字面值则有空再补充了。

4.4 结构 简介

结构是一种比数组更灵活地数据格式,同一个结构可以存储多种类型的数据,使得比较复杂的信息结合体可以存放在一个结构中。

结构是用户定义的类型,而结构声明定义了这种类型的数据属性。

创建结构分为两步:声明结构描述(秒数并表示了能够存储在结构中的各种数据类型),然后按描述创建结构变量(结构数据对象)

// 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; 
}
结构的声明分为外部声明与内部声明。

// assgn_st.cpp -- assigning structures
#include <iostream>
struct inflatable
{
    char name[20];
    float volume;
    double price;
};
int main()
{
    using namespace std;
struct perks
{

}
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; }
将结构作为参数传递给函数;让函数返回一个结构;同类结构之间的赋值(成员赋值)


可以同时完成定义结构与创建结构变量的工作:

struct perks
{
    int key_number;
    char car[12];
}mr_simth, ms_jones;


struct perks
{
    int key_number;
    char car[12];
}mr_glitz =
{
    7;
    "packard";
};   //注意这里需要写分号
一般将定义与声明分开,便于阅读和理解。

还可以声明没有名称的变量——省略名称,同时定义一种结构类型和一个这种类型的变量

struct 
{
    int x;
    int y;
}position;
这种形式怎么说呢,鸡肋?

// 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; 
}
结构数组:创建元素为结构的数组,方法与创建基本类型数组完全相同,初始化可以结合初始化数组的规则——用逗号分隔每个元素的值,并将这些值用花括号括起。

上述代码展示了如何定义与创建结构数组并初始化。


4.5 共用体

共用体union是一种数据格式,可以存储不同的数据类型,但是只能同时存储其中的一种类型。

结构可以同时存储int、long 和 double,共用体只能存储int、long 或 double。

struct widget
{
char brand[20];
int type;
union id
  {
      long id_num;
      char id_char[20];
  }id_val;
}
...
widget prize;
...
if(prize.type==1)
  cin >>prize.id_val.id_num;
else
  cin >>prize.id_val.id_char;
由于共用体每次只能存储一个值,因此它必须由足够的空间来存储最大的成员,所以共用体的长度为其最大成员的长度。

上述代码显示了共用体的用途之一:当数据项有多种格式表示某项数据时,可以节省空间。

匿名共用体anonymous union 没有名称,使用时也有些许变化:

struct widget
{
  char brand[20];
  int type;
  union 
  {
    long id_num;
    char id_char[20];
  };
};
...
widget prize;
...
if(prize.type==1)
  cin >> prize.id_num;
else
  cin >> prize.id_char;
共用体常用于节省内存;也用于操作系统数据结构或硬件数据结构。


4.6 枚举
4.7 指针与自由存储空间
4.8 指针算术
4.9 类型组合
4.10 数组的替代模板类

C++PrimerPlus回顾 | 阅读 5695 次
文章评论,共0条
游客请输入验证码
浏览5962次
文章归档
最新评论