【c++ primer plus】第四章-复合类型

数组

数组是一种数据格式,能够存储多个同类型变量的值。

数组的创建:存储在每一个元素中的值的类型,数组名,数组中元素个数。

可以使用下标分别给数组中的元素赋值。

数组声明:(声明的同时可以进行数组的初始化,只有声明时才能进行初始化)

typename arrayname[arraysize];//元素数目可以是整形常数或者是const型,也可以是常量表达式

复合类型数组

数组之所以被称为复合类型的数组,是因为它是由其他类型创建的。必须是特定类型的数组,如float类型数组。

float loans[20];//不是数组,而是浮点型数组

注:可以单独访问数组,方法是利用带方括号表示法来锁定数组元素。months【0】表示第一个元素。

有效下标的重要性

编译器不会检查下标是否是有效的,如果下标无效,可能会导致运行错误等一系列问题。sizeof用于整个数组则得到数组的字节数,用于单个数组元素则得到元素的长度。

数组的初始化规则

  1. 只有在定义数组时才可以对数组进行初始化,一个数组不可以赋值给另一个数组
  2. 可以使用下标分别给数组中的元素赋值。
  3. 数组初始化时提供的值可以比数组数少,少的系统补充0
  4. 通常,让编译器去计算数组的个数是非常糟糕的,因为如果在初始列表中遗漏一个初始值则不容易被发现。

c++11数组初始化方法

  1. 在原来的基础上,省略原有的等号
  2. 可在大括号中不包含任何东西,默认为0.
  3. 列表初始化禁止缩小转换。
  4. STL(标准库模板)提供一个数组代替品——模板类vector。

数组相关代码和常见问题

杨辉三角形

#include<iostream>
using namespace std;
int arr[10][10];//char arr[]显示的是方框,利用循环打印出二维数组(不要遗漏第一个for的花括号,不然显示不出应该有的图形的样子),两个循环则打印两个二维数组,先循环数据,在利用循环进行c代码的输出
int main()
{
	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j <= i; j++)
		{
			if (j == 0 || i == j)
			{
				arr[i][j] = 1;
				cout << arr[i][j] << " ";
			}
			else
			{
				arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
				cout << arr[i][j] << " ";
			}
		}cout << endl;
	}
	system("pause");
	return 0;
}




#include<iostream>
using namespace std;

int main()
{
	int a[10][10] = {};//运行出错的主要原因是数组下标溢出,初始化数组为什么不能放在main函数内,数组应该初始化
	cout << "请输入杨辉三角的行数;" << endl;
	
	int i, j;
	for (i = 0; i < 10; i++)//注意函数的行和列之间的差别
	{
		for (j = 0; j <= i; j++)//运行出错的原因之二是j可以等于i
		{
			if (i == 1 || j == i)
			{
				该行的第一个和该行的最后一个数据都是1 
				a[i][j] = 1;//整个数组等于1是数组中每一个元素等于1
			}
			else
			{
				a[i][j] = a[i - 1][j - 1] + a[i - 1][j];//杨辉三角基本公式
			}	
		}
	}
		
	下面为输出数据 
	cout << "输出的杨辉三角形为" << endl;
	for (i = 0; i <10; i++)
	{
		for (j = 0; j <= i; j++)
		{
			cout << a[i][j]; 
		}
		cout<<endl;//怎样使杨辉三角形输出时左对齐
	}
	return 0;
}



#include<iostream>
int main() {
	using namespace std;
	int n;
	cout << "请输入杨辉三角的行数;" << endl;
	cin >> n;
	int i, j;
	int array[n][n];
	//填充数值模块 
	for (i = 0; i < n; i++)
	{
		for (j = 1; j <= i; j++)
		{
			array[i][j] = array[i - 1][j - 1] + array[i - 1][j];
		}
		array[i][0] = array[i][i] = 1;//可是没有j
	}
	//输出模块 
	for (i = 0; i < n; i++) {
		cout << "\n";
		for (j = 0; j <= i; j++) {
			cout << array[i][j] << " ";
		}
		cout << endl;
	}
	return 0;
}


