02-C++数据类型-高级

news2024/12/23 12:15:04

数据类型-高级

4、复合类型

4.4、结构简介

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

inflatable vincent;			//C++
struct inflatable goose;	//C

例子

// 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; 
}
/*
Expand your guest list with Glorious Gloria and Audacious Arthur!
You can have both for $62.98!
*/

外部声明可以被其后面的任何函数使用,而内部声明只能被该声明所属的函数使用。通常使用外部声明,这样所有函数都可以使用这种类型的结构。

变量也可以在函数内部和外部定义,外部变量由所有的函数共享。C++不提倡使用外部变量,但提倡使用外部结构的声明。

结构的赋值

可以使用赋值运算符(=)将结构A赋给另一个同类型的结构B。这样结构中每个成员都将被设置成另一个结构中相应成员的值,即使成员是数组。这种赋值被称为成员赋值。

// 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;
}
/*
bouquet: sunflowers for $12.49
choice: sunflowers for $12.49
*/

结构体数组

// 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;
}
/*
The guests Bambi and Godzilla
have a combined volume of 2000.5 cubic feet.
*/

结构中的位字段

与C语言一样,C++也允许指定占用特定位数的结构成员,这使得创建于某个硬件设备上的寄存器对应的数据结构非常方便。

struct torgle_register
{
	unsigned int SN :4;
	unsigned int :4;
	bool goodIn:1
	bool goodTorgle:1;
}

4.5、共用体

共同体是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。也就是说,结构可以同时存储int、long、double,共用体只能存储int、long或double。

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

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;

//匿名共用体没有名称,其成员将成为位于相同地址处的变量
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、枚举

enum spectnum{red, orange, yellow, green, blue, violet, indigo, yyuu};

spectnum band;
band=blue;			//valid
band=2000;			//invalid

band=orange;		//valid
++band;				//invalid
band=orange + red;	//invalid

int color =blue;	//valid
band =3;			//invalid
color=3+red;		//valid, red converted to int

band = spectnum(3);	//强转

枚举的取值范围

enum bits{one=1, two=2, four=4, eight=8};
bits myflag;
myflag=bits(6);		//valid,because 6 is in bits range

范围,最大值、最小值所对应的2次幂-1(负数:+1)

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;
}
/*
donuts value = 6 and donuts address = 0x62fe1c
cups value = 4.5 and cups address = 0x62fe10
*/

指针与C++基本原理

面向对象编程与传统的过程性编程的区别在于,OOP强调的是在运行阶段(而不是编译阶段)进行决策。运行阶段指的是程序正在运行时,编译阶段指的是编译器将程序组合起来时。运行阶段觉得就好比度假时,选择参观哪些景点取决于天气和当时的心情;而编译阶段决策更像不管在什么条件下,都坚持预先设定的日程安排。

总之,使用OOP时,可能在运行阶段吧确定数组的长度。为使用这种方法,语言必须允许在程序运行时创建数组。C++采用的方法是,使用关键字new请求正确数量的农村以及使用指针来跟踪新分配的内存的位置。

在运行阶段做决策并非OOP独有的,但使用C++编写这样的代码比使用C语言要简单很多。

指针表示的是地址。*运算符被称为间接值或解除引用运算符,将其应用与指针,可以得到该地址处存储的值。

// pointer.cpp -- our first pointer variable
#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 = 0x62fe14, p_updates = 0x62fe14
Now updates = 7
*/

对于指针,&取地址运算符;*解除引用运算符。有以下的图

在这里插入图片描述

指针初始化

int * p_updates;

int *ptr;		//*ptr是一个int类型的值
int* ptr; 		//指针ptr指向int类型;ptr的类型是指针int的指针

int* p1,p2;		//一个指针(p1)和一个int变量(p2)

double* tax_ptr;//指向double的指针
char* str;		//指向char的指针

**注意:**在C++中,int*是一种复合类型,是指向int的指针

和数组一样,指针都是基于其他类型的。虽然tax_ptr和str指向两种长度不同的数据类型,但这两个变量本身的长度通常是相同的。也就是说,char的地址和double的地址的长度相同。

可以在声明语句中初始化指针。

