四、复合类型(数组、字符串、指针、数据结构、共用体、枚举)

本文详细介绍了C++中的数组,包括其声明、初始化规则、多维数组和数组与指针的关系。接着探讨了C++中的字符串,包括C风格字符串和C++的string类。指针部分讲解了指针的概念、指针算术运算、指针数组、指向指针的指针以及指针在函数中的使用。此外,还讨论了结构体,包括结构体的声明、初始化、作为函数参数以及结构体与数组的结合。最后,提到了共用体和枚举,解释了它们的用途和特性。

一、数组

数组(array)是一种数据格式,能够存储多个同类型的值。每个值都存储在一个独立的数组元素中,计算机在内存中依次存储数组的各个元素。

要创建数组,可使用声明语句。数组声明应指出以下三点:
♦ 存储在每个元素中的值的类型;
♦ 数组名;
♦ 数组中的元素数。
声明数组的通用格式如下:

typeName arryName[arrySize];

表达式arraySize指定元素数目,它必须是整型常数(如10)或const值,也可以是常量表达式(如8 * sizeof(int)),即其中所有的值在编译时都是已知的。具体地说,arraySize不能是变量,变量的值是在程序运行时设置的。然而,本章稍后将介绍如何使用new运算符来避开这种限制。

作为复合类型的数组
数组之所以被称为复合类型,是因为它是使用其他类型来创建的(C语言使用术语“派生类型”,但由于C++对类关系使用术语“派生”,所以它必须创建一个新术语)。不能仅仅将某种东西声明为数组,它必须是特定类型的数组。没有通用的数组类型,但存在很多特定的数组类型,如char数组或long数组。例如,请看下面的声明:
float loans[20];
loans的类型不是“数组”,而是“float数组”。这强调了loans数组是使用float类型创建的。

对于数组来说,访问数组的第一个元素,对应的数组下标是0;
在这里插入图片描述

1.数组初始化规则

1.只有在定义数组时才能使用初始化,此后就不能使用了,也不能将一个数组赋给另一个数组:

double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};

注意:大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。
2.初始化数组时,提供的值可以少于数组的元素数目:

double balance[5] = {1000.0, 2.0};

如果只对数组的一部分进行初始化,则编译器将把其他元素设置为0。

因此,将数组中所有的元素都初始化为0非常简单—只要显式地将第一个元素初始化为0,然后让编译器将其他元素都初始化为0即可:

double balance[5] = {0};

3.如果初始化数组时方括号内([ ])为空,C++编译器将计算元素个数。如:

double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};

通常,让编译器计算元素个数是种很糟的做法,因为其计数可能与您想象的不一样。例如,您可能不小心在列表中遗漏了一个值。然而,这种方法对于将字符数组初始化为一个字符串来说比较安全,很快您将明白这一点。如果主要关心的问题是程序,而不是自己是否知道数组的大小,则可以这样做:
int num_elements = sizeof(balance) / sizeof(double)

2.C++数组详解

1. 多维数组

如,下面的声明创建了一个三维 5 . 10 . 4 整型数组:

int threedim[5][10][4];

多维数组最简单的形式是二维数组。二维数组的理解可以参考X,Y坐标形式来理解,如 a[3][4]:

Column 0Column 1Column 2Column 3
Row 0a[0][0]a[0][1]a[0][2]a[0][3]
Row 1a[1][0]a[1][1]a[1][2]a[1][3]
Row 2a[2][0]a[2][1]a[2][2]a[2][3]

因此,数组中的每个元素是使用形式为 a[ i ][ j ] 的元素名称来标识的,其中 a 是数组名称,i 和 j 是唯一标识 a 中每个元素的下标。
初始化二维数组有两种方式:
1.内嵌 括号 {}

int a[3][4] = {  
 {0, 1, 2, 3} ,   /*  初始化索引号为 0 的行 */
 {4, 5, 6, 7} ,   /*  初始化索引号为 1 的行 */
 {8, 9, 10, 11}   /*  初始化索引号为 2 的行 */
};

2.没有内嵌 括号 {}

int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

两种方式是一样效果的。

2.C++ 指向数组的指针

数组名是指向数组中第一个元素的常量指针。因此,在下面的声明中:

double buff[50];

buff 是一个指向 &buff[0] 的指针,即数组 buff 的第一个元素的地址。因此,下面的程序片段把 p 赋值为 buff 的第一个元素的地址:

double *p;
double buff[10];
p = buff;

使用数组名作为常量指针是合法的,反之亦然。
因此,*(buff+ 4) 是一种访问 buff[4] 数据的合法方式。

一旦您把第一个元素的地址存储在 p 中,您就可以使用 * p、* (p+1)、* (p+2) 等来访问数组元素。下面的实例演示了上面讨论到的这些概念:

#include <iostream>
using namespace std;
 