int main()
{
	int arr[10][10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i][0] = 1;//列1
		int j = 0;
		for (j = 0; j <=i; j++)//下半个三角形
		{
			if (i == j)
			{
				arr[i][j] = 1;//j小于i的时候其他值默认是0,j>i时是不显示
			}
			/*else
			{
				arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
			}*/
		}
	}

	//打印看看效果
	for (i = 0; i < 10; i++)
	{
		int j = 0;
		for (j = 0; j <=i; j++)
		{
			//printf("%d ", arr[i][j]);
			cout << arr[i][j];
		}
		printf("\n");
	}
	return 0;
}

相关问题:

  1. 数组一定要初始化,如果数组不初始化则数组存放的是原来空间中的地址,但是可以将数组放在main函数后面则结果显示正确。
  2. 数组所返回的类型要和数组中的元素是对应关系,不然数字打印的结果是正方形
  3. 在利用循坏打印数组时一定要加花括号,避免打印错误。
  4. 下标一定不能溢出,会显示运行时栈溢出
  5. 杨辉三角形时显示行和列时注意行和列之间的关系
  6. 显示数组中元素全是1时直接让数组等于1
  7. 如何实现杨辉三角形输出时左对齐

数组-值为偶数的元素和

#include <iostream>
using namespace std;
int main(){
    int n[]={2,21,3,42};
    int sum=0;
    for(int i=0;i<4;i++){
    	if(n[i]%2!=0){
    		continue;
		}
		sum+=n[i];
	}
	cout<<"The sum is "<<sum<<endl;
	return 0;
}

相关问题:

  1. 取模就是求余数,在使用变量时注意局部变量只能作用于局部。
  2. 创建变量时不进行初始化会有什么结果

冒泡排序法

#include<iostream>
using namespace std;
int main()
{
	int i, j, k;
	int a[10];
	cout << "请输入10个整数:";
	for (i = 0; i < 10; i++)
	{
		cin >> a[i];
	}
	for (j = 0; j < 9; j++)
	{
		for (i = 0; i < 9 - j; i++)
		{
			if (a[i] > a[i + 1])
			{
				k = a[i];
				a[i] = a[i + 1];
				a[i + 1] = k;
			}
		}
	}
	cout << endl << "输出从小到大冒泡排序后的10个整数:";
	for (i = 0; i < 10; i++)
	{
		cout << a[i] << ' ';
	}
	cout << endl;
	system("pause");
	return 0;
}

注意事项

  1. 在输入十个数存进数组的时候,应使用循环存
  2. 发现的问题是一定输入十个数,不输入十个数程序不运行,它不会初始化为0,也可以超过数组规定的个数。

字符串

字符串是存放在内存当中连续字节中的一系列字符。c++处理字符串的方式有两种,一种是具有c风格的,一种是基于string类库的方法。

c风格字符串

c风格字符串以空字符结尾,ascll码为0,用来标记字符串的结尾。

字符数组初始化为字符串的方法:

  1. char dog={'a','b','c','\0'};//加上空字符将显示三个字符。
    char dog[4]="abc";//隐含了空字符
    char dog[]="abc";

    注:最后两种是字符串常量初始化方法,也称为字符串字面值。计算元素更安全但是会浪费空间。

拼接字符串常量

        一行显示不完全时,c++可以使用两个引号将其分开,中间间隔空格(空格,制表符,换行符)连接,最后都可以拼接成一个字符串。第一个字符串的空格将被第二个字符串的空格取代,两串之间没有空格。

在数组中使用字符串

  1. 将数组初始化为字符串常量
  2. 将键盘或者是文件输入到数组中
  3. 利用标准c语言当中cstring头文件和strlen求字符串的长度。它返回的是字符串的长度而不是数组的长度,所以数组的长度是strlen+1.

结构简介

同一结构可以存放不同种类的数据类型,但是数组不可以,结构是由用户定义。

