C++ Primer第四章 复合类型问题以及感悟

本章主要介绍了数组、字符串、结构体、枚举、指针等基础知识。我在复习的基础上对自己感到薄弱以及比较细节的问题进行了一个梳理和总结。

1.数组的一般通用格式是什么?

typeName arrayName[arraySize] = {arrayElement1,arrayElement2,arrayElement3,...};

表达式中的typeName表示数据类型
arrayName表示数组名
ararySize表示数组中的元素数
1.但是根据c++的初始化格式,其中的"="可以省略,如下:

typeName arrayName[arraySize]{arrayElement,arrayElement,arrayElement,...};

2.另外当"{}"中不写任何内容或者元素只为零时(只要不超过元素个数,不管有几个零),表示数组元素全部置零,但字符类型数组元素全部置空字符\0,并且使用strlen()函数会发现结果为0个元素,这是因为strlen()并不计算空字符,就算数组中全为空字符,它也一个都不会记录下来,所以结果为0。
3.如果初始化数组时方括号[]内为空时,c++编译器将根据大括号{}中元素的个数来计算元素个数。
比如typeName arrayName[]={arrayElement1,arrayElement2,arrayElement3};
编译器会自动认定arrayName数组风中包含3个元素。
4.另外定义数组时才能初始化,此后就不能使用了,然而可以使用下标分别给数组中的元素赋值,初始化时可以只对数组中的一部分进行初始化,这意味着提供的值可以少于数组的元素数目。
5.列表初始化不允许缩窄转换,可以理解为数组中的高级元素类型类型不允许向低级的类型转换。

2.cout是怎么判断完成一串字符输出的呢?

我们可以先编译一下以下的代码

#include <iostream>
int main()
{
	char hand[7]{'a','b','c','d','e','f','g' };
	char finger[7]{ 'a','b','c','d','e','f','\0' };//cout判断数组是否结束是通过空字符,\
	用来标记字符串的结尾
	char flower[10] = "rose";
	std::cout << finger<<std::endl;
	std::cout << hand << std::endl;
	std::cout << flower[1] << std::endl;;
	
}

编译结果为
Alt
从上图我们可以看到finger数组能正常输出,我们知道这是c-字符串格式,但是hand数组并没有正常显示,在输出完数组中的元素后带了一串乱码,这是因为cout对象是根据空字符(\0)来判断一串字符是否输出完成的,之所以结果带有乱码,是因为cout在读取完hand数组后并没有遇到空字符(\0),所以他一直读取输出流中的数据,直到遇到空字符才停下。

#include <iostream>
int main()
{
	char hand[7]{'a','b','c','\0','e','f','g' };
	char finger[7]{ 'a','b','c','d','e','f','\0' };//cout判断数组是否结束是通过空字符,\
	用来标记字符串的结尾
	char flower[10] = "rose";
	std::cout << finger<<std::endl;
	std::cout << hand << std::endl;
	std::cout << flower[1] << std::endl;;
	
}

此时输出hand数组只会显示空字符\0之前的元素。
Alt

3.strlen()函数返回的是数组长度吗?

strlen()函数只计算可见的字符,而不把空字符计算在内,所以strlen()返回的是数组中字符串的长度,而不是数组的长度,数组的长度为strlen(arrayName)+1。

4.cin是如何确定已完成字符串的输入的?

cin使用空白(空格、换行符、制表符)等来确定字符串的结束位置,并且会自动在结尾添加空字符。
但是我们经常输出的字符串中总是包含空格的,那怎么办呢?
istram类中的成员函数getline()和get()都可以读取一行数据,直到遇到换行符,但是这两个函数又各有区别。
1.getline()它通过回车输入的换行符来确定输入结尾,但是不保存换行符。相反,在存储字符串时,它用空字符来替换换行符。
2.get()它读取到换行符判断读取结束,但是它并不再读取并丢弃换行符,而是将其留在输入队列中,这样当下一次需要写入数据时,cin.get(*)会首先从队列中读取到换行符,此时get()函数会认为已经到达行尾,而没有发现任何可读取的内容,这个时候需要用cin.get()的无参数的重载形式来跳过换行符,程序才能正常运行。

5. string类函数size()的用法和strlen()一样吗?

	string str = "明天会更好";
	int len = str.size();

size()和strlen()有相同的功能,但是size()是string类方法,他可以由string类对象str来调用,strlen()是c的常规函数,他们使用的句法不同。

6.未初始化的数组元素数和指定的arraySize元素数相同吗?