int main ()
{
   // 带有 5 个元素的双精度浮点型数组
   double buff[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
   double *p;
 
   p = buff;
 
   // 输出数组中每个元素的值
   cout << "使用指针的数组值 " << endl; 
   for ( int i = 0; i < 5; i++ )
   {
       cout << "*(p + " << i << ") : ";
       cout << *(p + i) << endl;
   }
 
   cout << "使用 buff作为地址的数组值 " << endl;
   for ( int i = 0; i < 5; i++ )
   {
       cout << "*(buff+ " << i << ") : ";
       cout << *(buff+ i) << endl;
   }
 
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

使用指针的数组值
*(p + 0) : 1000
*(p + 1) : 2
*(p + 2) : 3.4
*(p + 3) : 17
*(p + 4) : 50
使用 runoobAarray 作为地址的数组值
*(runoobAarray + 0) : 1000
*(runoobAarray + 1) : 2
*(runoobAarray + 2) : 3.4
*(runoobAarray + 3) : 17
*(runoobAarray + 4) : 50

3.C++ 传递数组给函数

C++ 中您可以通过指定不带索引的数组名来传递一个指向数组的指针。

C++ 传数组给一个函数,数组类型自动转换为指针类型,因而传的实际是地址。

如果您想要在函数中传递一个一维数组作为参数,您必须以下面三种方式来声明函数形式参数,这三种声明方式的结果是一样的,因为每种方式都会告诉编译器将要接收一个整型指针。同样地,您也可以传递一个多维数组作为形式参数。

方式 1
形式参数是一个指针:

void myFunction(int *param)
{
.
.
}

方式 2
形式参数是一个已定义大小的数组:

void myFunction(int param[10])
{
.
.
}

方式 3
形式参数是一个未定义大小的数组:

void myFunction(int param[])
{
.
.
}

实例
该函数把数组作为参数,同时还传递了另一个参数,根据所传的参数,会返回数组中各元素的平均值:

#include <iostream>
using namespace std;
 
// 函数声明
double getAverage(int arr[], int size);
 
int main ()
{
   // 带有 5 个元素的整型数组
   int balance[5] = {1000, 2, 3, 17, 50};
   double avg;
 
   // 传递一个指向数组的指针作为参数
   avg = getAverage( balance, 5 ) ;
 
   // 输出返回值
   cout << "平均值是:" << avg << endl; //输出214.4
    
   return 0;
}

double getAverage(int arr[], int size)
{
  int    i, sum = 0;       
  double avg;          
 
  for (i = 0; i < size; ++i)
  {
    sum += arr[i];
   }
 
  avg = double(sum) / size;
 
  return avg;
}

就函数而言,数组的长度是无关紧要的,因为 C++ 不会对形式参数执行边界检查。

4.C++ 从函数返回数组

C++ 不允许返回一个完整的数组作为函数的参数。
但是,您可以通过指定不带索引的数组名来返回一个指向数组的指针。

如果您想要从函数返回一个一维数组,您必须声明一个返回指针的函数,如下:

int * myFunction()
{
.
.
}

另外,C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。

现在,让我们来看下面的函数,它会生成 10 个随机数,并使用数组来返回它们,具体如下:

#include <iostream>
#include <cstdlib>
#include <ctime>
 
using namespace std;
 
// 要生成和返回随机数的函数
int * getRandom( )
{
  static int  r[10];
 
  // 设置种子
  srand( (unsigned)time( NULL ) );
  for (int i = 0; i < 10; ++i)
  {
    r[i] = rand();
    cout << r[i] << endl;
  }
 
  return r;
}
 
// 要调用上面定义函数的主函数
int main ()
{
   // 一个指向整数的指针
   int *p;
 
   p = getRandom();
   for ( int i = 0; i < 10; i++ )
   {
       cout << "*(p + " << i << ") : ";
       cout << *(p + i) << endl;
   }
 
   return 0;
}

编译结果
624723190
1468735695
807113585
976495677
613357504
1377296355
1530315259
1778906708
1820354158
667126415
*(p + 0) : 624723190
*(p + 1) : 1468735695
*(p + 2) : 807113585
*(p + 3) : 976495677
*(p + 4) : 613357504
*(p + 5) : 1377296355
*(p + 6) : 1530315259
*(p + 7) : 1778906708
*(p + 8) : 1820354158
*(p + 9) : 667126415

二、字符串

C++ 提供了以下两种类型的字符串表示形式:
♦ C 风格字符串
♦ C++ 引入的 string 类类型

1.C风格字符串

C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。
字符串实际上是使用null 字符 \0 终止的一维字符数组。
因此,一个以 null 结尾的字符串,包含了组成字符串的字符。

下面的声明和初始化创建了一个 RUNOOB 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 RUNOOB 的字符数多一个。

char site[7] = {'R', 'U', 'N', 'O', 'O', 'B', '\0'};

依据数组初始化规则,可以把上面的语句写成以下语句:

char site[] = "RUNOOB";

以下是 C/C++ 中定义的字符串的内存表示:
在这里插入图片描述其实,不需要把 null 字符放在字符串常量的末尾。C++ 编译器会在初始化数组时,自动把 \0 放在字符串的末尾

C++ 中有大量的函数用来操作以 null 结尾的字符串:

序号函数&目的
1strcpy(s1, s2); 复制字符串 s2 到字符串 s1。
2strcat(s1, s2); 连接字符串 s2 到字符串 s1 的末尾。连接字符串也可以用 + 号,例如:
string str1 = “runoob”;
string str2 = “google”;
string str = str1 + str2;
3strlen(s1); 返回字符串 s1 的长度。
4strcmp(s1, s2); 如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。
5strchr(s1, ch);返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
6strstr(s1, s2);返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。

实例

#include <iostream>
#include <cstring>
 
using namespace std;
 
int main ()
{
   char str1[13] = "runoob";
   char str2[13] = "google";
   char str3[13];
   int  len ;
 
   // 复制 str1 到 str3
   strcpy( str3, str1);
   cout << "strcpy( str3, str1) : " << str3 << endl;//输出 runoob
 
   // 连接 str1 和 str2
   strcat( str1, str2);
   cout << "strcat( str1, str2): " << str1 << endl;//输出 runoobgoogle
 
   // 连接后,str1 的总长度
   len = strlen(str1);
   cout << "strlen(str1) : " << len << endl;// 输出 12
 
   return 0;
}

2.C++中的String类

C++ 标准库提供了 string 类类型,支持上述所有的操作,另外还增加了其他更多的功能。
我们将学习 C++ 标准库中的这个类,现在让我们先来看看下面这个实例:

现在您可能还无法透彻地理解这个实例,因为到目前为止我们还没有讨论类和对象。所以现在您可以只是粗略地看下这个实例,等理解了面向对象的概念之后再回头来理解这个实例。

#include <iostream>
#include <string>
 
using namespace std;
 
int main ()
{
   string str1 = "runoob";
   string str2 = "google";
   string str3;
   int  len ;
 
   // 复制 str1 到 str3
   str3 = str1;
   cout << "str3 : " << str3 << endl;//输出 str3 : runoob
 
   // 连接 str1 和 str2
   str3 = str1 + str2;
   cout << "str1 + str2 : " << str3 << endl;//输出 str1 + str2 : runoobgoogle
 
   // 连接后,str3 的总长度
   len = str3.size();
   cout << "str3.size() :  " << len << endl;//输出 str3.size() :  12
 
   return 0;
}

这个实例,可以看到相比于C风格的字符串,str1 , str2,str3定义的类型是string类型,同时在输出时,直接 对 str1 + str2,进行操作,可以先简单理解为string 是一个==“库”==,可以直接进行调用。

关于string类的相关信息

ISO/ANSI C++98标准通过添加string类扩展了C++库,因此现在可以string类型的变量(使用C++的话说是对象)而不是字符数组来存储字符串。
string类使用起来比数组简单,同时提供了将字符串作为一种数据类型的表示方法。

要使用string类,必须在程序中包含头文件string
string类位于名称空间std中,因此必须提供一条using编译指令,或者使用std::string来引用它。
string类定义隐藏了字符串的数组性质,让您能够像处理普通变量那样处理字符串。
下面实例说明了string对象与字符数组之间的一些相同点和不同点。

#include <iostream>
#include <string>
 
using namespace std;
 
int main ()
{
  char chr1[20];
  char chr2[20]="abc";
  string str1 ;
  string str2 = "def";


  cout << "Enter a kind of feline : " ;
  cin >> chr1;
  cout << "Enter another kind of feline : " ;
  cin >> str1;

  cout << "Here are some feline: \n";
  cout << chr1 << " " << chr2 << " "
       << str1 << " " << str2 << endl;
  cout << "The third letter in " << chr2 << " is "
       << chr2[2] <<endl;
  cout << "The third letter in " << str2 << " is "
       << str2[2] <<endl;

   return 0;
}

运行情况:

Enter a kind of feline : qwe
Enter another kind of feline : asd
Here are some feline:
qwe abc asd def
The third letter in abc is c
The third letter in def is f

从这个示例可知,在很多方面,使用string对象的方式与使用字符数组相同。

♦ 可以使用C-风格字符串来初始化string对象。
♦ 可以使用cin来将键盘输入存储到string对象中。
♦ 可以使用cout来显示string对象。
♦ 可以使用数组表示法来访问存储在string对象中的字符。

string对象和字符数组之间的主要区别是,可以将string对象声明为简单变量,而不是数组:

string str1;
string str2="asd";

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

cin >> str1;

这使得与使用数组相比,使用string对象更方便,也更安全。
从理论上说,可以将char数组视为一组用于存储一个字符串的char存储单元,而string类变量是一个表示字符串的实体。

可以使用cin和运算符<<来将输入存储到string对象中,使用cout和运算符<<来显示string对象,其句法与处理C-风格字符串相同。
但每次读取一行而不是一个单词时,使用的句法不同,下面实例说明了这一点

#include <iostream>
#include <string>
#include <cstring> 
using namespace std;
 
int main ()
{
  char chr1[20];
  string str1 ;


  cout << "Length of string in chr before input: " 
      << strlen(chr1) << endl;
  cout << "Length of string in str before input: " 
      << str1.size() << endl;

  cout << "Enter a line of text : " ;
  cin.getline(chr1,20);
  cout << "You entered: " << chr1 << endl;

  cout << "Enter another line of text : " ;
  getline(cin,str1);
  cout << "You entered: " << str1 << endl;

  cout << "Length of string in chr after input: " 
      << strlen(chr1) << endl;
  cout << "Length of string in str after input: " 
      << str1.size() << endl;

   return 0;
}

运行情况:

Length of string in chr before input: 1
Length of string in str before input: 0
Enter a line of text : qwer
You entered: qwer
Enter another line of text : asdfgh
You entered: asdfgh
Length of string in chr after input: 4
Length of string in str after input: 6

在用户输入之前,该程序指出数组charr中的字符串长度为1。
这里要两点需要说明。首先,为初始化的数组的内容是未定义的;其次,函数strlen( )从数组的第一个元素开始计算字节数,直到遇到空字符。
对于未被初始化的数据,第一个空字符的出现位置是随机的,因此您在运行该程序时,得到的数组长度很可能与此不同。
另外,用户输入之前,str中的字符串长度为0。这是因为未被初始化的string对象的长度被自动设置为0。

下面是将一行输入读取到数组中的代码

 cin.getline(chr1,20);

这种句点表示法表明,函数getline( )是istream类的一个类方法(还记得吗,cin是一个istream对象)。正如前面指出的,第一个参数是目标数组;第二个参数数组长度,getline( )使用它来避免超越数组的边界。

下面是将一行输入读取到string对象中的代码

  getline(cin,str1);

这里没有使用句点表示法,这表明这个getline( )不是类方法。它将cin作为参数,指出到哪里去查找输入。另外,也没有指出字符串长度的参数,因为string对象将根据字符串的长度自动调整自己的大小。

三、C++指针

学习 C++ 的指针既简单又有趣。通过指针,可以简化一些 C++ 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。所以,想要成为一名优秀的 C++ 程序员,学习指针是很有必要的。

正如您所知道的,每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。请看下面的实例,它将输出定义的变量地址:

#include <iostream>
 
using namespace std;
 
int main ()
{
   int  var1;
   char var2[10];
 
   cout << "var1 变量的地址: ";//var1 变量的地址: 0xbfebd5c0
   cout << &var1 << endl;
 
   cout << "var2 变量的地址: ";//var2 变量的地址: 0xbfebd5b6
   cout << &var2 << endl;
 
   return 0;
}

1.什么是指针?

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

type *var-name;

在这里,type 是指针的基类型,它必须是一个有效的 C++ 数据类型,var-name 是指针变量的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号(*)是用来指定一个变量是指针。以下是有效的指针声明:

int    *ip;    /* 一个整型的指针 */
double *dp;    /* 一个 double 型的指针 */
float  *fp;    /* 一个浮点型的指针 */
char   *ch;    /* 一个字符型的指针 */

所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

2.C++中使用指针

使用指针时会频繁进行以下几个操作:
♦ 定义一个指针变量
♦ 把变量地址赋值给指针
♦ 访问指针变量中可用地址的值
这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。下面的实例涉及到了这些操作:

#include <iostream>
 
using namespace std;
 
int main ()
{
   int  var = 20;   // 实际变量的声明
   int  *ip;        // 指针变量的声明
 
   ip = &var;       // 在指针变量中存储 var 的地址
 
   cout << "Value of var variable: ";//输出 Value of var variable: 20
   cout << var << endl;
 
   // 输出在指针变量中存储的地址
   cout << "Address stored in ip variable: ";//输出 Address stored in ip variable: 0xbfc601ac
   cout << ip << endl;
 
   // 访问指针中地址的值
   cout << "Value of *ip variable: "; //输出 Value of *ip variable: 20
   cout << *ip << endl;
 
   return 0;
}

3.C++指针详解

在 C++ 中,有很多指针相关的概念,这些概念都很简单,但是都很重要。下面列出了 C++ 程序员必须清楚的一些与指针相关的重要概念:

概念描述
C++ Null 指针C++ 支持空指针。NULL 指针是一个定义在标准库中的值为零的常量。
C++ 指针的算术运算可以对指针进行四种算术运算:++、–、+、-
C++ 指针 vs 数组指针和数组之间有着密切的关系。
C++ 指针数组可以定义用来存储指针的数组。
C++ 指向指针的指针C++ 允许指向指针的指针。
C++ 传递指针给函数通过引用或地址传递参数,使传递的参数在调用函数中被改变。
C++ 从函数返回指针C++ 允许函数返回指针到局部变量、静态变量和动态内存分配。

1.C++ Null指针

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。

NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:

#include <iostream>

using namespace std;

int main ()
{
   int  *ptr = NULL;

   cout << "ptr 的值是 " << ptr ;//输出 ptr 的值是 0
 
   return 0;
}

在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。
然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置
但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。

如需检查一个空指针,可以使用 if 语句,如下所示:

if(ptr)     /* 如果 ptr 非空,则完成 */
if(!ptr)    /* 如果 ptr 为空,则完成 */

因此,如果所有未使用的指针都被赋予空值,同时避免使用空指针,就可以防止误用一个未初始化的指针。
很多时候,未初始化的变量存有一些垃圾值,导致程序难以调试。

2.C++ 指针的算术运算

指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、–、+、-。

假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:

ptr++

在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。
如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。

♦ 递增一个指针
我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,因为数组是一个常量指针。下面的程序递增变量指针,以便顺序访问数组中的每一个元素:

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;
 
   // 指针中的数组地址
   ptr = var;
   for (int i = 0; i < MAX; i++)
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;
 
      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;
 
      // 移动到下一个位置
      ptr++;
   }
   return 0;
}