//被初始化的是指针,而不是它指向的值
int higgens=5;
int* pt=&higgens;
// 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;
}

/*
Value of higgens = 5; Address of higgens = 0x62fe14
Value of *pt = 5; Value of pt = 0x62fe14
*/

指针的危险

在C++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。为数据提供空间是一个独立的步骤。

long *fwllow;
*fwllow=23455556;	//invalid

警告

一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。

int* pt;
pt=0xB8000000;			//type mismatch
//要将数字值作为地址来使用,应通过强制类型转换将数字转换为适当的地址类型
pt=(int*)0xB8000000;	//type now match

new&delete

  • 可以使用new来分配内存
//方式1
int* pn=new int;

//方式2
int higgens;
int* pt=&higgens;

都是将一个int变量的地址赋给了指针。第2种情况下,可以通过名称higgens来访问该int,在第1种情况下,只能通过该指针进行访问。

// 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;
}
/*
nights value = 1001: location 0x62fe14
int value = 1001: location = 0x26d6710
double value = 1e+07: location = 0x26d6cf0
location of pointer pd: 0x62fe08
size of pt = 8: size of *pt = 4
size of pd = 8: size of *pd = 8
*/
  • 使用delete释放内存
int* ps= new int;		//allocate memory with new
....					//use the memory
delete ps;				//free memory with delete when done

这将释放ps指向的内存,但不会删除指针ps本身。例如,可以将ps重新指向另一个新分配的内存块。一定要配对得使用new和delete。

不要尝试释放已经释放的内存块。另外,不能使用delete来释放声明变量所获得的内存:

int *ps=new int;
delete ps;
delete ps;	//not ok now

int jugs=5;
int* pi=&jugs;	//ok
delete pi;		//not allowed

警告:

智能用delete来释放使用new分配的内存。然而,对空指针使用delete是安全的。

int* ps=new int;
int* pq=ps;
delete pq;

一般来说,不要创建两个指向同一个内存块的指针,因为这将增加错误地删除同一个内存块两次的可能性。

  • 使用new来创建动态数组
int* psome=new int[10];
delete [] psome;
//分配内存的通用格式
type_name* pointer_name =new type_name[size];

使用new和delete时,应遵守以下规则

  1. 不要使用delete来释放不是new分配的内存
  2. 不要使用delete释放同一个内存块两次
  3. 如果使用new[]为数组分配内存,则应使用delete[]来释放
  4. 如果使用new为一个实体分配内存,则应使用delete(没有方括号)来释放
  5. 对空指针应用delete是安全的
// 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;
}
/*
p3[1] is 0.5.
Now p3[0] is 0.5 and p3[1] is 0.8.
*/

不能修改数组名的值,但指针时变量,可以修改它的值。

4.8、指针、数组和指针算术

指针和数组等价的原因在于指针算术和C++内部处理数组的方式。

C++将数组名解释为地址。

// 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 =stacks 
// 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;
}
/*
pw = 0x62fdf0, *pw = 10000
add 1 to the pw pointer:
pw = 0x62fdf8, *pw = 20000

ps = 0x62fdea, *ps = 3
add 1 to the ps pointer:
ps = 0x62fdec, *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
*/

对于指针的加法

在这里插入图片描述

注意:

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

通常,使用数组表示法时,C++都执行下面的转换

arrayname[i] becomes *(arrayname+i)

如果使用的指针,而不是数组名,则C++也将执行同样的转换

pointername[i] becomes *(pointername+i)

因此,在很多情况下,可以相同的方式使用指针名和数组名。对于它们,可以使用数组方括号表示法,也可以使用解除引用运算符(*)。在多数表达式中,它们都表示地址。区别之一是,可以修改指针的值,而数组名是常量:

pointername=pointername+1;		//valid
arrayname=arrayname+1;			//not allow

另一个区别是,对数组应用sizeof运算符得到的是数组的长度,而对指针应用sizeof得到的是指针的长度,即使指针指向的是一个数组。

数组的指针

short tell[10];
cout<<tell;				//displays &tell[0]
cout<<&tell;			//displays address of whole array

​ 从数字上说,两个地址是相同的;但从概念上说,&tell[0](即tell)是一个2字节内存块的地址,而&tell是一个20字节内存块的地址。换句话说,tell是一个short指针(short*),而&tell是一个这样的指针,即指向包含10个元素的short数组(short( * )[10])。