struct inflacteble//struct是结构布局的关键字
{
    char name[20];
    float volume;
    double price;
};//结构体结尾记得放分号

程序清单4.11

注:等号可以有也可以没有

//#include<iostream>//程序清单4.11
//struct inflatable
//{
//	char name[20];
//	float volume;
//	double price;
//};
//
//int main()
//{
//	using namespace std;
//	inflatable guest =
//	{
//		"clorious gloria",
//		1.88,
//		29.99,
//	};
//	inflatable pal =
//	{
//		"audacious arthur",
//		3.12,
//		32.99,
//	};
//	cout << "expand your guest list with" << guest.name;
//	cout << "and" << pal.name << endl;
//	cout << "you can have ";
//	cout << guest.price + pal.price << endl;
//	system("pause");
//	return 0;
//}//结构体

结构体初始化

inflatable mayor{};//各个成员将被赋值为0

注:也可以将string类作为成员,如std::string name;

其他结构属性

可以将结构作为参数返回给函数,也可以让函数返回一个结构,还可以使用赋值将一个类型形同的结构赋值给另一个类型相同的结构。

将一个类型相同的结构赋给另一个类型相同的结构

bouquet:sunflower for$11
choice:sunflower for$11
直接用等号引用

注:定义完结构还可以直接定义结构变量和给结构变量赋初值。

结构数组

#include<iostream>
struct inflatable
{
	char name[20];
	float volume;
	double price;
};
using namespace std;
int main()
{
	inflatable guests[2] =
	{
		{"a",0.5,21.99},
		{"b",2000,565.99}
	};
	cout << "the guests" << guests[0].name << "and" << guests[1].name
		<< "have a combined volume of"
		<< guests[0].volume + guests[1].volume << "cubic feet";
	system("pause");
	return 0;
}

结构中的位字段

??????

共用体

(union)共用体是一种数据格式,它能构存储不同类型的数据,但是只能同时存储一种数据。

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

注:可以使用one4all来存三个类型的变量,条件是不在同一时间进行。

one4all pail;

pail.int_val=15;

cout<<pail.int_val;

pail.long_val=1111;

cout<<pail.long_val

注:共用体的用处之一,当数据项使用两种或者多种格式时,可以节省空间。匿名共用体没有名称,因此成员将位于相同地址处的变量。

#include<iostream>
using namespace std;
struct widget
{
	char brand[20];
	int type;
	uniom//这里后面还有一个名称
	{
		long id_num;
	char id_char[20];
	}//因为两个的地址都是一样的,所以不需要中间标识符id_val;
};
widget price;
if (prize.type == 1)
cin >> prize.id_char;
else
cin >> prize.id_char;

枚举

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

#include<iostream>
using namespace std;
int main()
{//枚举是整形
	enum spectrum { red, orange, yellow, green, blue, violet, indigo, u;traviolet };
	//spectrum称为枚举,括号里面的单词被称为常量,0~7
	spectrum band;//可以用枚举来声明一种变量
	band = orange;
	band = 2000;//前者可以后者不可以,因为它只有括号里面8个可能的值
	band = orange;
	++band;//不可行
	band = orange + red;//枚举只定义了赋值运算符
	int color = blue;
	band = 3;//虽然3对应的枚举量是green,但这样赋值依旧显示错误
	color = 3 + red;//它被转换成int变成一个算数表达式,变成3+0则可行
	band = spectrum(3);//将3强制转换成枚举型赋值给band,前提是int值有效
	band=spectrum(40003)//如果对一个不适当的值进行转换
	system("pause");
	return 0;
}

设置枚举量的值


enum bits {one=1,tow=2};//指定的值必须是整数,默认情况下是0开始,枚举量的值可以多个一样
默认情况下枚举量的值等于前面一个值加1,早期只能是int值或者是提升为int的值赋给枚举,现在可以是long 或者是long long型

枚举的取值范围

对于枚举来说,只有在声明中指出的值是有效的,但是c++可以通过强制类型转换,增加可附加给枚举的合法值,每个枚举独有取值范围,将通过强制转换将取值范围内的任何整数转化成枚举值。