运行以下代码:

	char ch[20];
	cout << strlen(ch);

编译结果如下:
Alt
所以未初始化的数组内容是未定义的,其次函数strlen()从数组的第一个元素开始计算字节数,直到遇到空字符,而第一个空字符的出现位置是随机的,因此编译得到的数组长度很可能与指定的数组长度不同。

7.结构体可以将string类对象作为成员吗?

答案是可以的,但是需要std这个命名空间,否则会出现下面这种错误。切记!

严重性	代码	说明	项目	文件	行	禁止显示状态
错误	C4430	缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int	Test11	d:\c++文件\c++primer\test11\test11\test11.cpp	12	

8.结构体可以作为参数吗?可以让函数返回一个结构吗?

都是可以的,这里我们可以将结构体看做一种类,结构体类型变量可以看做对象。

9.设置枚举量的值

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

这里first默认设置为0,second手动设置为100,但是这时候third的值为101而不是1。
没有被初始化的枚举量的值要比其前面的枚举量大1。

10.动态为指针分配内存的格式

typeName* pointer_name = new typeName;

指向两种不同类型数据的指针长度相同,是因为它们都是地址,但是它们指向的数据的长度不一定相同。
对于new分配的内存块与常规分配的内存块不同,常规分配的数据类型都存储在stack栈中,这样只在需要的时候才分配内存,离开代码块时按反顺序释放内存,而new分配的内存是放在heap堆中,这种内存空间需要手动delete。

11.使用new和delete的规则

1.不要使用delete来释放不是new分配的内存
2.不要使用delete释放同一个内存块来两次
3.如果使用new []为数组分配内存,则应该相应使用delete[]来释放
4.不能使用sizeof运算符来确定动态分配的数组包含的字节数,因为动态分配是在程序运行时分配内存,编译器无法确定分配的内存。

12.为什么对空指针使用delete是安全的?

因为空指针的值为0,也为null,通常系统地址为0的内存是无法访问的,就算可以访问,c++保证空指针不会指向有效的数据,就像邮差送快递发现查无此人,所以对空指针使用delete并不会删除有用的内存。

13.数组名代表什么?

一般情况下数组名代表的是数组第一个元素的地址,但是有时候它代表整个数组的地址,虽然他们的值相同,但是其中的意义不同。
1.对数组名应用sizeof运算符时得到的是数组的长度,这种情况下,c++不会将数组名解释为第一个元素地址。
2.对数组名应用地址运算符时,得到的是整个数组的地址。

14.数组指针和指针数组的区分

short* p1[20]			//指针数组
short (*p2)[20]		    //数组指针

首先如何判断指针数组和数组指针,我是这样区分的,当p1和[]先结合时,这时候表示一个数组,然后short和""结合为"short * “表示指向short类型的指针,两部分结合起来就表示指向short类型的指针的数组,即指针数组。
当pas首先和”
"结合时,表示p2为一个指针,我们将(*p2)看做一个数组名(当然现在数组名还不确定),另外我们知道数组名可以表示数组首元素的地址,所以(*p2)就是指向数组首元素的指针,而p2就是指向数组首元素指针的指针,总结一下p2的值就是指向数组名的地址,所以称为数组指针,即指向数组名的指针嘛。
Alt

15.cout遇到字符数组名的输出是一个字符还是一串字符?

char flowers[20] = "rose";
cout<<flowers<<endl;

cout中char数组名被解释为字符串第一个字符的地址,但是cout并不只是打印char数组中的第一个字符,而是继续打印后面的字符,直到遇到空字符为止。所以上面的代码输出的是"rose"而不是’r’。
如果想要打印字符串的地址,需要强制转换为cout<<int(*) flowers<<endl;

16.为什么c++初始化字符指针数组时需要const前缀?

char指针数组初始化成了字符串常量数组,常量在常量区中,不可更改,所以必须用const修饰。
而c语言中并没有要求,这是比较有趣的一点,只能说c++在这方面更严谨了。

17.模板类vector和模板类array有什么区别?

vector类是动态数组,array是静态数组,区别就是可以在程序运行期间设置vector对象的长度,而array只能事先预定好固定的长度。我一般将vector和new数组对应,array和常规数组对应。相应的,array对象和数组存储在stack中,vector对象存储在heap中,这两个内存块是不相同的。

发布了22 篇原创文章 · 获赞 2 · 访问量 487

猜你喜欢

转载自blog.csdn.net/weixin_42709632/article/details/103879404
今日推荐