C++类和对象——第二关

news2024/9/29 3:28:20

目录

类的默认成员函数:

(一)构造函数

(二)析构函数

(三)拷贝构造函数


类的默认成员函数:

类里面有6个特殊的成员函数分别包揽不同的功能;

(一)构造函数

说明:C++把类型分成内置类型(基本类型)和⾃定义类型。内置类型就是语⾔提供的原⽣数据类型,如:int/char/double/指针等,⾃定义类型就是我们使⽤class/struct等关键字⾃⼰定义的类型。

构造函数的特点:

(1)自动调用,在类实例化对象的时候会自动的调用构造函数。

(2)构造函数没有返回值(啥都不写,而不是说写void),名字和当前类的名字相同。

(3)构造函数可以分为三种,1.没有形参的构造,2.全缺省参数的构造,3.自动生成的构造,编译器默认生成的是无参构造。他们三个只能存在一个。如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦⽤⼾显式定义编译器将不再⽣成。

因为在调用的时候不需要传递任何的参数,所以构造函数总结下来可以称之为0实参构造函数。

自己写了构造函数,(编译器不再生成)。

class Date {
private:
	int _year;
	int _month;
	int _day;

public:
	Date(int year = 1999, int month = 01, int day = 01) // 自己定义的全缺省构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
	}

};

int main()
{
	Date d1(2024, 9, 23);
	Date d2;

	cout << "传参了:" << endl;
	d1.Print();

	cout << "没有传参:" << endl;
	d2.Print();

	return 0;
}

去掉自己写的构造函数的时候(使用的是编译器的默认构造):

class Date {
private:
	int _year;
	int _month;
	int _day;

public:
	//Date(int year = 1999, int month = 01, int day = 01) // 自己定义的全缺省构造函数
	//{
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//}

	void Print()
	{
		cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
	}

};

int main()
{
	//Date d1(2024, 9, 23);
	Date d1; 
	Date d2;

	cout << "传参了:" << endl;
	d1.Print();

	cout << "没有传参:" << endl;
	d2.Print();

	return 0;
}

这里可以看到,编译器初始化成员变量是随机值。

因为c++没有明确规定构造函数的初始化规则,所以不同的编译器会有不同的初始化规则,在vs上可能会初始化为随机值,但是在其他编译器上可能就不一样,构造函数中编译器对内置类型是没有确定处理的。

同样一段代码,我们放到devc++中执行的结果:编译器的初始化结果和vs是不一样的。

tips:正因为默认的构造函数初始化打击不确定的,所以大多数构造函数都是需要自己写的。

ps:想要redpanda dev编译器的可以私我给发。

(4)构造函数支持函数重载

我们可以写着两个构造函数,无参构造和全缺省构造函数,但是会产生调用歧义。

class Date {
private:
	int _year;
	int _month;
	int _day;

public:
	Date(int year = 1999, int month = 01, int day = 01) // 自己定义的全缺省构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	 
	
	// 自己定义的无参数的默认构造函数
	//Date() 
	//{
	//	_year = 1999;
	//	_month = 07;
	//	_day = 12;
	//}

	// 自己定义的带参默认构造
	//Date(int year, int month, int day)
	//{
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//}

	void Print()
	{
		cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
	}

};

int main()
{
	Date d1; 
	Date d2(2024,2,3);

	cout << "传参了:" << endl;

	cout << "没有传参:" << endl;
	d2.Print();

	return 0;
}

还有就是:在创建对象调用的时候,是无参构造就不需要给对象传参了,是有参数构造的必须要传参,不然编译器会报错的。

(5)为了更深层次的理解构造函数,我们使用C++来实现一个栈的初始化和压栈操作:

#include <stdlib.h>
#include <iostream>
using namespace std;
class stack {
private:
	int _top;// 栈顶
	int _capacity; // 数组空间的大小
	int* _arr; // 使用动态数组来实现栈

public:
	stack(int n = 4) // 实现构造函数,和init函数差不多
	{
		_top = 0;
		_capacity = 4;
		_arr = (int*)malloc(sizeof(int) * _capacity);//先预开辟4*4 = 16个字节的空间
	}

	// 压栈入数据
	void push(int x)
	{
		// 判断栈是否满了
		if (_top == _capacity) // 如果栈满了,就重新开空间
		{
			int newcapacity = _capacity * 2;
			int* tmp = (int*)realloc(_arr, sizeof(int) * newcapacity);
			if (tmp == nullptr)
			{
				cout << "realloc fail!" << endl;
				return;
			}
			_capacity = newcapacity;
			_arr = tmp;
		}
		_arr[_top] = x;
		_top++;
	}
};

