PTA 6-3 动态输入排序 题解
原题
本题要求实现一个函数input,能够输入n个整数。
裁判测试程序样例:
点击查看代码
/* 请在这里填写答案 */
//实现input函数
void sort(int a[], int n){
int i,j;
for(i=0;i<n-1;i++){
int min = i;
for(j=i+1;j<n;j++){
if(a[min]>a[j]) min = j;
}
int t = a[i]; a[i] = a[min]; a[min] = t;
}
}
int main(){
int *a;
int n;
cin>>n; //输入数据的数量
input(a,n); //输入n个整数
sort(a,n); //将数组a按从小到大排序
for(int i=0;i<n;i++)
cout<<a[i]<<" "; //按顺序输出
if(a!=NULL)
delete []a;
return 0;
}
输入样例:
在这里给出一组输入。例如:
5
10 9 8 7 6
输出样例:
在这里给出相应的输出。例如:
6 7 8 9 10 4
解析
要注意,标准代码中没有为 a 分配内存,我们要自己分配。
但若只在 input() 函数中加入一句 a = new int [n]; 是会报错的,我们在应该把函数也改写为 input(int *&a, int n)
因为 int a, int *a, int *&a是不一样的,我们这里要在函数内直接修改外部指针。
这个问题涉及C++中符号的语义差异,用具体例子说明:
三种参数传递方式对比:
int a(值传递):
void func(int a) {
a = 10; // 仅修改局部副本
}
int main() {
int x = 5;
func(x); // x仍为5
}
int* a(指针传递):
void func(int* a) {
*a = 10; // 修改指向的内容 ✔️
a = new int(20); // 仅修改指针副本 ❌
}
int main() {
int x = 5;
int* p = &x;
func(p); // x变为10,但p仍指向x
}
int* &a(指针的引用传递):
void func(int* &a) {
a = new int(20); // 直接修改外部指针 ✔️
}
int main() {
int* p = nullptr;
func(p); // p现在指向新分配的int(20)
}
为什么需要 int* &a:
当需要让函数修改外部指针本身(比如在input()中分配内存)普通指针参数 int* a只能修改指针指向的内容,无法改变指针的指向地址.
引用传递&让参数成为原指针的别名.
符号的语法本质:
int* &a // 读作:a是对int指针的引用
// 与运算符无关,这里没有使用*和&的运算符
// 这是类型声明中的组合符号
这就是为什么在需要修改指针本身时,必须使用指针的引用参数。
与之对比,sort(int a[], int n) 函数就不需要头疼这个问题,这是因为 sort() 函数只对指针指向的内存地址做修改,而不改变指针本身。
于是正确代码:
void input(int *&a, int n){
a = new int[n];
for(int i=0; i<n; i++){
cin >> a[i];
}
}
其他探讨
回顾一下基本的指针,&是取地址符
这里的指针可以修改指向内容,但不能修改指针本身,如果修改,将仅影响函数内的局部指针副本,如 x = new int[10]

其中图中的数组传递时会退化为一个指向数组首字母的指针。
但是指针和引用应该分开看,,这两个东西是不同的
// 引用版本(本题解法)
void mySwap(int &x, int &y) { ... }
mySwap(a, b); // 直接传变量
// 参数声明中的 & 是引用声明符(不是取地址运算符) 表示x和y是调用时传入变量的别名
// 指针版本(需要改变调用方式)
void mySwap(int* x, int* y) { ... }
mySwap(&a, &b); // 必须传地址

浙公网安备 33010602011771号