short(*pas)[10]=&tell;

指针小结

  • 声明指针
typeName* pointerName;
double* pn;
char* pc;
  • 给指针赋值

应将内存地址赋给指针。可以对变量名应用 &运算符,来获得被命名的内存的地址,new运算符返回未命名的内存的地址。

double* pn;
double* pa;
char *pc;
double bubble=3.2;

pn=&bubble;
pc=new char;
pa=new double[30];
  • 对指针解除引用
cout<< *pn;		//3.2
*pc='s';	

另一种对指针解除引用的方法是使用数组表示法,例如,pn[0]与*pn是一样的。决不要对未被初始化为适当地址的指针解除引用。

  • 区分指针和指针所指向的值
int* pt=new int;	//assigns an address to the pointer pt
*pt=5;				//stores the value 5 at that address
  • 数组名

在多数情况下,C++将数组名视为数组的第1个元素的地址

int tacos[10];
  • 指针算术

C++允许将指针和整数相加。加1的结果等于原来的地址值加上指向的对象占用的总字节数。还可以将一个指针减去另一个指针,获得两个指针的差。

仅当两个指针指向同一个数组(也可以指向超出结尾的一个位置)时,这种运算才有意义。

int tacos[10]={5,2,8,2,3,4,5,5,6,7};
int* pt=tacos;
pt=pt+1;
int* pe=&tacos[9];
pe=pe-1;
int diff=pe-pt;
  • 数组的动态联编和静态联编
//static
int tacos[10];

//dynamic
int size;
cin>>size;
int *pz=new int[size];
...
delete[]pz;
  • 数组表示法和指针表示法

使用方括号数组表示法等同于对指针解除引用

tacos[0]
tacos[3]

数组名和指针变量都是如此。因此对于指针和数组名,即可以使用指针表示法,也可以使用数组表示法

int *pt=new int[10];
*pt=5;
pt[0]=6;
pt[9]=44;

int coats[10];
*(coats+4)=12;

指针和字符串

注意:

在cout和多数C++表达式中,char数组名、char指针以及用括号扩起来的字符串常量都被解释为字符串第一个字符的地址。

// 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;
}
/*
bear and wren
Enter a kind of animal: fox
fox!
Before using strcpy():
fox at 0x62fdf0
fox at 0x62fdf0
After using strcpy():
fox at 0x62fdf0
fox at 0x2576cd0
*/

通过使用strcpy()和new,将获得"fox"的两个独立副本

经常需要将字符串放到数组中。初始化数组时,请使用=运算符;否则应使用strcpy()或strncpy()。

char food[20]="carrots";		//initalization
strcpy(food,"flan");			//otherwise

对于strncpy()

strncpy(food,"a picnic basket filled with many goodies",19);
food[19]='\0';

这样最多将19个字符复制到数组中,然后将最后一个元素设置成空字符。如果该字符串少于19个字符,则strncpy()将在复制完该字符串之后加上空字符,以 标记该字符串的结尾。

使用new创建动态结构

在这里插入图片描述

提示

如果结构标识符时结构名,则使用句点运算符;如果标识符是指向结构的指针,则使用箭头运算符。

另一种访问结构成员的方法是,如果ps是指向结构的指针,则*ps就是被指向的值——结构本身。由于*ps是一个结构,因此(*ps).price是该结构的price成员。
// 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;
}
/*
Enter name of inflatable item: Fab
Enter volume in cubic feet: 1.4
Enter price: $27.99
Name: Fab
Volume: 1.4 cubic feet
Price: $27.99
*/
  • 使用new和delete
// 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
}

/*
Enter last name: Fredlkin
Fredlkin at 0x726cd0
Enter last name: Pook
Pook at 0x726cd0
*/

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

  • 自动存储

​ 在函数内部定义的常规变量使用自动存储空间,被称为自动变量,这以为着它们在所属的函数被调用时自动产生,在该函数结束时消亡。

​ 实际上,自动变量是一个局部变量,其作用域为包含它的代码块。