运行结果
Address of var[0] = 0xbfa088b0
Value of var[0] = 10
Address of var[1] = 0xbfa088b4
Value of var[1] = 100
Address of var[2] = 0xbfa088b8
Value of var[2] = 200

♦ 递减一个指针
同样地,对指针进行递减运算,即把值减去其数据类型的字节数,如下所示:

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;
 
   // 指针中最后一个元素的地址
   ptr = &var[MAX-1];
   for (int i = MAX; i > 0; i--)
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;
 
      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;
 
      // 移动到下一个位置
      ptr--;
   }
   return 0;
}

运行结果
Address of var[3] = 0xbfdb70f8
Value of var[3] = 200
Address of var[2] = 0xbfdb70f4
Value of var[2] = 100
Address of var[1] = 0xbfdb70f0
Value of var[1] = 10

♦ 指针的比较
指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。

下面的程序修改了上面的实例,只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1],则把变量指针进行递增:

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;
 
   // 指针中第一个元素的地址
   ptr = var;
   int i = 0;
   while ( ptr <= &var[MAX - 1] )
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;
 
      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;
 
      // 指向上一个位置
      ptr++;
      i++;
   }
   return 0;
}

运行结果
Address of var[0] = 0xbfce42d0
Value of var[0] = 10
Address of var[1] = 0xbfce42d4
Value of var[1] = 100
Address of var[2] = 0xbfce42d8
Value of var[2] = 200

