C++ 学习笔记 -- 3

C++ Primer Plus 学习笔记


第四章:复合类型(上)

本章学习内容:

[TOC]

4.1 数组

数组可以储存多种同类型的值,要创建数组,可以使用声明语句,语句应指明以下3点:

  • 存储再每个元素中的值的类型;
  • 数组名;
  • 数组中的元素数。

数组的通用格式是:

TypeName ArrayName [ArraySize];

例如:

short months [12];   // create a array of 12 short

数组之所以被称为复合类型是因为它是由其他类型来创建的。数组中的每个元素可以单独调用,其计数方式是从0n-1

下面的例程展示了数组的使用方法和属性:

// arrayone.cpp -- samll array of integers
#include <iostream>

int main(int argc, char const *argv[])
{
    using namespace std;

    int yams [3];
    yams [0] = 7;
    yams [1] = 8;
    yams [2] = 6;

    int yamscost [3] =  {20, 30, 5};

    cout << "Total yams = " << yams [0] + yams[2] + yams[1];
    cout << endl;
    cout << "The package with " << yams [1] << " yams costs ";
    cout << yamscost[1] << " cent per yam. \n";
    int total = yams [0] * yamscost[0] + yams[1] * yamscost [1] + yams [2] * yamscost[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;
}

out:

Total yams = 21
The package with 8 yams costs 30 cent per yam.
The total yam expense is 410 cents.

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

4.1.1 数组初始化的规则

  • 只有定义数组的时候才可以对数组进行初始化,此后就不能再用了,且不能把数据赋值给另外一个数组。
int cards [4] {1, 2, 3, 4}; //allowed
int hands [4];              //allowed
hands = {5, 6, 7 ,8};       //not allowed   
hands = cards;              //not allowed
  • 初始化的时候赋值的个数可以小于数组元素的数目,比如:
float num[5] = {1, 2};

此时,只有数组中前两个数被赋值了,其他的数被置零。

  • 零数组,将数组中的所有元素置零。
float zeros [6] = {0};
  • 如果初始化时,方括号[]内为空,则C++编译器会计算元素的个数,如:
short things[] = {1, 5, 3, 8};

则编译器会将things中包含4个元素。

4.2 字符串

这里推荐使用以下的方式定义字符串变量:

char name[] = "Alex";

4.2.1 字符串与数组

下面的例程将演示数组和字符串的结合使用方法:

// strings.cpp -- store string in an array
#include <iostream>
#include <cstring>

int main(int argc, char *argv[])
{
    using namespace std;
    const int Size = 15;
    char name1[Size];   // empty array  
    char name2[Size] = "C++ Oldboy";// initialized array

    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";
    name2[3] = '\0';    // set to null character
    cout << "Your initial letter is " << name1[0] << endl;
    cout << "Here are the first three letter of my name: ";
    cout << name2 << endl;

    return 0;
}

out:

Howdy! I'm C++ OldboyWhat's your name? 
Dao
Well, Dao your name has 3 letters and is stored
in an array of 15 bytes.
Your initial letter is D
Here are the first three letter of my name: C++

从程序的输出我们可以看出来,strlen()返回的是可见的字符串的长度,不包含\0。在程序中,我们将name2[3]设置为了\0因此虽然后面还有内容,但是不再显示。

4.2.2 字符串输入

使用cin作为字符串的输入的时候存在一些问题,下面的例程将反应出这个问题:

// cinproblem.cpp -- reading more than one thing

#include <iostream>

int main(int argc, char *argv[])
{
    using namespace std;
    const int ArSize = 20;
    char name[ArSize];
    char city[ArSize];

    cout << "What's your name? \n";
    cin >> name;
    cout << "Which city do you live in? \n";
    cin >> city;

    cout << "Okey, now I know you're " << name << " and you live in ";
    cout << city << endl;
    
    return 0;
}

out:

What's your name? 
TIM D
Which city do you live in? 
Okey, now I know you're TIM and you live in D

在上面的例程中,我输入了我的名字: TIM D 还没来得及输入我所居住的城市,程序就已经结束了。并且程序将我的名字记为了TIM,将我的城市记为了D。这是因为cin()使用空白(空格、制表符、换行符)作为确定字符串结束的位置,并自动在结尾添加空字符。

为了解决这个问题,istream中的类(如cin)提供了一些面向行的类成员函数:getline(), get()。这两个函数都是读取一行的输入,知道换行符。他们之间的区别是,getline()会丢弃换行符,而get()不会。

为了熟悉这两个函数的使用方法,下面给出了一个例程:

// instr.cpp -- read more than one word in getlin()

#include <iostream>
int main(int argc, char *argv[])
{
    using namespace std;
    const int ArSize = 20;
    char name[ArSize];
    char city[ArSize];

    cout << "What's your name? \n";
    cin.getline(name,ArSize);
    cout << "Which city do you live in? \n";
    cin.getline(city,ArSize);


    cout << "Okey, now I know you're " << name << " and you live in ";
    cout << city << endl;

    return 0;
}

out:

What's your name? 
TIM D
Which city do you live in? 
Suzhou
Okey, now I know you're TIM D and you live in Suzhou

getline()一次可以读取一行的输入信息,以换行符确定行尾,并将换行符变成空字符。

另外一种get()getline()的不同点就在于get()并不是以换行符结尾,而是会读取换行符。要实现getlin()的效果,我们可以使用cin.get(name, size).get()下面的例程将会展示get()的用法:

// instr.cpp -- read more than one word with get() & get()

#include <iostream>
int main(int argc, char *argv[])
{
    using namespace std;
    const int ArSize = 20;
    char name[ArSize];
    char city[ArSize];

    cout << "What's your name? \n";
    cin.get(name,ArSize).get();
    cout << "Which city do you live in? \n";
    cin.get(city,ArSize).get();


    cout << "Okey, now I know you're " << name << " and you live in ";
    cout << city << endl;

    return 0;
}

out:

What's your name? 
Which city do you live in? 
Suzhou
Okey, now I know you're TIM D and you live in Suzhou

但如果我们只使用cin.get()则会出现以下现象:

What's your name?
TIM D
Which city do you live in?
Okey, now I know you're TIM D and you live in

在我第一次输入后,便不再询问再次输入。书籍《C++ Primer Plus》推荐的输入方式是cin.get(),具体原因会在后面的章节中讲到。

4.3 String类介绍

string头文件中的string类是和字符串类型功能类似的存在。其好处是我们可以像处理变量一样,去处理strig。下面的例程演示了string的用法。

// strtype1.cpp -- using the C++ string class
#include <iostream>
#include <cstring>

int main(int argc, char *argv[])
{
    using namespace std;

    char animal1[20];
    char animal2[20] = "jaguar";
    string str1;
    string str2 = "panther";

    cout << "Enter a kind of feline." << endl;;
    cin.get(animal1,20).get();
    cout << "Enter another feline." << endl;
    cin >> str1;
    cout << "Here are some felines: " <<
    animal1 << " " << animal2 << " " <<
    str1 << " " << str2 << endl;
    cout << "The third letter in " << animal2 <<
    " is " << animal2[2] << endl;
    cout << "The third letter in " << str2 <<
    " is " << str2[2] << endl;

    return 0;
}

out:

Enter a kind of feline.
Tiger
Enter another feline.
Ocelot 
Here are some felines: Tiger jaguar Ocelot panther
The third letter in jaguar is g
The third letter in panther is n

string类相比使用char会有很多方便之处:

  • 无需声明长度,在使用cin >> str1;的时候,程序会自动调整str1的长度。
  • string可以进行赋值,string类的操作会比数组更加方便,一个数组不能赋值给另一个数组,但string可以。
string animal1 = "tiger";
char charr1[20] = "tiger";
string animal2;
char charr2[20];
animal2 = animal1;  //VALID
charr2 = charr1;    //INVALID
  • string类简化了字符串的合并操作。可以使用运算符+将两个string对象合并起来,还可以用+=将一个字符串添加到另一个string对象的结尾。
string str1 = "I LOVE";
string str2 = "U";
string str3;
str3 = str1 + str2;
str1 += str2;

则:

str3 = I LOVE U
str1 = I LOVE U

4.4 结构简介

4.4.1 结构例程

struct结构可以方便的存储多种不同类型的变量。下面的例程展示了struct的用法:

// structure.cpp -- a simple structrue.

#include <iostream>
#include <cmath>
using namespace std;

struct Classmates
{
    char name[20];
    float height;
    float weight;
    int student_num;
};

int main(int argc, char *argv[])
{
    Classmates Tim =
    {
        "Tim",  // name value of Tim  
        180,    // height value of Tim
        67,     // weight value of Tim
        02      // Tim's student number
    };
//Tim is a structure variable of type Classmats

    Classmates Tom =
    {
        "Tom",
        177,
        68,
        06
    };

    Classmates Lucas =
    {
        "Lucas",
        190,
        78,
        27
    };


    cout << "There are 3 people in the list"
          << " namely: \n" << Tom.name << endl
          << Tim.name << endl << Lucas.name 
          << endl<<endl;

    cout << "The hight of Lucas is " << Lucas.height
        << "\nThe student number of Tom is " << Tom.student_num
        << "\nThe weight of Tim is " << Tim.weight
        << endl;

    return 0;
}

out:

There are 3 people in the list namely:
Tom
Tim
Lucas

The hight of Lucas is 190
The student number of Tom is 6
The weight of Tim is 67

structure的声明可以放在main的前面也可以放在main函数内部。但,如果将结构声明放在函数内部,则结构只能够被这个函数调用,其他函数不可以使用。

4.4.2 结构的形式

在初始化结构的时候其形式与声明时不同,结构内部之间的变量以逗号(,)隔开,最后一个变量末尾没有逗号。比如:

    Classmates Lucas =
    {
        "Lucas",
        190,
        78,
        27
    };

他们分别表示为:

    结构名称 变量名称 =
    {
        成员1,
        成员2,
        成员3
    }

除了上面展示的,所有整型,浮点数,数组,字符串,string都可以是结构成员的类型。

4.4.3 结构初始化的其他方式

除了之前例程里展示的方式,下面还将介绍3种结构的初始化方式:

  • 将变量放在结束括号后:
struct Name
{
    char [20] first_name;
    char [20] last_name;
} Man1, Man2;   // 2 variables
  • 声明的同时初始化
struct Name
{
    char [20] first_name;
    char [20] last_name;
} Man1 =
{
    "Leonardo",
    "DaVince"
};
  • 声明时还可以省略结构名称:
struct  // no tag
{
    char [20] first_name;
    char [20] last_name;
} Man1; // a tructure variable

4.4.4 结构数组

结构数组的意思将数组作为一个结构的变量,这个变量中的每一个元素都可以作为一个单独的结构变量。这么说可能有点绕,那么看看例程吧:

// arrstruc.cpp -- an array of structures
#include <iostream>
struct inflatable
{
    char name[20];
    float volume;
    double price;
};
int main(int argc, char *argv[])
{
    using namespace std;
    inflatable guests[2] = // initializing an array of structs
        {
            {"Bambi", 0.5, 21.99},     // first structure in array
            {"Godzilla", 2000, 565.99} // second 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 cm. \n";

    return 0;
}

out:

The guests Bambi and Godzilla
have a combined volume of 2000.5cubic cm.

4.5 枚举

enum枚举工具提供了另外一种创建符号常量的方式,这种方式可以代替const。它还允许定义新类型,但必须按严格的限制进行。使用方式如下:

enum spectrum {red, orange, yellow,green, blue, violet, indigo, ultravilet}; //共8个值

上方的语句完成了两项任务:

  • spectrum成为新类型的名称;spectrum被称为枚举(enumeraton),就像struct变量被称为结构一样。
  • red, orange, yellow等作为符号常量,它们对应的整数值为:0-7。这些常量叫做枚举量(enumerator)。

一般来说,枚举量不用来计算。

枚举常用来代替const,使用方法如下:

enum {zero, null = 0, one, numero_uno = 1};
// zero 和 null 都是常量 0, one 和 number_uno 都是常量 1.
posted @ 2021-08-16 10:49  Alexbeast-CN  阅读(65)  评论(0)    收藏  举报