IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++复合类型 -> 正文阅读

[C++知识库]C++复合类型

1、数组

数组声明应该指出元素类型、数组名和元素个数。数组的初始化需要遵循以下规则:

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

	int narray1[4] = { 1, 2, 3, 4 };
	int narray2[4];
	// narray2 = { 2, 3, 4, 5 };	// not allowed
	// narray2 = narray1;			// not allowed

初始化结束后只能通过下标来给数组元素赋值

b. 初始化数组时,提供的值可以少于数组的元素数目

int narray1[4] = { 1, 2};

c. 初始化数组时没有指定元素个数,C++编译器将计算元素的个数,我们可以通过sizeof来计算元素个数

	int arr[] = { 1, 2, 3, 4};
	cout << sizeof(narray1) / sizeof(narray1[1]);

数组的初始化方法:

列表初始化(花括号初始化)作为通用初始化方式,适用于任何类型,当然也支持数组初始化。

	int arr1[3] = { 1, 2, 3 };
	int arr2[]{ 1, 2, 3, 4 };
	int arr3[10]{};

花括号里不填任何东西时,所有元素将被设置为0。

2、字符串

字符串是存储在连续内存中的一串字符。C++处理字符串的方式有两种:C风格字符串 和 基于string类的字符串。

a. C风格字符串

C风格字符串以空字符'\0'结尾,ASCII值为0:

	char str1[] = { 'h', 'e', 'l', 'l', 'o' };		// not a string
	char str2[] = { 'h', 'e', 'l', 'l', 'o', '\0'};	// string

除了用数组来初始化字符串,还有一种双引号括号的字符串,这种字符串被称为字符串常量:

    char str1[] = "this is a const string";
	str1[0] = 'a';
	cout << str1;        // ahis is a const string

我们可以用数组下标来修改字符串的内容。

任何两个有空白(空格、制表符、换行符)分隔的字符串常量可以拼接为一个,拼接后的字符串之间不会添加空格,前一个字符串的'\0'会被后一个字串取代

	cout << "hello " "world " "!!!!" << endl;	// hello world !!!!
	cout << "hello "
		"world "
		"!!!!" << endl;							// hello world !!!!

    #define HEL "hello"
    cout << HEL" world";	                    // hello world

	char str[] = "hello " "world"
					"!!!";
	cout << str;	                            // hello world!!!

b. string类简介

string类位于命名空间std中,可以通过using std::string来引入,string类隐藏了字符串的数组性质。string可以有以下初始化方式:

	string str1 = "hello world";
	string str2 = { "hello world" };
	string str3("hello world");
	string str4{ "hello world" };
	string str5 = str1;
	string str6(str1);

3、结构体简介

结构体是一种比数组更为灵活的数据格式,同一个结构可以存储多种类型的数据。结构体可以有外部声明(可以被其后面的任何函数使用)和内部声明(被该声明所属的函数使用)。

C++11结构创建与初始化:

	struct student
	{
		char name[20];
		int age;
		bool gender;
	};
 
	student s1 = { "ming", 11, true };
	student s2{ "hong", 10, false };
    student s3{};  // 初始化为0
    
    student s4;    // 这时候结构体中的成员都是未初始化的,使用可能会出现未知的问题
    memset(&s4, 0, sizeof(s4));

    // 指定初始化,不是所有的编译器都支持的,linux中常用
    student s5 = { .name = "bing", .age = 10, .gender = false };

结构体定义和创建结构体变量可以同时完成,初始化也可以同时完成:

	struct student
	{
		char name[20];
		int age;
		bool gender;
	} s1 = {}, s2 =
	{
		"ming", 11, true
	};

我们还可以声明匿名的结构体类型,但是我们必须要在定义的同时声明变量:

	struct 
	{
		int x;
		int y;
	} position;

有了结构体我们可以声明结构体数组了:

	student ss[3]{
		{ "ming", 11, true },
		{ "hong", 10, false },
		{ }
	}

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

	struct torgle_register
	{
		unsigned int a : 4;		// 4 bits for SN
		unsigned int : 4;		// 4 bits unused
		unsigned int b : 2;		// 2 bits unused
		unsigned int c : 14;	// 14 bits unused
	} tr;
	tr = { 0xf, 0x3, 0xfff };
	cout << hex;
	cout << tr.a << " " << tr.b << " " << tr.c << endl;		// f 3 fff
	tr = { 0xf1, 0x5, 0x4fff };
	cout << tr.a << " " << tr.b << " " << tr.c << endl;		// 1 1 fff
	cout << "sizeof(tr) = " << sizeof(tr);					// 4

位段的存储规则:当相邻成员的类型相同时,如果它们的位宽之和小于类型的 sizeof 大小,那么后面的成员紧邻前一个成员存储,直到不能容纳为止;如果它们的位宽之和大于类型的 sizeof 大小,那么后面的成员将从新的存储单元开始,其偏移量为类型大小的整数倍。计算位段结构体大小时可能还需要兼顾到内存对齐,这里暂不介绍。

4、共用体