int main()
{
	stack st;
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);
	st.push(5);

	return 0;
}

可以看到我们写的栈的初始化函数就是构造函数我们没有手动调用,它在程序执行过程中自动调用了。

(二)析构函数

和构造函数相反对应的是析构函数,它们可以说是相辅相成。

C++规定对象在销毁时会⾃动调⽤析构函数,完成对象中资源的清理释放⼯作。

析构函数的特性:

(1)函数名和对象名一样,没有返回值,没有参数,定义时在函数名前面加~:

(2)同构造函数一样,一个类只能存在一个析构函数,构造函数在创建对象时调用,析构函数在对象生命周期结束的时候调用。

class Date {
private:
	int _year;
	int _month;
	int _day;

public:
	Date(int year = 1999, int month = 01, int day = 01) // 自己定义的全缺省构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
	// 自己写的析构函数
	~Date()
	{
		cout << "这里调用了析构函数:~Date()" << endl;
	}
	void Print()
	{
		cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
	}

};

int main()
{
	Date d1;
	// 这里定义的两个对象没有显示的调用析构函数如:d1.Date().
	Date d2;

	return 0;
}

step1:d1和d2两个对象当代码执行到return 0;这句代码的时候生命周期结束,我们在这句代码处打一个断点进行调试。

step2:我们接下来对代码进行逐步调试,发现代码直接跳到了我们刚自己实现的析构函数的位置

step3:程序继续执行,执行完析构函数内的程序代码之后打印结束,程序结束。

在调用析构函数的时候,有几个对象就析构几次,可以看到我们创建了两个析构函数,打印了两次。因为在main的函数栈帧中,执行规则和数据结构的栈的执行规则差不多,都是后进先出,所以在析构多个对象的时候,遵循先定义的后析构,也可以理解为生命周期先结束的最后析构。

(3)跟构造函数类似,编译器默认⽣成的析构函数对内置类型成员不做处理,自定义类型成员会调⽤他的析构函数。

(4)还需要注意的是我们显⽰写析构函数,对于⾃定义类型成员也会调⽤他的析构,也就是说⾃定义类型成员⽆论什么情况都会⾃动调⽤析构函数

比如说:我们定义了一个类,里面存在另外一个类实例化的对象,我们在另一个类中实现了析构函数,在定义这个类实例化的对象的时候,这个实例化的对象生命周期结束的时候会去调用另一个类的析构函数。

(5)没有申请资源时,析构函数可以不写,有资源申请时,⼀定要⾃⼰写析构,否则会造成资源泄漏。

        在上面我面我们定义了一个栈的类做构造函数的例子,我们在写的时候申请了空间,但是我们没有将空间释放掉,也没有写析构函数,而编译器自己默认生成的析构函数只会清理内置类型的空间,所以其实已经造成了内存泄漏了,最终泄露的这块内存由操作系统回收。

        我们给它加上析构函数将开辟在堆上的空间释放掉。

#include <cstdlib>
#include <stdlib.h>
#include <iostream>

using namespace std;

class stack {
private:
	int _top;// 栈顶
	int _capacity; // 数组空间的大小
	int* _arr; // 使用动态数组来实现栈

public:
	stack(int n = 4) // 实现构造函数,和init函数差不多
	{
		_top = 0;
		_capacity = 4;
		_arr = (int*)malloc(sizeof(int) * _capacity);//先预开辟4*4 = 16个字节的空间
	}

	// 压栈入数据
	void push(int x)
	{
		// 判断栈是否满了
		if (_top == _capacity) // 如果栈满了,就重新开空间
		{
			int newcapacity = _capacity * 2;
			int* tmp = (int*)realloc(_arr, sizeof(int) * newcapacity);
			if (tmp == nullptr)
			{
				cout << "realloc fail!" << endl;
				return;
			}
			_capacity = newcapacity;
			_arr = tmp;
		}
		_arr[_top] = x;
		_top++;
	}

	// 自己写的析构函数
	~stack()
	{
		free(_arr);
		_arr = nullptr;
		_capacity = _top = 0;
	}
};

int main()
{
	stack st;

	return 0;

}

当然,如果可以也可以在析构函数里面申请空间,除非你有病。

(三)拷贝构造函数

需要理解的几个点:

(1)拷贝构造是构造函数的重载,他和构造函数一样,都是为了初始化一个对象。构造函数是初始化当前对象,拷贝构造是使用另一个函数来初始化当前对象。