3.C++ 指针 vs 数组

指针和数组是密切相关的,事实上,指针和数组在很多情况下是可以互换的
例如,一个指向数组开头的指针,可以通过使用指针的算术运算或数组索引来访问数组。请看下面的程序:

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;
 
   // 指针中的数组地址
   ptr = var;
   for (int i = 0; i < MAX; i++)
   {
      cout << "var[" << i << "]的内存地址为 ";
      cout << ptr << endl;
 
      cout << "var[" << i << "] 的值为 ";
      cout << *ptr << endl;
 
      // 移动到下一个位置
      ptr++;
   }
   return 0;
}

运行结果
var[0]的内存地址为 0x7fff59707adc
var[0] 的值为 10
var[1]的内存地址为 0x7fff59707ae0
var[1] 的值为 100
var[2]的内存地址为 0x7fff59707ae4
var[2] 的值为 200

【注意】:指针和数组并不是完全互换的。例如,请看下面的程序:

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
 
   for (int i = 0; i < MAX; i++)
   {
      *var = i;    // 这是正确的语法 对var[0]赋值0
      var++;       // 这是不正确的
   }
   return 0;
}

把指针运算符 * 应用到 var 上是完全可以的,但修改 var 的值是非法的
这是因为 var 是一个指向数组开头的常量,不能作为左值。

