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 次**。
详细分析:
- **`MyClass obj3(obj1);`**
用 `obj1` 初始化 `obj3`,调用 1 次复制构造函数。
- **函数调用 `fun(obj3)` 时的参数传递**
形参 `p` 通过值传递的方式用 `obj3` 初始化,调用 1 次复制构造函数。
- **`fun` 函数内部定义 `temp` 对象**
`MyClass temp(p);` 用 `p` 初始化 `temp`,调用 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次)
}
```
关键机制:返回值的临时对象
**函数按值返回对象时**,需要创建一个临时对象来保存返回值
**这个临时对象是通过复制构造函数创建的**
**创建源**:局部对象 `temp`
**创建目标**:编译器生成的临时对象
执行流程可视化
```cpp
// main函数中:
obj2 = fun(obj3);
// 实际执行过程:
调用fun(obj3),参数传递:复制构造生成p ← obj3(第2次)
fun内部:复制构造生成temp ← p(第3次)
fun返回:复制构造生成临时对象 ← temp(第4次)
临时对象赋值给obj2(调用赋值运算符,不是复制构造)
临时对象销毁
```
如果不理解,看这个简单例子
```cpp
MyClass getObject() {
MyClass obj(10);
return obj; // 这里也会调用复制构造函数
}
```
当函数返回局部对象时,C++需要将局部对象的值传递给调用方,这是通过:
创建一个临时对象
用局部对象初始化这个临时对象(调用复制构造函数)
调用方使用这个临时对象
重要区别:复制构造函数 vs 赋值运算符
```cpp
MyClass a(1);
MyClass b = a; // 复制构造函数(对象b正在被定义)
MyClass c(2);
c = a; // 赋值运算符(对象c已经存在)
// 函数返回的情况类似:
obj2 = fun(obj3); // fun返回临时对象,然后赋值给已存在的obj2
// fun返回时需要创建临时对象 ← 复制构造函数
// obj2 = 临时对象 ← 赋值运算符
```
所以第四次复制构造函数的调用发生在函数返回创建临时对象时,这是C++按值返回对象的固有机制。