​ 自动变量通常存储在栈中。这意味着执行代码块时,其中的变量依次加入到栈中,而离开代码块时,将按相反的顺序释放这些变量。这被称为后进先出(LIFO)。因此,在程序执行的过程中,栈不断地增大和缩小。

  • 静态存储

​ 静态存储是整个程序执行期间都存在的存储方式。使变量称为静态的方式有两种:一种是在函数外面定义它;另一种是在声明变量时使用关键字static:

static double fee=56.50;
  • 动态存储

​ new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内存池,这在C++中被称为自由存储空间(free store)或堆(heap)。该内存池同用于静态变量和自动变量的内存时分开的。

​ new和delete让我们能够在一个函数中分配内存,在另一个函数中释放它。因此,数据的生命周期不完全受程序或函数的生存时间控制。

栈、堆和内存泄漏

​ 如果使用了new运算符在自由存储空间(或堆)上创建变量后,没有调用delete,将会发生什么?

​ 如果没有调用delete,则即使包含指针的内存由于作用域规则和对象生命周期的原因而被释放,在自由存储空间上动态分配的变量或结构也将继续存在。实际上,将会无法访问自由存储空间中的结构,因为指向这些内存的指针无效。这将导致内存泄漏。被泄漏的内存将在程序的整个生命周期内都不可使用;这些内存被分配出去,但无法收回。

4.9、类型组合

//结构定义
struct antarctica_year_end
{
	int year;
};

antarctica_year_end s01,s02,s03;		//创建变量
s01.year=1998;							//使用成员运算符访问成员

antarctica_year_end=&s02;				//创建指向这种结构的指针
pa->year=1999;							//使用间接成员运算符访问成员

antarctica_year_end trio[3];			//创建结构数组
trio[0].year=2003;						//使用成员运算符访问成员
(trio+1)->year=2004;					//使用间接成员运算符

const antarctica_year_end* arp[3]={&s01,&s02,&s03};		//创建指针数组
std::cout<<arp[1]->year<<std::endl;						//使用间接运算符

const antarctica_year_end** ppa=arp;					//创建上面数组的指针 ppa=arp
std::cout<<(*ppa)->year<<std::endl;					//*ppa为&s01,式子为s01的year成员
std::cout<<(*(ppb+1))->year<<std::endl;

例子

// 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;
}
/*
2003
1999
1998
1999
*/

4.10、vector、array

vector

模板类vector类似于string类,也是一种动态数组。可以在运行阶段设置vector对象的长度,可以在末尾附加新数据,还可以再中间插入新数据。

声明创建一个名为vt的vector对象,它可以存储n_elem个类型为typeName的元素

vector<typeName> vt(n_elem)
//其中参数n_elem可以是整型常量,也可以是整型变量。

#include<vector>
using namespace std;
vector<int>vi;
int n;
cin>>n;
vector<double> vd(n);

array

​ vector类的功能比数组强大,但代价是效率较低。如果需要长度固定的数组,使用数组是更佳的选择,但代价是不那么方便和安全。array,也位于名称空间std中。

​ 与数组一样,array对象的长度也是固定的,也使用栈(静态内存分配),而不是自由存储区,因此其效率与数组相同,但更方便、安全。

array<typeName,n_elem> arr;
//声明创建一个名为arr的array对象,它包含n_elem个类型为typeName的元素。
//n_elem不能是变量

#include<array>
....
using namespace std;
array<int,5> ai;
array<double,4>ad={1.2, 2.1, 3.43, 4.3};

对比

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

/*
a1[2]: 3.6 at 0x62fdf0
a2[2]: 0.142857 at 0x25b6720
a3[2]: 1.62 at 0x62fdb0
a4[2]: 1.62 at 0x62fd90
a1[-2]: 20.2 at 0x62fdd0
a3[2]: 1.62 at 0x62fdb0
a4[2]: 1.62 at 0x62fd90
*/

首先,无论是数组、vector对象还是array对象,都可以使用标准数组表示法来访问各个元素。

其次,从地址中可知,array对象和数组存储在相同的内存区域(即栈)中,而vector对象存储在另一个区域(自由存储区或堆)中。

第三,可以将一个array对象赋给另一个array对象;对于数组,必须逐个元素复制数据。