由于一个数组名对应一个指针常量,只要不改变数组的值,仍然可以用指针形式的表达式。例如,下面是一个有效的语句,把 var[2] 赋值为 500:

*(var + 2) = 500;

4.C++ 指针数组

在我们讲解指针数组的概念之前,先让我们来看一个实例,它用到了一个由 3 个整数组成的数组:

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
 
   for (int i = 0; i < MAX; i++)
   {
      cout << "Value of var[" << i << "] = ";
      cout << var[i] << endl;
   }
   return 0;
}

运行结果
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200

可能有一种情况,我们想要让数组存储指向 int 或 char 或其他数据类型的指针。下面是一个指向整数的指针数组的声明:

int *ptr[MAX];

在这里,把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 int 值的指针。下面的实例用到了三个整数,它们将存储在一个指针数组中,如下所示:

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int *ptr[MAX];
 
   for (int i = 0; i < MAX; i++)
   {
      ptr[i] = &var[i]; // 赋值为整数的地址
   }
   for (int i = 0; i < MAX; i++)
   {
      cout << "Value of ptr[" << i << "] = ";
      cout << *ptr[i] << endl;
   }
   return 0;
}

运行结果
Value of ptr[0] = 10
Value of ptr[1] = 100
Value of ptr[2] = 200

也可以用一个指向字符的指针数组来存储一个字符串列表,如下:

#include <iostream>
 
using namespace std;
const int MAX = 4;
 
int main ()
{
 const char *names[MAX] = {
                   "Zara Ali",
                   "Hina Ali",
                   "Nuha Ali",
                   "Sara Ali",
   };
 
   for (int i = 0; i < MAX; i++)
   {
      cout << "Value of names[" << i << "] = ";
      cout << names[i] << endl;
   }
   return 0;
}

运行结果
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali

5.C++ 指向指针的指针

指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。

指针的指针就是将指针的地址存放在另一个指针里面

通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
在这里插入图片描述一个指向指针的指针变量必须如下声明,即在变量名前放置两个星号。例如,下面声明了一个指向 int 类型指针的指针:

int **var;

当一个目标值被一个指针间接指向到另一个指针时,访问这个值需要使用两个星号运算符,如下面实例所示:

#include <iostream>
 
using namespace std;
 
int main ()
{
    int  var;
    int  *ptr;
    int  **pptr;
 
    var = 3000;
 
    // 获取 var 的地址
    ptr = &var;
 
    // 使用运算符 & 获取 ptr 的地址
    pptr = &ptr;
 
    // 使用 pptr 获取值
    cout << "var 值为 :" << var << endl;
    cout << "*ptr 值为:" << *ptr << endl;
    cout << "**pptr 值为:" << **pptr << endl;
 
    return 0;
}

运行结果
var 值为 :3000
*ptr 值为:3000
**pptr 值为:3000

6.C++ 传递指针给函数

C++ 允许您传递指针给函数,只需要简单地声明函数参数为指针类型即可。

下面的实例中,我们传递一个无符号的 long 型指针给函数,并在函数内改变这个值:

#include <iostream>
#include <ctime>
 
using namespace std;
 
// 在写函数时应习惯性的先声明函数,然后在定义函数
void getSeconds(unsigned long *par);
 
int main ()
{
   unsigned long sec;
 
 
   getSeconds( &sec );
 
   // 输出实际值
   cout << "Number of seconds :" << sec << endl;
 
   return 0;
}
 
void getSeconds(unsigned long *par)
{
   // 获取当前的秒数
   *par = time( NULL );
   return;
}

运行结果
Number of seconds :1294450468

能接受指针作为参数的函数,也能接受数组作为参数,如下所示:

#include <iostream>
using namespace std;
 
// 函数声明
double getAverage(int *arr, int size);
 
int main ()
{
   // 带有 5 个元素的整型数组
   int balance[5] = {1000, 2, 3, 17, 50};
   double avg;
 
   // 传递一个指向数组的指针作为参数
   avg = getAverage( balance, 5 ) ;
 
   // 输出返回值
   cout << "Average value is: " << avg << endl; 
    
   return 0;
}
 
double getAverage(int *arr, int size)
{
  int    i, sum = 0;       
  double avg;          
 
  for (i = 0; i < size; ++i)
  {
    sum += arr[i];
   }
 
  avg = double(sum) / size;
 
  return avg;
}

运行结果
Average value is: 214.4

7.C++ 从函数返回指针

在C++从函数返回数组小节中,已了解C++ 中如何从函数返回数组,类似地,C++ 允许您从函数返回指针。为了做到这点,您必须声明一个返回指针的函数,如下所示:

int * myFunction()
{
.
.
}

另外,C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static变量

现在,让我们来看下面的函数,它会生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下:

#include <iostream>
#include <ctime>
#include <cstdlib>
 
using namespace std;
 
// 要生成和返回随机数的函数
int * getRandom( )
{
  static int  r[10];
 
  // 设置种子
  srand( (unsigned)time( NULL ) );
  for (int i = 0; i < 10; ++i)
  {
    r[i] = rand();
    cout << r[i] << endl;
  }
 
  return r;
}
 
// 要调用上面定义函数的主函数
int main ()
{
   // 一个指向整数的指针
   int *p;
 
   p = getRandom();
   for ( int i = 0; i < 10; i++ )
   {
       cout << "*(p + " << i << ") : ";
       cout << *(p + i) << endl;
   }
 
   return 0;
}