(2)拷⻉构造函数的第⼀个参数必须是类类型对象的引⽤,使⽤传值⽅式编译器直接报错,因为语法逻辑上会引发⽆穷递归调⽤。拷⻉构造函数也可以多个参数,但是第⼀个参数必须是类类型对象的引⽤,后⾯的参数必须有缺省值。

假设不是类类型的对象引用——>引发无穷递归:

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	} 
		// 编译报错:error C2652 : “Date”: ⾮法的复制构造函数: 第⼀个参数不应是“Date”
		//Date(Date d)
		Date(const Date & d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		} 

		Date(Date  d) // 这里语法上是不允许的,只是为了举例。
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		} 

		void Print()
		{
			cout << _year << "-" << _month << "-" << _day << endl;
		}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2(d1);

	return 0;
}

tips:为了避免发生被拷贝对象成员被修改的情况,在拷贝构造函数的参数前面加一个const限定。如在上面的日期类的拷贝构造函数中:

Date(const Date&  d) //这里加一个const修饰能够避免源对象(d1)被修改
{
    _year = d._year;
    _month = d._month;
	_day = d._day;
}
 
int main()
{
	Date d1;
	Date d2(d1);

	return 0;
}

(3)C++规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造,⾃定义类型传值传参和传值返回都会调⽤拷⻉构造完成

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	} 

		Date(const Date&  d) //这里加一个const修饰能够避免源对象
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		} 

		void Print()
		{
			cout << _year << "-" << _month << "-" << _day << endl;
		}
private:
	int _year;
	int _month;
	int _day;
};

void func(Date d)
{
	d.Print();
}

int main()
{
	Date d1;
	Date d2(d1);

	func(d1); // 这里传值传参会调用拷贝构造

	return 0;
}

对代码进行调试运行过程如图:

(4)若未显式定义拷⻉构造,编译器会⽣成⾃动⽣成拷⻉构造函数。⾃动⽣成的拷⻉构造对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉)类似于memcpy函数,对⾃定义类型成员变量会调⽤他的拷⻉构造

(5)如果在定义对象(类)的时候产生了资源的申请,就需要自己写拷贝构造函数,同析构函数一样,是否有资源的申请决定是否需要自己写拷贝构造函数,一般需要自己写析构函数的话就需要自己写拷贝构造函数。

(4)(5)两点且看下面代码:

class stack {
private:
	int _top;// 栈顶
	int _capacity; // 数组空间的大小
	int* _arr; // 使用动态数组来实现栈

public:
	stack(int n = 4) // 实现构造函数,和init函数差不多
	{
		_top = 0;
		_capacity = 4;
		_arr = (int*)malloc(sizeof(int) * _capacity);//先预开辟4*4 = 16个字节的空间
	}

	// 压栈入数据
	void push(int x)
	{
		// 判断栈是否满了
		if (_top == _capacity) // 如果栈满了,就重新开空间
		{
			int newcapacity = _capacity * 2;
			int* tmp = (int*)realloc(_arr, sizeof(int) * newcapacity);
			if (tmp == nullptr)
			{
				cout << "realloc fail!" << endl;
				return;
			}
			_capacity = newcapacity;
			_arr = tmp;
		}
		_arr[_top] = x;
		_top++;
	}

	// 自己写的析构函数
	~stack()
	{
		free(_arr);
		_arr = nullptr;
		_capacity = _top = 0;
	}
};

int main()
{

	stack st1;

	stack st2(st1);//使用st1来初始化st2

	return 0;

}

当我们执行这段代码的时候会发生下列情况:

程序挂掉了,为什么?

我们来调试看一下:

对于这种情况我们就需要自己写一个拷贝构造函数了。

class stack {
private:
	int _top;// 栈顶
	int _capacity; // 数组空间的大小
	int* _arr; // 使用动态数组来实现栈

public:
	stack(int n = 4) // 实现构造函数,和init函数差不多
	{
		_top = 0;
		_capacity = 4;
		_arr = (int*)malloc(sizeof(int) * _capacity);//先预开辟4*4 = 16个字节的空间
	}

	// 压栈入数据
	void push(int x)
	{
		// 判断栈是否满了
		if (_top == _capacity) // 如果栈满了,就重新开空间
		{
			int newcapacity = _capacity * 2;
			int* tmp = (int*)realloc(_arr, sizeof(int) * newcapacity);
			if (tmp == nullptr)
			{
				cout << "realloc fail!" << endl;
				return;
			}
			_capacity = newcapacity;
			_arr = tmp;
		}
		_arr[_top] = x;
		_top++;
	}