数组越界无法禁止。对于vector和array对象,可以禁止,但仍然不安全。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/882683.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据库系统】--【2】DBMS架构

DBMS架构 01DBMS架构概述02 DBMS的物理架构03 DBMS的运行和数据架构DBMS的运行架构DBMS的数据架构PostgreSQL的体系结构RMDB的运行架构 04DBMS的逻辑和开发架构DBMS的层次结构DBMS的开发架构DBMS的代码架构 05小结 01DBMS架构概述 02 DBMS的物理架构 数据库系统的体系结构 数据…

(二)结构型模式:5、装饰器模式(Decorator Pattern)(C++实例)

目录 1、装饰器模式&#xff08;Decorator Pattern&#xff09;含义 2、装饰器模式的UML图学习 3、装饰器模式的应用场景 4、装饰器模式的优缺点 5、C实现装饰器模式的简单实例 1、装饰器模式&#xff08;Decorator Pattern&#xff09;含义 装饰模式&#xff08;Decorato…

学习 Iterator 迭代器

今天看到一个面试题&#xff0c; 让下面解构赋值成立。 let [a,b] {a:1,b:2} 如果我们直接在浏览器输出这行代码&#xff0c;会直接报错&#xff0c;说是 {a:1,b:2} 不能迭代。 看了es6文档后&#xff0c;具有迭代器的就一下几种类型&#xff0c;没有Object类型&#xff0c;…

探索Java中的静态变量与实例变量:存储区域、生命周期以及内存分配方式的区别

文章目录 静态变量实例变量不可变对象静态变量和实例变量有什么区别&#xff1f;静态变量实例变量 Object 类都有哪些公共方法&#xff1f;Java 创建对象有哪几种方式&#xff1f;ab 与 a.equals(b) 有什么区别&#xff1f;总结 &#x1f389;欢迎来到Java面试技巧专栏~探索Jav…

Nacos详解(springcloud+nacos实战)

Nacos详解 Nacos1.介绍2.Nacos专业术语2.1 服务 (Service)2.2 服务注册中心 (Service Registry)2.3服务提供方 (Service Provider)2.4服务消费方 (Service Consumer)2.5版本依赖关系 Nacos 注册中心1. 启动NacosServer2 使用 Nacos 做注册中心2.1 nacos-client-b2.2 nacos-clie…

部门用户权限应用的设计和创建(进行中)

数据库表设计 代码实现之前首先是表设计&#xff0c; 六个基本步骤 1.需求分析 (分析用户需求,包括数据、功能和性能需求&#xff09; 2.概念结构设计(主要采用 E-R图) 3.逻辑结构设计 (将ER图转换成表,实现从E-R模型到关系模型转换&#xff09; 4.数据库物理设计 (为设计的…

深度学习的“前世今生”

1、“感知机”的诞生 20世纪50年代&#xff0c;人工智能派生出了这样两个学派&#xff0c;分别是“符号学派”及“连接学派”。前者的领军学者有Marvin Minsky及John McCarthy&#xff0c;后者则是由Frank Rosenblatt所领导。 符号学派的人相信对机器从头编程&#xff0c;一个…

Vue-5.编译器idea

关闭 IDEA 自动更新 IDEA无法搜索插件 填写idea下载插件的官方地址点击ok测试成功则ok https://plugins.jetbrains.com/idea 全局内存配置&#xff08;重启后生效&#xff09; 部署 Alibaba Cloud toolkit&#xff08;部署代码的利器&#xff09; Git&#xff08;需要安装gi…

人工智能原理(4)

目录 一、确定性推理 1、推理方式 2、控制策略 二、推理的逻辑基础 1、永真和可满足性 2、等价性和永真蕴含 3、置换与合一 三、自然演绎推理 四、归结演绎推理 1、子句型 2、鲁滨逊归结原理 3、归结策略 一、确定性推理 推理&#xff1a;就是按照某种策略从已有事…

微机原理与接口技术 学习笔记(二) 存储器

文章目录 一&#xff0c;存储器1.1 概述1.1.1 半导体存储器的分类按制造工艺&#xff1a; 易失性或挥发性存储器 / 不易失性或不挥发性存储器按制造工艺&#xff1a; 1.1.2 半导体存储器的性能指标1.1.3 半导体存储器的一般结构及组成 1.2 随机存取存储器 RAM1.2.1 静态RAM1.2.…