共用体能够存储不同的数据类型,但是只能同时存储其中的一种类型。由于每次只能存储一个值,所以必须要有足够的空间来存储最大的成员,共用体的长度为其最大成员的长度。

	struct widget {
		char brand[20];
		int type;
		union id {
			long id_num;
			char id_char[20];
		} id_val;
	};

    cout << sizeof(widget);    // 44

	w1.id_val.id_num = 10;
	w1.id_val.id_char[0] = 20;
	cout << w1.id_val.id_num;	// 20

匿名共用体的成员会被是为结构体成员的两个成员,我们使用时需要先确定哪个成员是正在活动的:

	struct widget2 {
		char brand[20];
		int type;
		union{
			long id_num;
			char id_char[20];
		};
	} w1 = {};
	if (w1.type == 1)
		w1.id_num = 10;
	else
		memcpy(w1.id_char, "apple", strlen("apple"));

5、枚举

C++的enum提供了另一种创建符号常量的方式,这种方式可以替代const。

默认情况下,将整数值赋给枚举量,第一个枚举量的值为0,第二个枚举量的值为1,以此类推;此外,我们可以通过显式指定整数值来覆盖默认值,我们也可以创建多个值相同的枚举量。

    enum MyEnum
	{
		APPLE,
		ORANGE,
		BANANA,
	};

枚举变量有些特殊的属性:在不进行强制转换的情况下,只能将定义枚举时使用的枚举量赋给这种枚举的变量。枚举量是整形,可被提升为int类型,但是int类型不能自动转换为枚举类型。

    MyEnum fruit;
	fruit = APPLE;
	// fruit = 1000;        // invalid
	fruit = MyEnum(2);
    // fruit = 1 + APPLE;   // invalid
    // fruit = 2;           // invalid
    int nu = 1 + APPLE;     // valid

枚举的上限为大于最大值的、最小的2的幂减1,最小值如果大于等于0则下限为0,否则下限的计算方式和上限相同。下例中6不是枚举值,但是它位于枚举定义的取值范围内。

	enum bits {
		one = 1,
		two = 2,
		four = 4,
		eight = 8,
	};
	bits myflag = bits(6);
    // bits myflags2 = bits(9); // invalid

6、指针和自由存储空间

指针是一个变量,存储的是一个值的地址,而不是值本身。指针声明必须指定指针指向的数据的类型。以下声明的是一个指针变量和一个int变量:

	int * p, p1;

我们可以通过new 和 delete来分配、释放内存

	int * p = new int;
	*p = 100;
	delete p;
	p = NULL;

也可以通过malloc 和 free来分配、释放内存

	int *p = (int*)malloc(sizeof(int));
	*p = 100;
	cout << p << " " << *p << endl;        // 00DE89B8 100
	free(p);
	p = NULL;

使用new来创建动态数组:

	int *p = new int[10];
	// int p[10] = new int[10];		// invalid
    delete[] p;

7、指针、数组和指针算数

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

很多情况下我们可以以相同的方式使用指针名和数组名,包括方括号表示法和解引用运算符。区别是指针的值可以被修改,而数组名是常量;另一个区别是对数组应用sizeof运算符得到的是数组的长度,对指针应用sizeof得到的是指针的长度。

	int array[10]{};
	int *parray = new int[10];
	array[2] = 2;
	*(array + 3) = 3;
	parray[2] = 2;
	*(parray + 3) = 3;
	parray++;
	// array = array + 1; not allowed
	cout << sizeof(array) << endl;	// 40
	cout << sizeof(parray) << endl;	// 4

    int *p = array;

数组名会被解释为其第一个元素的地址,对数组名应用地址运算符时,得到的是整个数组的地址

	short tell[3]{};
	cout << &tell[0] << endl;      // 012FFB64
	cout << tell << endl;          // 012FFB64
	cout << &tell << endl;         // 012FFB64
	cout << tell + 1 << endl;      // 012FFB66     + 2
	cout << &tell + 1 << endl;     // 012FFB6A     + 6

数组指针:指向数组的指针

变量首先和*结合说明是一个指针,指向的类型是 short []

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

指针数组:存储指针的数组

变量首先和[]结合说明是一个数组,存储的类型是short *

	short *pp[3]{};

指向同一个数组的指针相减得到的是两个元素之间的间隔

	short *p1 = tell;
	short *p2 = &tell[2];
	cout << p2 - p1 << endl;    // 2
	cout << p1 - p2 << endl;    // -2

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

自动存储:函数内部定义的常规变量使用自动存储空间被称为自动变量,自动变量是一个局部变量,其作用域为包含它的代码块。

	{
		int a = 0;
	}

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

// 函数外部明静态变量

static int ga = 0;

int addA()
{
	ga++;
	return ga;
}

int a = addA();
cout << a << endl;	// 1
a = addA();
cout << a << endl;	// 2
// 函数内声明静态变量
int addA()
{
	static int a = 0;
	a++;
	return a;
}

int a = addA();
cout << a << endl;	// 1
addA();
cout << a << endl;	// 2

以上两种声明方式的不同点在于:在函数内部声明的静态变量只能在函数内部访问到,而外部声明在声明位置之后都可以访问到。

动态存储:new和delete运算符提供了一种更灵活的方法,他们管理了一个内存池(heap),数据的生命周期不完全受程序或函数的生存时间控制。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 10:47:31  更:2022-12-25 10:48:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 2:50:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码