	// 自己写的析构函数
	~stack()
	{
		free(_arr);
		_arr = nullptr;
		_capacity = _top = 0;
	}

	// 自己写的拷贝构造函数
	stack(const stack& st)
	{
		_capacity = st._capacity;
		_top = st._top;
		int new_capacity = st._capacity;
		int* tmp = (int*)malloc(sizeof(int) * new_capacity);//重新申请一片空间
		if (tmp == nullptr)
		{
			perror("malloc fail!");
			return;
		}
		_arr = tmp;
	}

};

执行代码重新调试看一下:

地址不一样了,我们重新申请了空间。

        在上面的代码调试过程中,我们发现使用编译器默认生成的拷贝构造函数不会申请空间,它会一个个字节的拷贝,拷贝动态数组的时候它拷贝的值动态数组指针变量的地址,并没有申请空间这一操作,我们将这种拷贝方式称为浅拷贝。而我们自己实现的拷贝构造函数自己申请了空间,我们将这种拷贝称为深拷贝。

        也可以使用等号的方式调用拷贝构造函数初始化对象,在承接上面的代码,我们定义一个新的对象,如:

int main()
{

	stack st1;

	stack st2(st1);//使用st1来初始化st2

	// 也可以使用等号的方式调用拷贝构造函数初始化对象
	stack st3 = st1; 

	return 0;

}

这样写不会报错。

(6) 传值返回会产⽣⼀个临时对象调⽤拷⻉构造,产生拷贝,传值引⽤返回,返回的是返回对象的别名(引⽤),没有产⽣拷⻉。但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使⽤引⽤返回是有问题的,这时的引⽤相当于⼀个野引⽤,类似⼀个野指针⼀样。传引⽤返回可以减少拷⻉,但是⼀定要确保返回对象,在当前函数结束后还在,才能⽤引⽤返回。

不能返回临时对象,返回临时对象是会销毁的,里面的各种指针就成了野指针,返回的是一个被销毁了的空间,所以引用这时候是这块被销毁的空间的别名。

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

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

相关文章

基于nodejs+vue的小型企业工资管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

[附源码]在线音乐系统+SpringBoot+Vue前后端分离

今天带来一款优秀的项目&#xff1a;在线音乐系统源码 。 系统采用的流行的前后端分离结构&#xff0c;内含功能包括 "管理后台"&#xff0c;“用户端”&#xff0c;“评论系统”&#xff0c;“歌手&#xff0c;歌曲管理”&#xff0c;“用户系统”,"统计"…

mapboxGL 离线部署或者说去除token最简单得方法

找到本项目中得node_modules包管理器中得mapbox-gl包 找打dist文件夹下得mapbox-gl-dev.js 相比于mapbox-gl.js得压缩文件 mapbox-gl-dev.js没有压缩&#xff0c;好修改&#xff0c;也无需要编译 在mapbox-gl-dev.js找到 this._authenticate()&#xff0c;注释或者去除即可 最…

tauri中加载本地文件图片或者下载网络文件图片后存储到本地,然后通过前端页面展示

有一个需求是需要将本地上传的文件或者网络下载的文件存储到本地&#xff0c;并展示在前端页面上的。其实如果只是加载本地文件&#xff0c;然后展示还是挺简单的&#xff0c;可以看我的文章&#xff1a;tauri程序加载本地图片或者文件在前端页面展示-CSDN博客 要想实现上述需…

【Linux】项目自动化构建工具-make/Makefile 详解

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…

关于车载视频监控的重要性及其发展趋势

一、车载视频监控的意义和概念 车载视频监控是专为车载安防领域打造的一款新型视频监控设备。随着社会的快速发展和科技的不断进步&#xff0c;安装车载视频监控设备已经成为社会发展的必然趋势。车载视频监控不仅关乎个人安全&#xff0c;更对企业的安全生产和管理起着至关重要…

可编辑PPT | 能源企业数字化框架、数字化运营及数字化平台建设方案

项目背景及需求理解 首先提出了全球能源互联网的概念&#xff0c;强调了清洁能源和电能替代的重要性&#xff0c;并介绍了德国工业4.0战略以及泛在电力物联网的创新。文档探讨了信息化与工业化的深度融合&#xff0c;以及云计算、大数据、物联网和移动应用等新技术在能源行业的…

克隆GitHub仓库中的一个文件夹

要只克隆GitHub仓库中的一个文件夹&#xff0c;你可以使用 git sparse-checkout 功能。以下是具体步骤&#xff1a; 克隆仓库&#xff08;使用 --no-checkout 选项&#xff0c;避免下载所有内容&#xff09;&#xff1a; git clone --no-checkout <仓库地址> 进入克隆的…

