#include<bits/stdc++.h>
using namespace std;
class Array{
private:
int n;//数组大小
int *a;//数组
public:
// write your code here......
Array(){
cin >>n;
a = new int[n];
for(int i=0; i<n; i++){
cin>>a[i];
}
}
~Array(){
delete []a;
}
void show(){
for (int i=0;i<n;i++) cout<<a[i]<<' ';
}
};
int main(){
Array a;
a.show();
return 0;
}
你的两段代码核心差异是 「变量遮蔽(Name Hiding)」 —— 第二段构造函数里定义了局部变量 int* a,覆盖了类的成员变量 int* a,导致成员变量未被正确初始化,进而引发编译/运行错误(编译器可能不报错,但运行时必崩溃,你感知的“不正常编译”本质是运行逻辑错误)。
一、先拆解两段代码的核心区别
第一段(正常):给「成员变量a」赋值
Array(){
cin >>n;
a = new int[n]; // 这里的a是类的成员变量 int* a
for(int i=0; i<n; i++){
cin>>a[i]; // 给成员变量a指向的动态数组赋值
}
}
- 构造函数里的
a没有重新定义,直接指向类的成员变量int* a; - 执行
a = new int[n]后,成员变量a指向一块动态分配的数组内存; - 后续
cin>>a[i]给这块内存赋值,show()能正常访问,析构函数delete[]a也能正确释放内存。
第二段(异常):定义了「局部变量a」,遮蔽成员变量
Array(){
cin >>n;
int* a = new int[n]; // 这里定义了【局部变量】int* a,和成员变量同名
for(int i=0; i<n; i++){
cin>>a[i]; // 给局部变量a指向的数组赋值
}
}
这行 int* a = new int[n]; 是关键错误:
- 它在构造函数的局部作用域里,定义了一个新的指针变量
a,和类的成员变量int* a同名; - 编译器遵循「局部优先」原则:构造函数里所有的
a都会被识别为局部变量a,而非成员变量a; - 构造函数执行完毕后,局部变量a会被销毁(出作用域),但它指向的动态数组内存没有被释放(内存泄漏);
- 类的成员变量
a从头到尾都是「空指针(nullptr)」(未被赋值)。
二、为什么第二段“不正常”?(运行时必崩溃/报错)
虽然第二段代码语法上没有编译错误(编译器不会提示语法问题),但运行时会触发两个致命问题:
问题1:show() 函数访问空指针,触发崩溃
show() 里的 a[i] 访问的是成员变量a(空指针),对空指针解引用(a[i] 等价于 *(a+i))是C++的「未定义行为」,直接导致程序崩溃(比如段错误、闪退)。
问题2:析构函数 delete[]a 释放空指针(或野指针)
- 如果成员变量a是空指针:C++11后
delete[] nullptr是安全的,但局部变量a指向的动态数组内存永远无法释放(内存泄漏); - 如果成员变量a是随机野指针(未初始化的指针值):
delete[]野指针会直接崩溃。
三、直观对比:两段代码的内存状态
构造函数执行时 | 成员变量a → 指向动态数组(内存地址0x123) | 局部变量a → 指向动态数组(0x456);成员变量a → 空指针(0x0) |
构造函数执行结束 | 成员变量a 保留指向0x123 | 局部变量a销毁,0x456内存泄漏;成员变量a仍为0x0 |
show()调用时 | 访问0x123的数组,正常输出 | 访问0x0的空指针,崩溃 |
析构函数执行时 | 释放0x123的内存,正常 | 释放0x0的空指针,无意义且内存泄漏 |
四、修正第二段代码的两种方式
核心是「让构造函数给成员变量a赋值,而非定义局部变量」:
方式1:去掉局部变量的定义(推荐,和第一段一致)
Array(){
cin >>n;
a = new int[n]; // 直接给成员变量a赋值,不重新定义
for(int i=0; i<n; i++){
cin>>a[i];
}
}
方式2:用 this->a 明确指定成员变量(避免遮蔽)
如果想保留局部变量名(不推荐,易混淆),可以用 this-> 区分成员变量:
Array(){
cin >>n;
int* a = new int[n]; // 局部变量a
for(int i=0; i<n; i++){
cin>>a[i]; // 给局部a赋值
}
this->a = a; // 把局部a的地址赋值给成员变量a(此时成员a指向有效内存)
}
⚠️ 注意:这种方式虽然能运行,但没必要定义局部变量,徒增复杂度,优先用方式1。
五、总结:变量遮蔽的核心坑点
- 局部变量会覆盖同名的成员变量:编译器优先访问“更小作用域”的变量,这是C++的作用域规则;
- 指针未初始化=空指针/野指针:类的成员变量如果是指针,默认不会初始化为nullptr(全局对象除外),未赋值的指针是随机野指针,访问/释放都会崩溃;
- 动态内存要“谁分配谁释放”:局部指针指向的动态内存,若没有赋值给成员变量,出作用域后会内存泄漏。
你的第二段代码本质是「语法合法,但逻辑错误」,这也是新手最容易踩的坑 —— 写代码时要注意:避免局部变量和成员变量同名,如果必须同名,用 this->成员名 明确指定成员变量。

京公网安备 11010502036488号