C++学习之第五天

一、选择题

1、执行以下程序

char *str;
cin >> str;
cout << str;
若输入abcd 1234,则输出(D)
A. abcd        B. abcd 1234         C.1234         D. 输出乱码或错误

str是一个char*型指针,未初始化,是一个野指针。所以往该地址输入会coredump;

2、执行以下程序

char a[200];
cin.getline(a, 200, ' ');
cout << a;
若输入abcd 1234,则输出(A)
A. abcd      B. abcd 1234      C.1234      D. 输出乱码或错误

cin.getline(char* buf, std::streamsize count,char_type delim = '\n');

buf--->接受cin输入流的对象
count--->最多接受字符书
delim--->接受停止标识符,默认为'\n'

二、解答题

1.new/和delete的工作步骤

new的工作步骤:

1、调用名为operator new的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的

一个对象

2、运行该类型的一个构造函数初始化对象

3、返回指向新分配并构造的构造函数对象的指针  

delete的工作步骤:

1、调用析构函数,回收对象中数据成员所申请的资源

2、调用名为operator delete的标准库函数释放该对象所用的内存 
 

2.对象的销毁与析构函数的调用是不是等价的?

对于栈对象,本句话是对的,但是对于堆对象而言,析构函数的的调用只是对象销毁中的一个步骤,先去调用对象的析构函数,再去调用operator delete函数来释放自身。

3.创建栈对象的条件是什么?

1.能访问构造函数进行初始化 2.能执行析构函数进行销毁。

**4.标准IOStream,简述4种流的状态,Linux下ctrl+z、ctrl+c,ctrl+d各种代表什么**

4种流的状态:
1.badbit:使用bad函数进行测试,是一个无法恢复的系统级错误
2.failbit:使用fail函数进行测试,是一个可恢复的错误,可以用cin.clear()来重置流的状态,
然后用cin.ignore来清空缓冲区
3.eofbit:使用eof函数进行测试,表明文件指针到达文件末尾
4.goodbit:使用good函数进行测试,表明流的状态是正常的,才可以进行接下来的操作

ctrlt+z--->挂起,把进程挂起到后台
ctrl+c---->中断,终止进程
ctrl+d----->表示 EOF,是发送一个exit信号,

5.为什么内存对齐,内存对齐的规则?

为什么内存对齐?------如果不进行内存对齐,访问数据的时候可能会造成二次访问

内存对齐的规则:

1、数据成员对齐规则结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset(偏移)为0的地方,以后每个数据成员的对齐按照 #pragma pack 指定的数值和这个数据成员自身长度中,比较小的那个进行

#pragma pack(8)
struct x
{
	char a;
	int b;
	short c;
	char d;
}MyStructX;//12
0 1 2 3 4 5 6 7
a x x x b b b b 
c c d x
所以是12

struct y
{
	int b;
	char a;
	char d;
	short c;
}MyStructY;//8

0 1 2 3 4 5 6 7
b b b b a d c c --->8,
    

2、结构(或联合)的整体对齐规则 在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照 #pragma pack 指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

#pragma pack(8)
struct SS
{
	int a;
	char b;
	short c;
	int d;
	struct FF
	{
		int a1;
		char b1;
		short c1;
		char d1;
	}MyStructFF;
	char e;
}MyStructSS;
0  1  2  3  4  5  6  7 
a  a  a  a  b  x  c  c
d  d  d  d  a1 a1 a1 a1
b1 x  c1 c1 d1 x  x  x	//FF结构体中最小为int,内存对齐
e  x  x  x 
所以是28

3、结构体作为成员如果一个结构里有某些结构体成员,则内部结构体成员要从成员最大元素大小的整数倍和 #pragmapack指定的数值中最小的一个的整数倍的地址开始存储。#pragma pack(n) 对齐系数

struct DD
{
	int a;
	char b;
	short c;
	int d;

	struct FF
	{
		double a1;
		char b1;
		short c1;
		char d1;
	}MyStructFF;

	char e;//40

}MyStructDD;

0	1	2	3	4	5	6	7
a	a	a	a	b   x	c	c
d	d	d	d	x	x	x	x //FF结构体里面最大的是double,结构体对齐
a1	a1	a1	a1	a1	a1	a1	a1
b1	x	c1	c1	d1	x	x	x	//结构体对齐,因此总字节为40

三、编程题

1、分别实现new/delete表达式中只能生成栈对象的代码和只能生成堆对象的代码

a.new/delete工作测试代码:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include<string>


class Student
{
public:
	Student(int id, const char *name)
		:_id(id)
		, _name(new char[strlen(name) + 1]())
	{
		cout << "Student()构造函数" << endl;
		strcpy(_name, name);
	}

	~Student()
	{
		if (_name)
		{
			
			delete[]_name;
			_name = nullptr;
		}
		cout << "~Student()析构函数" << endl;
	}

	void *operator new(size_t sz)
	{
		cout << "operator new" << endl;
		void *ret = malloc(sz);
		return ret;
	}

	void operator delete(void *pointer)
	{
		cout << "operator delete" << endl;
		free(pointer);
	}