运行结果
624723190
1468735695
807113585
976495677
613357504
1377296355
1530315259
1778906708
1820354158
667126415
*(p + 0) : 624723190
*(p + 1) : 1468735695
*(p + 2) : 807113585
*(p + 3) : 976495677
*(p + 4) : 613357504
*(p + 5) : 1377296355
*(p + 6) : 1530315259
*(p + 7) : 1778906708
*(p + 8) : 1820354158
*(p + 9) : 667126415

四、数据结构(结构体)

C/C++ 数组允许定义可存储相同类型数据项的变量,但是结构是 C++ 中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。

C++中的结构的可以满足要求(存储篮球运动员的信息)。结构是一种比数组更灵活的数据格式,因为同一个结构可以存储多种类型的数据,这使得能够将有关篮球运动员的信息放在一个结构中,从而将数据的表示合并到一起。

struct inflatable
{
	char name[20];
	float volume;
	double price;
};

关键字struct表明,这些代码定义的是一个结构的布局。标识符inflatable是这种数据格式的名称,因此新类型的名称为inflatable。这样,便可以像创建char或int类型的变量那样创建inflatable类型的变量了。接下来的大括号中包含的是结构存储的数据类型的列表,其中每个列表项都是一条声明语句。这个例子使用了一个适合用于存储字符串的char数组、一个float和一个double。列表中的每一项都被称为结构成员,因此infatable结构有3个成员。总之,结构定义指出了新类型(这里是inflatable)的特征。
在这里插入图片描述定义结构后,便可以创建这种类型的变量了:

inflatable zhangsan;
inflatable lisi;

如果您熟悉C语言中的结构,则可能已经注意到了,C++允许在声明结构变量时省略关键字struct

struct inflatable zhangsan;	//在 c 中需要添加 struct
inflatable zhangsan;	//在 c++ 中不需要添加 struct

在C++中,结构标记的用法与基本类型名相同。这种变化强调的是,结构声明定义了一种新类型。在C++中,省略struct不会出错。

由于 zhangsan 的类型是 inflatable ,因此可以使用成员运算符(.)来访问各个成员。例如,zhangsan .volume指的是结构的volume成员,zhangsan .price指的是price成员。

1.结构体的用法

#include <iostream>
#include <cstring>
 
using namespace std;
 
// 声明一个结构体类型 Books 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   Books Book1;        // 定义结构体类型 Books 的变量 Book1
   Books Book2;        // 定义结构体类型 Books 的变量 Book2
 
   // Book1 详述
   strcpy( Book1.title, "C++ 教程");
   strcpy( Book1.author, "Runoob"); 
   strcpy( Book1.subject, "编程语言");
   Book1.book_id = 12345;
 
   // Book2 详述
   strcpy( Book2.title, "CSS 教程");
   strcpy( Book2.author, "Runoob");
   strcpy( Book2.subject, "前端技术");
   Book2.book_id = 12346;
 
   // 输出 Book1 信息
   cout << "第一本书标题 : " << Book1.title <<endl;
   cout << "第一本书作者 : " << Book1.author <<endl;
   cout << "第一本书类目 : " << Book1.subject <<endl;
   cout << "第一本书 ID : " << Book1.book_id <<endl;
 
   // 输出 Book2 信息
   cout << "第二本书标题 : " << Book2.title <<endl;
   cout << "第二本书作者 : " << Book2.author <<endl;
   cout << "第二本书类目 : " << Book2.subject <<endl;
   cout << "第二本书 ID : " << Book2.book_id <<endl;
 
   return 0;
}

实例中定义了结构体类型 Books 及其两个变量 Book1 和 Book2。当上面的代码被编译和执行时,它会产生下列结果:

第一本书标题 : C++ 教程
第一本书作者 : Runoob
第一本书类目 : 编程语言
第一本书 ID : 12345
第二本书标题 : CSS 教程
第二本书作者 : Runoob
第二本书类目 : 前端技术
第二本书 ID : 12346

2.结构体的初始化

和数组一样,使用由逗号分隔值列表,并将这些值用花括号括起。在该程序中,每个值占一行,但也可以将它们全部放在同一行中。只是应用逗号将它们分开:

inflatable duck = {"xiaoming" 0.12 9.98};

可以将结构的每个成员都初始化为适当类型的数据。例如,name成员是一个字符数组,因此可以将其初始化为一个字符串。

【注意】:在C++11中
与数组一样,C++11也支持将列表初始化用于结构,且等号(=)是可选的

inflatable duck  {"xiaoming" 0.12 9.98}; //在C++11中可以不加 = 号

其次,如果大括号内未包含任何东西,各个成员都将被设置为零。例如,下面的声明导致mayor.volume和mayor.price被设置为零,且mayor.name的每个字节都被设置为零:

inflatable mayor {}; 

最后,不允许缩窄转换

《缩窄转换》
C++11中的列表初始化禁止缩窄转换,关于缩窄转换的规则如下:
1.从浮点数转换为整数
2.从取值范围大的浮点数转换为取值范围小的浮点数(在编译期可以计算并且不会溢出的表达式除外)
3.从整数转换为浮点数(在编译期可以计算并且转换之后值不变的表达式除外)
4. 从取值范围大的整数转换为取值范围小的整数(在编译期可以计算并且不会溢出的表达式除外)

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

可以将成员name指定为string对象而不是字符数组吗?即可以像下面这样声明结构吗?

#include <string>
struct inflatable
{
	std:string name;
	float volume;
	double price;
};

答案是肯定的,只要您使用的编译器支持对以string对象作为成员的结构进行初始化。

一定要让结构定义能够访问名称空间std。为此,可以将编译指令using移到结构定义之前;也可以像上面那样,将name的类型声明为std::string。

