您现在的位置是:首页 >技术杂谈 >交大C语言程设课的题目,让我意识到了自己为什么只读了大专网站首页技术杂谈
交大C语言程设课的题目,让我意识到了自己为什么只读了大专
今天,鼠鼠看到了朋友圈里的一个交大✌在讨论一道C语言程序设计的代码题。不知道天高地厚的鼠鼠就附庸风雅地去讨论了一下,这才发现自己为什么只能读大专!
题目看起来非常简单,鼠鼠好像也会,我在这里简单地阐述一下:
把下面的代码补充完整,包括在main函数之前添加2行代码以及在最后添加一个函数的定义,使得该程序能在一行里输出三个数:输出的第一个数是x(即用户输入的第一个数)减去y(即用户输入的第二个数)的差的个位数,第二个数是x的3倍,第三个数是y的2倍。
鼠鼠寻思,这好像就是实现三个简单到不能再简单的功能:
第一,两个整数x和y相减;第二,把相减的结果的个位数取出来;第三,按照题意更新x和y。但一看要补充的代码,鼠鼠才发现原来自己只是一只会耍杂技的小丑!读大专的我只是想着如何机械地去实现题目的各个要求,全然不知这道题背后能隐藏的逻辑游戏的极大魅力。
大家请看这段代码:
#include <iostream>
using namespace std;
//请在下面补充两行代码
//
int myfun(int* a,int* b);
int main (void)
{
int x,y;
cin>>x>>y;
cout<<myfun(x,y);
cout<<x<<' '<<y;
}
int myfun(int* a,int* b)
{
int c=*a-*b;
*a *=2;
*b *=3;
return c;
}
//请在下面补充函数的定义
鼠鼠直接被难住了。读大专的鼠鼠只学过一点点c语言,不太看得会这些C++代码。好在鼠鼠翻过几页《C++ Primer Plus》,懂一点c++的皮毛。但即使这样,鼠鼠还是不太懂这道题该怎么写。
小丑啊小丑,到最后才发现鼠鼠就是一个在大专耍杂技的小丑,怎么能忝列交大✌之中讨论这种高智商者的思维游戏呢?
好在最后交大✌大发慈悲,把答案发给了我,让鼠鼠见识到了一点点小小的交大震撼。大专的鼠鼠,真是,开了眼了!
#include <iostream>
using namespace std;
//
char* myfun(int& a,int &b);
char s[3]=" ";
//
int myfun(int* a,int* b);
int main (void)
{
int x,y;
cin>>x>>y;
cout<<myfun(x,y);
cout<<x<<' '<<y;
}
int myfun(int* a,int* b)
{
int c=*a-*b;
*a *=2;
*b *=3;
return c;
}
//
char *myfun(int &a,int &b)
{
s[0]='0'-myfun(&b,&a)%10;
return s;
}
//
—————————————————分割线
嘿嘿,上面只是鼠鼠的自嘲。上海交通大学是很好的学校,北航虽然比不上交大,但也是一所挺好的大学。鼠鼠还在这里学到了很多东西的,请大家图一乐。
下面我将介绍一下这段代码中所运用的一些C语言学习者不常用的C++性质,同时也会解释一些比较基础的语法。
一、函数的传参
在C语言中,函数的传参是以传值的形式进行的,这就意味着,main函数里传入myfunction函数的a和myfunction函数里进行运算的a不是一个变量,虽然名称相同,但它们是储存在不同的地址里的!这么说,其实很模糊,下面我将举例子具体阐述:
我要在如下代码段中实现一个函数double_it,目的是把括号里的两个数字,也就是这个函数的两个参数分别乘2。
#include <stdio.h>
int main(void)
{
int a,b;
a=1;
b=2;
double_it(a,b);
printf("%d %d",a,b);
//或者,按照C++的习惯,写std::cout<<a<<b,
//不过这样,要改一下头文件
return 0;
}
那么我可以用两种方式向函数里传参
第一种:
#include <stdio.h>
void double_it(int a,int b);
int main(void)
{
int a,b;
a=1;
b=2;
double_it(a,b);
printf("%d %d",a,b);
return 0;
}
void double_it(int a,int b)
{
a=a*2;
b=b*2;
return;
}
传入函数的参数就是两个数a,b本身。在这种情况下,你会发现,打印出来的结果还是1和2,完全没有实现加倍的目的!
这是因为,函数的传参是以传值的方式实现的,你向函数double_it中传入了a和b,不是真的让a和b被函数改变,而是让把a和b的值复制给了函数中新开辟的两个int型变量。这样,改变函数里的a和b,当然不能改变函数外的a和b!
第二种:
#include <stdio.h>
void double_it(int* a,int* b);
int main(void)
{
int a,b;
a=1;
b=2;
double_it(&a,&b);
printf("%d %d",a,b);
return 0;
}
void double_it(int* a,int* b)
{
*a=*a*2;
*b=*b*2;
return;
}
使用传地址的方式,传入函数的参数是a和b的两个地址。传入函数后,即使这两个地址被复制进函数内的新变量的,但它们仍然指向a和b这两个变量。函数可以通过地址访问的方式修改a和b的值。
在这种情况下,使用函数时,要将a和b取地址,方能正确传入参数
double_it(&a,&b);
相应的,函数的参数应该定义为
void double_it(int* a,int* b)
因为传入的是int的地址,int地址的类型是int*,也就是指向int的指针!
还有,函数种使用a和b需要解引用
*a=*a*2;
*b=*b*2;
编译运行这段代码你会发现,结果变成了2和4,符合要求了!
二、函数传参时直接引用
答案中定义的函数char *myfun(int &a,int &b)出现了奇怪的int &a和int &b。这不是别的,就是把之前所说的C语言传参方式颠覆掉的方式!
如果你这样设置,你把a和b传入myfun函数,a和b就能直接被myfun改变了!
还是用之前的例子,为了让a和b翻倍,我们还能这样改代码:
#include <stdio.h>
void double_it(int &a,int &b);
int main(void)
{
int a,b;
a=1;
b=2;
double_it(a,b);
printf("%d %d",a,b);
return 0;
}
void double_it(int &a,int &b)
{
a=a*2;
b=b*2;
return;
}
这段代码编译运行,你会发现,结果变成了我们期待的2和4!
三、函数名的重载(令人窒息的操作)
下面是交大代码题的一个片段:
int main (void)
{
int x,y;
cin>>x>>y;
cout<<myfun(x,y);
cout<<x<<' '<<y;
}
这里出题者竟然使用了myfun(x,y),而由它题目中int myfun(int* a,int* b);的定义,传入myfun函数的参数应该是int*类型的数据,而不是int类型的数据。x和y是int类型的数据,这里好像错了!
但这就是这道题目诡谲的地方,它就是想让你再写一个名称为myfun的函数。让你实现它的功能!
但,两个同样名称的函数,不会矛盾吗?
这也是最惊讶我的地方,但转念一想,只要这两个函数的返回值和传入参数都不一样,是不是可以同时存在了呢?
编译器告诉我的答案,是,是的!就是可以同时存在的,非常神奇!只要用传入参数和返回值的差异来区分就行。
四、其他
至于这段代码的逻辑,我就不赘述了。它不是一个正常的编码者会使用的。更多的是出题者的一种巧妙设计。这种设计存在的意义是未定义的。
—————————————————分割线
但是,我还是忍不住要吐槽这一段破代码。不管时为了做实用性的代码开发,还是写竞赛性的代码。这种逻辑,这种代码都是一种故弄玄虚的矫揉造作!
可能它能锻炼同学们的智力,拓展同学们的认知。但就其本身而言,这就是一段及其糟糕的代码!
一、逻辑混乱
函数被设计出来的意义是把一系列复杂的功能和逻辑简化,达到逐个击破的效果;或者说它可以把一些常用的功能封装起来。
这段代码用函数,则是把一段完整清晰的逻辑人为地,随意地割裂成一个个小片段,让解题者去拼凑。
你看,你作差就作差罢了,为什么要在作差之后乘2和乘3,把它们写到主函数或者别的函数里不香吗?而且它的逻辑又非常奇怪,让非常正常的取个位算法由s[0]='0'+myfun(&b,&a)%10;变成了s[0]='0'-myfun(&b,&a)%10; 怪哉怪哉!
二、使用语法混乱
这其实是一个C语言程序设计课的代码,为什么要用cin>>x>>y这样的输入方法和int &a,int &b这样的C++性质。我不理解。
照道理,用C++性质应该一以贯之,但字符串又用了s[0]这样的c语言风格字符串,不应该用String吗?
如果你当作C语言,那这个文件无法以.c后缀文件被编译;如果你当作C++文件,那应该来体现一下面向对象的性质啊!
不理解,不过这可能是个人风格,我觉得它也不置可否!
三、训练的意义?
我们学习C,C++,是为了掌握编写实用程序的方法。但我感觉这道题目貌似流于炫技,没有太大的实际意义。有种数学考试对数学知识本身异化的感觉。学会C,不是为了去写程序解决学习和生活种的现实问题,而是为了以它为媒介玩智力游戏,把它变成区分智商的手段,这就有些令人生厌了吧。
也许,在AI技术和新语言日新月异的今天,C和C++这种古老的语言,真的会沦为一种滋生题目的媒介,失去其本身的固有价值,像儒学那样成为了科举考试的附庸。这对我们这些C语言的殉道者无疑是肝肠寸断之痛。
但不管怎么说,历史的潮流是难以改变的。如果C语言真的死了,就让它以这种形式继续它的生命吧!