	void print()const
	{
		cout << "id:" << _id << endl
			<< "name:" << _name << endl;
	}
private:
	int _id;
	char *_name;
};
//1.问题1:对象的销毁和执行析构函数是不是等价的?
//--1.对于栈上的对象,是等价的 2.对于堆上的对象,析构函数的调用只是对象销毁的一个步骤,真正的销毁是在operator的delete里
//2.问题2:成员函数operator new和delete是否有this指针   ----没有,operator new/delete 是全局静态函数,全员共享
//3.问题3:将operator new/delete函数放在类外且不加类名与作用域限定符,又会产生什么现象,该如何解释?
void test01()
{
	Student *pstu = new Student(100, "Jackie");//1.申请空间 2.调用构造函数 3.返回指针。
	pstu->print();

	delete pstu;

	//Student St = Student(20, "Jerry");
	//St.print();
}
int main()
{

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

b.只能在栈中生成对象: 把operator new/delete函数设置成私有

栈对象存在的条件:1.能访问构造函数进行初始化 2.能执行析构函数进行销毁。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include<string>

/*
使用new表达式的时候,发生的三个步骤:
1.调用名为operator new的标准库函数,分配足够大的原始未初始化的内存,
2.运行调用类型的一个构造函数来初始化对象
3.返回指向新分配构造函数对象的指针。

使用delete的工作步骤:
1.调用析构函数,回收对象中数据成员所申请的资源
2.调用operator delete 的标准库函数释放该对象所用的内存
*/
class Student
{
public:
	Student(int id, const char *name)
		:_id(id)
		, _name(new char[strlen(name) + 1]())
	{
		cout << "Student()构造函数" << endl;
		strcpy(_name, name);
	}

	void print()const
	{
		cout << "id:" << _id << endl
			<< "name:" << _name << endl;
	}


	~Student()
	{
		if (_name)
		{

			delete[]_name;
			_name = nullptr;
		}
		cout << "~Student()析构函数" << endl;
	}
private:
	int _id;
	char *_name;

	void *operator new(size_t sz)
	{
		cout << "operator new" << endl;
		void *ret = malloc(sz);
		return ret;
	}

	void operator delete(void *pointer)
	{
		cout << "operator delete" << endl;
		free(pointer);
	}


};

void test01()
{
	//Student *pstu = new Student(100, "Jackie");//1.operator new/delete设置成私有后,用new时会拒绝访问,因此会报错
	//pstu->print();

	//pstu->destroy();

	Student St = Student(20, "Jerry");//
	St.print();
}
int main()
{

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

c.只能在堆中生成对象:

        1、只需要把析构函数设为私有

         2.还需要在类里面第一一个函数来销毁堆对象

        3、在类中执行delete this的时候,先去调用析构函数来释放类中的成员,再通过operator delete来释放自身

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include<string>

/*
使用new表达式的时候,发生的三个步骤:
1.调用名为operator new的标准库函数,分配足够大的原始未初始化的内存,
2.运行调用类型的一个构造函数来初始化对象
3.返回指向新分配构造函数对象的指针。

使用delete的工作步骤:
1.调用析构函数,回收对象中数据成员所申请的资源
2.调用operator delete 的标准库函数释放该对象所用的内存
*/
class Student
{
public:
	Student(int id, const char *name)
		:_id(id)
		, _name(new char[strlen(name) + 1]())
	{
		cout << "Student()构造函数" << endl;
		strcpy(_name, name);
	}

	void *operator new(size_t sz)
	{
		cout << "operator new" << endl;
		void *ret = malloc(sz);
		return ret;
	}

	void operator delete(void *pointer)
	{
		cout << "operator delete" << endl;
		free(pointer);
	}

	void destroy()
	{
		if (this)
		{
			delete this;//会跑去调用析构函数,先把成员函数释放掉,再来运行operator delete函数,把自身释放掉
			
		}
		
	}
	void print()const
	{
		cout << "id:" << _id << endl
			<< "name:" << _name << endl;
	}
private:
	int _id;
	char *_name;
	

	~Student()
	{
		if (_name)
		{

			delete[]_name;
			_name = nullptr;
		}
		cout << "~Student()析构函数" << endl;
	}

};

void test01()
{
	Student *pstu = new Student(100, "Jackie");//1.申请空间 2.调用构造函数 3.返回指针。
	pstu->print();

	pstu->destroy();

	//Student St = Student(20, "Jerry");//把析构函数放在私有权限下,会error报错
	//St.print();
}
int main()
{

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

四、算法题(选做,如果做不出来可以不做)

1、题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include<string>
class Solution
{
public:
	void odd(int *array, int len)
	{
		int k = 0;
		for (int i = 0; i < len; i++)
		{
			if (array[i] % 2 != 0)
			{
				int temp = array[i];
				array[i] = array[k];
				array[k] = temp;
				k++;
			}

		}
	}
};
int main()
{
	Solution s1;
	int array[10] = { 1,2,3,4,5,6,7,8,9,10 };

	s1.odd(array,10);

	for (int i = 0; i < 10; i++)
	{
		cout << array[i] << endl;
	}



	system("pause");
	return EXIT_SUCCESS;
}

猜你喜欢

转载自blog.csdn.net/weixin_49278191/article/details/121057216