注:找到最大的那个定义的取值,2的最小幂大于它再减去1则得到取值范围的最大值,最小值也是一样的算法。

选用多少空间来存储枚举是由编译器决定,对于范围小的一般是一个字节或者是更小的空间,包含long型的枚举则选用四个字节。

整形和int型的区别

?????

指针和自由存储空间

指针是一个变量,存储的值是一个地址而不是本身。常规变量的地址就是在前面加上一个取地址符号&,打印时直接取地址符号加常规变量名称。 值是指定的量,而地址是派生量。处理存储数据恰好相反,地址是指定的量,而值是派生量。

*运算符被称为间接值或者解引用运算符,将其运用于指针,则可以的到该位置存放的值。

声明和初始化指针

计算机必须跟踪和指定指针的值的类型。

//声明和初始化指针
int* p_updatas;//p_updatas是指针,而前面加一个*则表示是int类型
int* a;
int * a;
int *a;//这样定义都可以
int* a, b;//定义的是一个指针和一个变量
int higgens = 5;//初始化指针
int* pt = &higgens;//将pt的值设置为higgens的地址

指针的危险

在c++创建指针时,计算机分配用来存放地址的内存,但是不会分配用来存放指针所指的数据的内存,所以应由我们为数据提供一个空间

long *fellow=223544;

没有使用取地址符号,这样的话地址就不一定是223544的地址,但是程序编译时随便将一个地址赋值进去,就很难发现问题。

指针和数字

指针不是整形,虽然计算机一直将它作为一个整形来处理,所以不能简单的将整形赋值给指针。

int *pt;
pt=(int *)0x565234;

注:强制转化,赋值两边都是整数赋值才有效,pt是int值地址不意味着pt就是int型。

使用new来分配内存

指针是一个为了通过名称而访问内存的一个别名,指针真正的作用是在运行的阶段分配未命名的内存以存值,c或c++可以使用malloc分配内存,更好的是c++中的new。

int *pn=new int;

new int告诉程序,需要适合存储int的内存,找到这样的内存然后返回地址,将地址存在pn中,pn是被声明为int的指针,现在pn是地址,而*pn是那里的值,pn指向的是为数据分布内存的内存块。

为一个数据对象(可以是结构,或者是基本类型)分配内存的格式如下:

typename *pointer_name=new typename;

注:对于指针,new分配的内存块通常与常规变量声明的内存块不同,变量都是分配在栈的内存区域中,而new则是被分在堆或者是自由区域中/

内存耗尽问题

使用delete释放内存

使用完内存后将其余归还给内存值,归还或者释放的内存可供其他程序使用。

int *ps=new int;
delete ps;

这是释放ps的内存,但是不会删除ps指针本身。

int *ps=new int;
delete ps;
delete ps;//不可以尝试释放已经释放过的内存块,结果是不确定的
int jugs=5;
int *pi=&jugs;
delete pi;//不可以使用它来释放声明变量所获得的内存

delete对空指针是安全的。

使用new来创建动态数组

如果通过声明来创建数组,则在程序编译时都会给数组分配空间,不管程序最终是否会用到数组,都会占有内存,在编译时给数组分配内存被称为静态联编,意味着数组在编译的时候加入到程序中。

new使用时,如果运行阶段需要数组则创建它,不需要则不创建,还可以在运行时选择数组的长度,这是动态联编。静态则是编写程序时确定数组的长度。

使用new创建动态数组

int *psome=new int[10];//创建包含10个int的数组
delete[]psome;//当程序使用完new分配的内存块时,使用delete释放

注:new与delete的使用规则

  1. 不要使用delete来释放不是new分配的内存
  2. 不要使用delete来释放同一内存块两次
  3. 如果使用new【】来分配内存则应该使用delete【】来释放内存
  4. 如果使用new【】为一个实体分配内存,则delete没有括号
  5. 对空指针delete是安全的