微信小程序组件封装使用

1.第一步先新建一个components组件的文件夹第二步在创建一个文件夹第三步在新建components 例如先封装一个VCaption头部导航组件

IvorySQL 3.4 来了

9 月 26 日&#xff0c;IvorySQL 3.4 发版。本文将带大家快速了解新版本特性。 IvorySQL 3.4 发版说明 IvorySQL 3.4 基于 PostgreSQL 16.4&#xff0c;修复了多个问题&#xff0c;并增强多项功能。 PostgreSQL 16.4 的变更 在未经授权时防止 pg_dump 执行&#xff0c;并引入一…

初识C语言(三)

感兴趣的朋友们可以留个关注&#xff0c;我们共同交流&#xff0c;相互促进学习。 文章目录 前言 八、函数 九、数组 &#xff08;1&#xff09;数组的定义 &#xff08;2&#xff09;数组的下标和使用 十、操作符 &#xff08;1&#xff09;算数操作符 &#xff08;2&#xff…

MySQL多版本并发控制MVCC实现原理

MVCC MVCC 是多版本并发控制方法&#xff0c;用来解决读和写之间的冲突&#xff0c;比如脏读、不可重复读问题&#xff0c;MVCC主要针对读操作做限制&#xff0c;保证每次读取到的数据都是本次读取之前的已经提交事务所修改的。 概述 当一个事务要对数据库中的数据进行selec…

AIGAME背后的强大背景与AI币价值的崛起

AIGAME平台背后汇集了强大的资本和技术支持&#xff0c;凭借蒙特加密产业基金的战略投资和汇旺集团的多元化Web3基础设施建设&#xff0c;AIGAME在全球范围内迅速崛起。平台所使用的Sleepless AI技术&#xff0c;结合区块链与AI的深度融合&#xff0c;赋能AI币&#xff0c;使其…

【hot100-java】【二叉树的直径】

R9-二叉树篇 左子树的深度右子树的深度即可 但好像不行 思路&#xff1a; 对于每个节点&#xff0c;计算它的左子树深度和右子树深度相加的和&#xff0c;并更新最大值。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode le…

海外社媒怎么运营?代理IP有必要吗?看这5个关键点就够了!

想要在海外社交媒体上大放异彩&#xff0c;但不知从何下手&#xff1f; 面对着Instagram、Facebook、Twitter等平台的海量用户&#xff0c;如何确保你的品牌能够脱颖而出&#xff1f; 如何在海外社交媒体上突破地域限制&#xff0c;实现全球覆盖&#xff1f; 别担心&#xf…

3D建模软件 | Blender v4.2.2 绿色版

Blender是一款功能强大的免费开源3D创作套件&#xff0c;适用于创建3D可视化效果&#xff0c;如静态图像、3D动画、视觉特效以及视频编辑。Blender以其跨平台兼容性、高效内存管理、统一的工作流程和活跃的社区支持而受到独立艺术家和小型工作室的青睐。 它提供了从建模、渲染…

AI爆火的今天,普通人如何利用AI赚钱?

AI是一门非常有前景和潜力的领域&#xff0c;而且赚钱也并非难事&#xff0c;可以说只是一层窗户纸的问题。我身边就有两个朋友&#xff0c;他们通过AI副业获得的收入甚至超过了他们的主要工作收入。更令人惊讶的是&#xff0c;学会AI并开始创造收入并不需要太多的技术背景&…

vue初学随笔

Vue基础 Vue基本概念 Vue是什么 Vue是一个渐进式的JavaScript框架&#xff0c;它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。 渐进式&#xff1a;各个特性可以根据项目需要逐渐引入和…

运算符两边的数据类型

6-3 类型转换 1.非赋值运算的类型转换 &#xff08;1&#xff09;水平方向的转换&#xff1a;所有的char型和short型自动地转换成int 型&#xff0c;所有的unsigned short 型自动地转换成unsigned型&#xff0c;所有的long型自动地转换成unsigned long 型&#xff0c;所有的f…

蓝桥等级考试C++组七级真题-2022-04-23

PDF及答案回复:LQDKC720220423 单项选择题 1、C L7 (15分) 执行以下程序后&#xff0c;输出结果是( )。 int a5; int b a; cout << a << " "<< b;A 5 5 B 5 6 C 6 5 D 6 6 2、CL7(15分) 执行以下程序后&#xff0c;输出结果是() int k0; for(…