4. 其他结构属性

C++使用户定义的类型与内置类型尽可能相似。例如,可以将结构作为参数传递给函数,也可以让函数返回一个结构。另外,还可以使用赋值运算符(=)将结构赋给另一个同类型的结构,这样结构中每个成员都将被设置为另一个结构中相应成员的值,即使成员是数组。

1.成员赋值 & 创建结构

示例:

#include <iostream>
using namespace std;
 
 struct inflatable
 {
    char name[20];
    float volume;
    double price;
 };
 
int main( )
{
   inflatable bounquet =
   {
      "sunflowers",
      0.20,
      12.49
   };
   inflatable choice;

   cout << "bounquet :" << bounquet.name << "for $";
   cout << bounquet.price <<endl;

   choice =  bounquet;
   cout << "choice :" << choice.name << "for $";
   cout << choice.price <<endl;

   return 0;
}

运行结果
bounquet :sunflowersfor $12.49
choice :sunflowersfor $12.49

从中可以看出,成员赋值是有效的,因为choice结构的成员值与bouquet结构中存储的值相同。

可以同时完成定义结构和创建结构变量的工作。为此,只需将变量名放在结束括号的后面即可:

struct perks
{
   int key_num;
   char car[12];
}mr_smith,ms_jones;

甚至可以初始化以这种方式创建的变量:

struct perks
{
   int key_num;
   char car[12];
}mr_smith=
{
	7,
	"packcard"
};

然而,将结构定义和变量声明分开,可以使程序更易于阅读和理解。

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

struct 
{
   int x;
   int y;
}mr_smith;

这样将创建一个名为mr_smith的结构变量。可以使用成员运算符来访问它的成员(如mr_smith.x),但这种类型没有名称,因此以后无法创建这种类型的变量

2.结构作为函数参数

您可以把结构作为函数参数,传参方式与其他类型的变量或指针类似。您可以使用下面实例中的方式来访问结构变量:

#include <iostream>
#include <cstring>
 
using namespace std;
void printBook( struct Books book );
 
// 声明一个结构体类型 Books 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   Books Book1;        // 定义结构体类型 Books 的变量 Book1
   Books Book2;        // 定义结构体类型 Books 的变量 Book2
 
    // Book1 详述
   strcpy( Book1.title, "C++ 教程");
   strcpy( Book1.author, "Runoob"); 
   strcpy( Book1.subject, "编程语言");
   Book1.book_id = 12345;
 
   // Book2 详述
   strcpy( Book2.title, "CSS 教程");
   strcpy( Book2.author, "Runoob");
   strcpy( Book2.subject, "前端技术");
   Book2.book_id = 12346;
 
   // 输出 Book1 信息
   printBook( Book1 );
 
   // 输出 Book2 信息
   printBook( Book2 );
 
   return 0;
}
void printBook( struct Books book )
{
   cout << "书标题 : " << book.title <<endl;
   cout << "书作者 : " << book.author <<endl;
   cout << "书类目 : " << book.subject <<endl;
   cout << "书 ID : " << book.book_id <<endl;
}

运行结果:
书标题 : C++ 教程
书作者 : Runoob
书类目 : 编程语言
书 ID : 12345
书标题 : CSS 教程
书作者 : Runoob
书类目 : 前端技术
书 ID : 12346

3.指向结构的指针

您可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似,如下所示:

struct Books *struct_pointer;

现在,您可以在上述定义的指针变量中存储结构变量的地址。为了查找结构变量的地址,请把 & 运算符放在结构名称的前面,如下所示:

struct_pointer = &Book1;

为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,如下所示:

struct_pointer->title;

让我们使用结构指针来重写上面的实例,这将有助于您理解结构指针的概念:

#include <iostream>
#include <cstring>
 
using namespace std;
void printBook( struct Books *book );
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   Books Book1;        // 定义结构体类型 Books 的变量 Book1
   Books Book2;        // 定义结构体类型 Books 的变量 Book2
 
    // Book1 详述
   strcpy( Book1.title, "C++ 教程");
   strcpy( Book1.author, "Runoob"); 
   strcpy( Book1.subject, "编程语言");
   Book1.book_id = 12345;
 
   // Book2 详述
   strcpy( Book2.title, "CSS 教程");
   strcpy( Book2.author, "Runoob");
   strcpy( Book2.subject, "前端技术");
   Book2.book_id = 12346;
 
   // 通过传 Book1 的地址来输出 Book1 信息
   printBook( &Book1 );
 
   // 通过传 Book2 的地址来输出 Book2 信息
   printBook( &Book2 );
 
   return 0;
}
// 该函数以结构指针作为参数
void printBook( struct Books *book )
{
   cout << "书标题  : " << book->title <<endl;
   cout << "书作者 : " << book->author <<endl;
   cout << "书类目 : " << book->subject <<endl;
   cout << "书 ID : " << book->book_id <<endl;
}

运行结果
书标题 : C++ 教程
书作者 : Runoob
书类目 : 编程语言
书 ID : 12345
书标题 : CSS 教程
书作者 : Runoob
书类目 : 前端技术
书 ID : 12346

typedef 关键字
下面是一种更简单的定义结构的方式,您可以为创建的类型取一个"别名"。例如:

typedef struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
}Books;

现在,您可以直接使用 Books 来定义 Books 类型的变量,而不需要使用 struct 关键字。下面是实例:

Books Book1, Book2;

也可以使用 typedef 关键字来定义非结构类型,如下所示:

typedef long int *pint32;
 
pint32 x, y, z;

x, y 和 z 都是指向长整型 long int 的指针。

5.结构数组

inflatable结构包含一个数组(name)。也可以创建元素为结构的数组,方法和创建基本类型数组完全相同。例如,要创建一个包含100个inflatable结构的数组,可以这样做:

inflatable gifts[100];

这样,gifts将是一个inflatable数组,其中的每个元素(如gifts[0]或gifts[99])都是inflatable对象,可以与成员运算符一起使用:

cin >> gifts[0].volume;
cout << gifts[99].price <<endl;

记住,gifts本身是一个数组,而不是结构,因此像gifts.price这样的表述是无效的。

6.结构中的位字段

与C语言一样,C++也允许指定占用特定位数的结构成员,这使得创建与某个硬件设备上的寄存器对应的数据结构非常方便。
字段的类型应为整型或枚举(稍后将介绍),接下来是冒号,冒号后面是一个数字,它指定了使用的位数。可以使用没有名称的字段来提供间距。每个成员都被称为位字段(bit field)。
下面是一个例子:

struct torgle-register
{
	unsigned int SN:4;// 4位表示SN值
	unsigned int :4;//4位未使用
	bool goodIn :1;	//有效输入(1位)
	bool goodTorgle :1;
};

五、共用体

共用体(union)是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。也就是说,结构可以同时存储 int、long和double,共用体只能存储int、long double。共用体的句法与结构相似,但含义不同。例如,请看下面的声明:

union one4all
{
	int int_val;
	long long_val;
	double double_val;
};

可以使用 one4all 变量来存储 int、long或double,条件是在不同的时间进行:

one4all pail;
pail.int_val = 5;
cout << pail.int_val;
pail.double_val= 1.52;
cout << pail.double_val;

因此,pail有时可以是int变量,而有时又可以是double变量。成员名称标识了变量的容量。由于共用体每次只能存储一个值,因此它必须有足够的空间来存储最大的成员,所以,共用体的长度为其最大成员的长度
共用体的用途之一是,当数据项使用两种或更多种格式(但不会同时使用)时,可节省空间

六、枚举

C++的enum工具提供了另一种创建符号常量的方式,这种方式可以代替const。它还允许定义新类型,但必须按严格的限制进行。使用enum的句法与使用结构相似。例如,请看下面的语句:

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

这条语句完成两项工作。
♦ 让spectrum成为新类型的名称;spectrum被称为枚举(enumeration),就像struct变量被称为结构一样。
♦ 将red、orange、yellow等作为符号常量,它们对应整数值0~7。这些常量叫作枚举量(enumerator)。

在默认情况下,将整数值赋给枚举量,第一个枚举量的值为0,第二个枚举量的值为1,依次类推。可以通过显式地指定整数值来覆盖默认值,本章后面将介绍如何做。

可以用枚举名来声明这种类型的变量:

spectrum band;

枚举变量具有一些特殊的属性,下面来看一看。
不进行强制类型转换的情况下,只能将定义枚举时使用的枚举量赋给这种枚举的变量,如下所示:

band = blue;//有效的,blue是 enumeration
band = 2000;//无效的

因此,spectrum变量受到限制,只有8个可能的值。如果试图将一个非法值赋给它,则有些编译器将出现编译器错误,而另一些则发出警告。为获得最大限度的可移植性,应将把非enum值赋给enum变量视为错误

枚举量是整型,可被提升为int类型,但int类型不能自动转换为枚举类型

int color =blue;//有效的
band =3; //无效的
color = 3 + red;//有效的

虽然在这个例子中,3对应的枚举量是green,但将3赋给band将导致类型错误。不过将green赋给band是可以的,因为它们都是spectrum类型。同样,有些实现方法没有这种限制。
表达式3 + red中的加法并非为枚举量定义,但red被转换为int类型,因此结果的类型也是int。由于在这种情况下,枚举将被转换为int,因此可以在算术表达式中同时使用枚举和常规整数,尽管并没有为枚举本身定义算术运算。

1.设置枚举量的值

可以使用赋值运算符来显式地设置枚举量的值:

enum bits{one = 1, two=2, four = 4, eight = 8};

指定的值必须是整数。也可以只显式地定义其中一些枚举量的值:

enum bigstep{first, second=100, third};

这里,first在默认情况下为0。后面没有被初始化的枚举量的值将比其前面的枚举量大1。因此,third的值为101。

最后,可以创建多个值相同的枚举量:

enum {zero, null = 0, one, umero_uno=1};

其中,zero和null都为0,one和umero_uno都为1。在C++早期的版本中,只能将int值(或提升为int的值)赋给枚举量,但这种限制取消了,因此可以使用long甚至long long类型的值。

2.枚举的取值范围

最初,对于枚举来说,只有声明中指出的那些值是有效的。然而,C++现在通过强制类型转换,增加了可赋给枚举变量的合法值每个枚举都有取值范围(range),通过强制类型转换,可以将取值范围中的任何整数值赋给枚举变量,即使这个值不是枚举值。例如,假设bits和myflag的定义如下:

enum bits{one = 1, two=2, four = 4, eight = 8};
bits myflag;

则下面的代码将是合法的:

 myflag = bits{6};

其中6不是枚举值,但它位于枚举定义的取值范围内。

取值范围的定义如下:
首先,要找出上限,需要知道枚举量的最大值。找到大于这个最大值的、最小的2的幂,将它减去1,得到的便是取值范围的上限。例如,前面定义的bigstep的最大值枚举值是101。在2的幂中,比这个数大的最小值为128,因此取值范围的上限为127。要计算下限,需要知道枚举量的最小值。如果它不小于0,则取值范围的下限为0;否则,采用与寻找上限方式相同的方式,但加上负号。例如,如果最小的枚举量为−6,而比它小的、最大的2的幂是−8(加上负号),因此下限为−7。

选择用多少空间来存储枚举由编译器决定。对于取值范围较小的枚举,使用一个字节或更少的空间;而对于包含long类型值的枚举,则使用4个字节。

下一篇:五、C++ 类、对象、继承

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值