psome是指向int(数组第一个元素的指针),由于编译器不能对psome指向10个整数的第一个元素进行跟踪,因此编写时必须让程序跟踪元素数目。

不能使用sizeof来确定动态分配的数组包含的字节数,为数组分配内存的通用格式:

type_name*pointer_namme=new type_name[num_elements];
short *ps=new short[100];

使用动态数组

将指针当作数组元素使用即可。

#include<iostream>
using namespace std;
int main()
{
	double* p3 = new double[3];
	p3[0] = 0.2;
	p3[1] = 0.5;
	p3[2] = 0.8;
	cout << "p3[1] is" << p3[1] << endl;
	p3 = p3 + 1;
	cout << "p3[0] is" << p3[0] << endl;
	cout << "p3[1] is" << p3[1] << endl;
	system("pause");
	return 0;
}

指针、数组和指针算数

指针和数组基本等价的原因是因为指针算数和c++内部处理指针的方式,指针变量增加1是对应的数据类型的字节数加1,原本指向下标是0。。。。

指针小结

  • 声明指针

double *pn;//表示pn是指向double的指针。

  • 给指针赋值

应该将内存地址赋值给指针。

double *pn;
double *pa;
char *pc;
double bubble=3.2;
pn=&bubble;
pc=new char;
pa=new double [30];
  • 对指针解引用

注:对指针解引用意味着或者指针所指向的值。

*ps=5;表示5就是指针所指向的值,也可以用指针表示所指向的值,ps【0】与*ps是一样的。

区别指针与指针所指向的值

int *pt=new int;//pt是指向int的指针,*pt完全等同于int类型的变量,pt才是指针。

数组名

c++将数组名视为第一个数组的地址。

指针算数

C++允许指针相加,加1的结果等于原来的地址加上指向对象占用的字节数,还可以进行指针的减法,减法所运算得到的数是整数,且两个指针的减法运算仅限于同一数组。

类型组合

struct anter
{
	int year;
};
//可以利用结构创建这种类型的变量、
anter s1, s2, s3;
//使用成员运算符访问成员
s1.year = 100;
//可以创建指向这种结构的指针
anter* pa = &289;
pa->year = 1039;//给指针赋值有效的地址后将使用间接成员运算符访问成员
//可以创建数组
anter arr[3];
arr[0].year = 149;//arr是数组,arr[0]是一个结构而arr【0】.year是结构的一个成员

数组的替代品

模板类vector-动态数组

可以在运行阶段设置vector对象的长度,也可以在末尾添加心得数据,还可以在中间插入新的数据。

使用vector注意事项

  • 必须包含头文件。且包含using指令
  • 模板使用不同的语法来指出它存储的数据类型
  • vector使用不同的语法来指定元素数。
vector <int>vi;
int n;
cin>>n;
vecter <double>vd(n);

注:vi是vector<int>的一个对象,由于对象在插入时可以自动调整长度,因此vi的初始值可以是0,常见的创建vector对象的方法。缺点是效率比数组的低。

vector <typename>vt(n_elem(参量))//参量可以是常量也可以是变量

模板类array

如果需要固定的长度则创建数组,代价是不方便和安全,

array<int,5>ai;//ai是数组名称,包含5个类型。类型必须是常量

比较数组、vector对象和array对象

无论是数组还是vector还是array,都可以使用标准数组表示法来访问其元素,array可以将一个对象赋值给另一个对像,但是数组则需要一一赋值,vector对象存放的位置与其他存放的位置不同。

c++派生和继承

继承和派生的概念
继承:在定义一个新的类B时,如果该类与某 个已有的类A相似(指的是B拥有A的全部特点), 那么就可以把A作为一个基类,而把B作为基 类的一个派生类(也称子类)。
派生类是通过对基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量
和成员函数。
派生类一经定义后,可以独立使用,不依赖于基类。
 派生类拥有基类的全部成员函数和成员变 量,不论是private、protected、public 。
在派生类的各个成员函数中,不能访问基类中的private成员。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值