C++期末复习

1.指针

cpp 复制代码
#include<iostream>
using namespace std;
int sum(int ar2[][4],int size){
	int total=0;
	for(int r=0;r<size;r++){
		for(int c=0;c<4;c++)
			total+=ar2[r][c];
	}
	return total;
}
int main(){
	int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
	int total=sum(arr,3);
	cout<<total<<endl;
	cout<<"arr[0][0]的地址:"<<arr<<endl;
	cout<<"arr[1][0]的地址:"<<arr+1<<endl;
	cout<<"arr[1][0]的地址:"<<*(arr+1)<<endl;
	cout<<"arr[1][0]的值:"<<*(*(arr+1))<<endl;
	cout<<"arr[1][2]的值:"<<*(*(arr+1)+2)<<endl;
	cout<<"arr[1][2]的地址:"<<*(arr+1)+2<<endl;
	int a[]={1,2,3,4,5,6,7,8,9,0},*p,*q;
	p=a;
	cout<<p[2]<<'\t'//<<&(p+2)<<'\t'//
	<<a+2
	//<<&(a+2)//
	<<'\t'<<&p[2]<<'\t'<<p<<'\t'<<&a<<'\t'<<&a[0]<<endl;
	cout<<p-q<<endl;
	cout<<"一维数组取地址"<<endl;
	cout<<"方法一:p(+i)"<<' '<<"首元素地址"<<p<<'\t'<<"p[2]的地址"<<p+2<<endl;
	cout<<"方法二:a(+i)"<<' '<<"首元素地址"<<a<<'\t'<<"p[2]的地址"<<a+2<<endl;
	cout<<"方法三:&p[]"<<' '<<"首元素地址"<<&p[0]<<'\t'<<"p[2]的地址"<<&p[2]<<endl;
	cout<<"方法四:&a[]"<<' '<<"首元素地址"<<&a[0]<<'\t'<<"p[2]的地址"<<&a[2]<<endl;
	cout<<"结论:a与p完全等价";
	cout<<"一维数组取值"<<endl;	
	cout<<"方法一:*(p+i)"<<' '<<"首元素的值"<<*p<<'\t'<<"a[2]的值(3)"<<*(p+2)<<endl;
	cout<<"方法二:*(a+i)"<<' '<<"首元素的值"<<*a<<'\t'<<"a[2]的值(3)"<<*(a+2)<<endl;
	
	return 0;
}
/*
78
arr[0][0]的地址:0x7afe00
arr[1][0]的地址:0x7afe10
arr[1][0]的地址:0x7afe10
arr[1][0]的值:5
arr[1][2]的值:7
arr[1][2]的地址:0x7afe18
3       0x7afdd8        0x7afdd8        0x7afdd0        0x7afdd0        0x7afdd0
2015083
一维数组取地址
方法一:p(+i) 首元素地址0x7afdd0        p[2]的地址0x7afdd8
方法二:a(+i) 首元素地址0x7afdd0        p[2]的地址0x7afdd8
方法三:&p[] 首元素地址0x7afdd0 p[2]的地址0x7afdd8
方法四:&a[] 首元素地址0x7afdd0 p[2]的地址0x7afdd8
结论:a与p完全等价一维数组取值
方法一:*(p+i) 首元素的值1      a[2]的值(3)3
方法二:*(a+i) 首元素的值1      a[2]的值(3)3
*.

2.static

cpp 复制代码
#include<iostream>
using namespace std;
int fun(){
	static int i=0;
	int s=1;
	s+=i;
	i++;
	return s;}
int main(){
	int i,a=0;
	for(i=0;i<5;i++){
		a+=fun();}
	cout<<a<<endl;
	return 0;
}

结果:15

在程序中,`static` 关键字修饰了函数 `fun()` 中的局部变量 `i`,这使其成为**静态局部变量**,具有以下关键特性:

1. **延长生命周期**

  • **普通局部变量**:在函数调用时创建,函数返回时销毁

  • **静态局部变量**:在程序开始运行时分配内存,直到程序结束才销毁(生命周期与全局变量相同)

**2. **保持值的持久性**

变量 `i` 的值在函数调用之间保持不变:

  • 第一次调用 `fun()` 时,`i` 被初始化为 0
  • 后续每次调用 `fun()` 时,`i` 都保留上一次调用结束时的值
  • 初始化 `=0` 只执行一次**

## 3. **作用域仍局限于函数内**

尽管生命周期是全局的,但 `i` 的作用域仍然只在 `fun()` 函数内部,外部代码无法直接访问它。

4. **具体执行过程分析**

```cpp

int fun(){

static int i=0; // 第1次调用时初始化为0,以后跳过初始化

int s=1; // 普通局部变量,每次调用都初始化为1

s += i; // s = 1 + i(i是静态变量,保留上次的值)

i++; // i自增1,保留到下次调用

return s;

}

```

5. **如果去掉 `static` 会怎样?**

```cpp

int fun(){

int i=0; // 普通局部变量,每次调用都重新初始化为0

int s=1;

s += i; // 每次 s = 1 + 0 = 1

i++; // i自增,但函数返回后i被销毁

return s; // 总是返回1

}

```

结果将是:1+1+1+1+1 = 5

总结

`static` 在这个程序中的作用是:**让局部变量 `i` 在函数调用之间保持其值的连续性**,从而实现了类似"计数器"的功能,记录函数被调用的次数(从0开始计数)。这是静态局部变量的典型应用场景之一。

3.for(l=0;l<6;l++) l最终等于6!

cpp 复制代码
#include<iostream>
using namespace std;
void f(float *p,float &b,int n){
	int l;
	for(l=0;l<n;l++)
		b+=*p++;
	b/=l;
}
const int N=6;
int main(){
	int l;
	float a[N]={1,2,3,4,5},c=0;
	f(a,c,N);
	cout<<c<<endl;
	return 0;
}

答案:2.5

(1+2+3+4+5)/6

4.复制构造函数的调用

cpp 复制代码
#include<iostream>
using namespace std;
class MyClass{
	public:
		MyClass(int n){number=n;}
		MyClass(MyClass &other){number=other.number;cout<<"调用了复制构造函数"<<endl;}
		~MyClass(){}
	private:
		int number;
};
MyClass fun(MyClass p){
	MyClass temp(p);
	return temp;
}
int main(){
	MyClass obj1(10),obj2(0);
	MyClass obj3(obj1);
	obj2=fun(obj3);
	return 0;
}

调用了4次

程序执行过程中,`MyClass` 类的复制构造函数被调用的次数为 **4 次**。

详细分析:

  1. **`MyClass obj3(obj1);`**

用 `obj1` 初始化 `obj3`,调用 1 次复制构造函数。

  1. **函数调用 `fun(obj3)` 时的参数传递**

形参 `p` 通过值传递的方式用 `obj3` 初始化,调用 1 次复制构造函数。

  1. **`fun` 函数内部定义 `temp` 对象**

`MyClass temp(p);` 用 `p` 初始化 `temp`,调用 1 次复制构造函数。

  1. **`fun` 函数返回 `temp` 对象**

返回 `temp` 时,理论上会用 `temp` 构造一个临时对象,调用 1 次复制构造函数(假设无编译器优化)。

> **注意**:赋值操作 `obj2 = fun(obj3);` 使用默认的赋值运算符,不调用复制构造函数。
**第4次复制构造函数的调用发生在函数 `fun` 返回时**,这是最容易忽略的一点。让我详细解释:

函数返回值的处理过程

```cpp

MyClass fun(MyClass p){ // 参数p通过复制构造函数传入(第2次)

MyClass temp(p); // temp通过复制构造函数初始化(第3次)

return temp; // 返回时,temp复制到临时对象(第4次)

}

```

关键机制:返回值的临时对象

  1. **函数按值返回对象时**,需要创建一个临时对象来保存返回值

  2. **这个临时对象是通过复制构造函数创建的**

  3. **创建源**:局部对象 `temp`

  4. **创建目标**:编译器生成的临时对象

执行流程可视化

```cpp

// main函数中:

obj2 = fun(obj3);

// 实际执行过程:

  1. 调用fun(obj3),参数传递:复制构造生成p ← obj3(第2次)

  2. fun内部:复制构造生成temp ← p(第3次)

  3. fun返回:复制构造生成临时对象 ← temp(第4次)

  4. 临时对象赋值给obj2(调用赋值运算符,不是复制构造)

  5. 临时对象销毁

```

如果不理解,看这个简单例子

```cpp

MyClass getObject() {

MyClass obj(10);

return obj; // 这里也会调用复制构造函数

}

```

当函数返回局部对象时,C++需要将局部对象的值传递给调用方,这是通过:

  1. 创建一个临时对象

  2. 用局部对象初始化这个临时对象(调用复制构造函数)

  3. 调用方使用这个临时对象

重要区别:复制构造函数 vs 赋值运算符

```cpp

MyClass a(1);

MyClass b = a; // 复制构造函数(对象b正在被定义)

MyClass c(2);

c = a; // 赋值运算符(对象c已经存在)

// 函数返回的情况类似:

obj2 = fun(obj3); // fun返回临时对象,然后赋值给已存在的obj2

// fun返回时需要创建临时对象 ← 复制构造函数

// obj2 = 临时对象 ← 赋值运算符

```

所以第四次复制构造函数的调用发生在函数返回创建临时对象时,这是C++按值返回对象的固有机制。

相关推荐
草莓熊Lotso2 小时前
Linux 命令行参数与环境变量实战:从基础用法到底层原理
linux·运维·服务器·开发语言·数据库·c++·人工智能
枫叶丹42 小时前
【Qt开发】Qt系统(七)-> Qt网络安全
c语言·开发语言·c++·qt·网络安全
草莓熊Lotso2 小时前
Qt 控件核心入门:从基础认知到核心属性实战(含资源管理)
运维·开发语言·c++·人工智能·后端·qt·架构
夏鹏今天学习了吗10 小时前
【LeetCode热题100(82/100)】单词拆分
算法·leetcode·职场和发展
mit6.82410 小时前
mysql exe
算法
2501_9011478311 小时前
动态规划在整除子集问题中的应用与高性能实现分析
算法·职场和发展·动态规划
中草药z11 小时前
【嵌入模型】概念、应用与两大 AI 开源社区(Hugging Face / 魔塔)
人工智能·算法·机器学习·数据集·向量·嵌入模型
知乎的哥廷根数学学派11 小时前
基于数据驱动的自适应正交小波基优化算法(Python)
开发语言·网络·人工智能·pytorch·python·深度学习·算法
ADI_OP12 小时前
ADAU1452的开发教程10:逻辑算法模块
算法·adi dsp中文资料·adi dsp·adi音频dsp·adi dsp开发教程·sigmadsp的开发详解