操作符和表达式求值

目录 1.运算符的优先级和结合性 1.1运算符的优先级 1.2结合性 2.操作符的使用最终带来的是一个表达式的值 2.1.隐式类型转换&#xff08;整型提升&#xff09; 2.1.1整形提升的例子 2.2算术转换 1.运算符的优先级和结合性 运算符是编程语言中的基本元素之一&#xff0c;主…

临床试验三原则-对照、重复、随机

临床试验必须遵循三个基本原则&#xff1a;对照、重复、随机。 一、对照原则和对照的设置 核心观点&#xff1a;有比较才有鉴别。 对照组和试验组同质可比。 三臂试验 安慰剂&#xff1a;试验组&#xff1a;阳性对照组1&#xff1a;n&#xff1a;m&#xff08;n≥m&#xff…

论文略读:城市道路场景下车辆编队运动规划与控制算法研究

1. 一些观点&#xff1a; &#xff08;1&#xff09;我曾经认为不能复现的论文都是垃圾。我现在看到能够量产的论文之后发现&#xff0c;论文的复现实属难得&#xff0c;即使给你代码&#xff0c;反复钻研&#xff0c;一个月之久才敢说略微看懂&#xff0c;所以论文的复现实在是…

使用 `tailwindcss-patch@2` 来提取你的类名吧

使用 tailwindcss-patch2 来提取你的类名吧 使用 tailwindcss-patch2 来提取你的类名吧 安装使用方式 命令行 Cli 开始提取吧 Nodejs API 的方式来使用 配置 初始化 What’s next? tailwindcss-patch 是一个 tailwindcss 生态的扩展项目。也是 tailwindcss-mangle 项目重要…

高等数学教材重难点题型总结(二)导数与微分

本章重点题目较少&#xff0c;除了*标题页没什么特别难的&#xff0c;本帖出于总结性的角度考虑并未囊概全部的*标&#xff0c;最后会出一期*标题的全部内容整理&#xff0c;在攻克重难点的基础上更上一层楼。 1.根据定义求某点处的导数值 2.通过定义证明导数 3.左右导数的相关…

QT使用QML实现地图绘制虚线

QML提供了MapPolyline用于在地图上绘制线段&#xff0c;该线段是实线&#xff0c;因此我使用Canvas自定义绘制的方式在地图上绘制线段&#xff0c;如图&#xff1a; 鼠标在地图上点击后&#xff0c;在点击位置添加图标 &#xff0c;当有多个图标被添加到地图上后&#xff0c;计…

openGauss学习笔记-40 openGauss 高级数据管理-锁

文章目录 openGauss学习笔记-40 openGauss 高级数据管理-锁40.1 语法格式40.2 参数说明40.3 示例 openGauss学习笔记-40 openGauss 高级数据管理-锁 如果需要保持数据库数据的一致性&#xff0c;可以使用LOCK TABLE来阻止其他用户修改表。 例如&#xff0c;一个应用需要保证表…

MTK Android非常用分辨率修改充电动画

非标准分辨率的屏,配置MTK Android的关机充电动画. 环境 芯片 MTK 系统 Android 服务器 ubuntu 屏幕分辨率356*400,不是常见的分辨率. 原始充电动画显示异常,画面扭曲. 方法 确定使用的图片 vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo 这个目录下…

05-基础入门-系统及数据库等

基础入门-系统及数据库等 一、操作系统层面1、识别操作系统常见方法2、简要两者区别及识别意义3、操作系统层面漏洞类型对应意义4、简要操作系统层面漏洞影响范围 二、数据库层面1、识别数据库类型常见方法2、数据库类型区别及识别意义3、数据库常见漏洞类型及攻击4、简要数据库…

【【STM32之GPIO】】

STM32之GPIO 学完了正点原子自带的视频课之后感觉仍然一知半解现在更新一下来自其他版本的STM32学习 GPIO 就是 General Purpose Input Output 中文名叫通用输入输出口 可配置8种输入输出模式 引脚电平 0V~3.3V 部分引脚可容忍5V 输出模式下可控制端口输出高低电平&#xff…