求解c++难度题


P
0
概述
//
同学们大家好,今天这篇文章讲解的是函数与编译预处理,对应蓝本教材中的第四章和第五章。函数这一章还是比较重要的,其中有一些非常重要的概念,需要好好理解,比如函数参数的传递、引用、递归、局部变量与全部变量等,很多同学直到快期末考试都理不清这些概念。编译预处理这一章,宏定义是每年必考的一道题,选择题、填空题中都会出现。话不多说,我们赶紧开始吧!
W
INTER
函数是什么
//
我们总是习惯使用旧的知识理解新的知识,我们在高中数学的课堂上见过函数就是那个f(x),数学老师告诉我们,f就是一种对应法则,它实际上是一种算法。比如f(x)=2x+1,F就表示x的2倍再加1这样一种算法。
而C++中的函数呢,可以理解为一个“过程”,这个“过程”可以有输入输出,也可以没有,甚至你可以从主程序中摘出一段代码,定义为某个函数写在主程序外面,然后在main函数的对应位置调用,从这个角度看,函数是一组一起执行一个任务的语句。每个 C++ 程序都至少有一个函数,即主函数 main,通过函数,还可以把一个复杂任务分解成为若干个易于解决的小任务。
函数的输入需要写在函数定义的函数列表中,如果函数有输出的话,需要说明函数“返回值”的数据类型,写在函数名的前面,如“int clac”、“bool ifprime(int x)”等,分别表示函数的输出为int型和bool型。如果函数没有输出,则需要定义为void。
按函数是否由系统定义:分为库函数(系统函数)和自定义函数。
C++标准库提供了大量的程序可以调用的内置函数。例如,函数 strcat 用来连接两个字符串,函数 memcpy 用来复制内存到另一个位置。本文重点介绍自定义函数。
W
INTER
C++函数的实参和形参
//
形式参数就是定义函数时候的参数表,只是定义了调用时参数的个数、类型和用来引用的名字,并没有具体的内容。
实际参数是调用函数传递的具体数据,实参可以是常量、变量或者表达式,且要与形参类型一致!实参对形参数据传递时是单向传递——形参相当于剧本中的人物;实参相当于演员,演员(实参)去扮演(替换)剧本里的角色(形参),不可能用剧中人物去替代现实的演员!
形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。每次调用函数时,都会重新创建该函数所有的形参,此时所传递的实参将会初始化对应的形参。形参的初始化与变量的初始化一样:如果形参具有非引用类型,则复制实参的值;如果形参为引用类型,则它只是实参的别名。
形参和函数体内部定义的变量统称为局部变量,仅在函数的作用域内可见,同时局部变量还会隐藏在外层作用域中同名的其他所有声明(局部变量和全局变量可以重名)
W
INTER
局部变量和全局变量
//
局部变量
在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的。同样,在复合语句中定义的变量只在本复合语句范围内有效。这称为局部变量(local variable)。参见如示意图:
对局部变量的一些说明:
1)局部变量在定义时可加修饰词auto,但通常省略。局部变量在定义时若未初始化,其值为随机数。
2) 主函数main中定义的变量(m, n)也只在主函数中有效,不会因为在主函数中定义而在整个文件或程序中有效。主函数也不能使用其他函数中定义的变量。
3) 不同函数中可以使用同名的变量,它们代表不同的对象,互不干扰。例如,在f1函数中定义了变量b和c,倘若在f2函数中也定义变量b和c,它们在内存中占不同的单元,不会混淆。
4) 可以在一个函数内的复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为分程序或程序块。
5) 形式参数也是局部变量。例如f1函数中的形参a也只在f1函数中有效。其他函数不能调用。
6) 在函数声明中出现的参数名,其作用范围只在本行的括号内。实际上,编译系统对函数声明中的变量名是忽略的,即使在调用函数时也没有为它们分配存储单元。例如:
int max(int a, int b);//函数声明中出现a、b
int max(int x, int y) //函数定义,形参是x、y
{
cout<<x<<y<<endl; <="" span="">合法,x、y在函数体中有效
cout<<a<<b<<endl; 非法,a、b在函数体中无效,编译时报错
}
全局变量
程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数之外定义的变量是外部变量,称为全局变量(global variable。全局变量的有效范围为从定义变量的位置开始到本源文件结束。参见如示意图:
p、q、c1、c2都是全局变量,但它们的作用范围不同,在main函数和f2函数中可以使用全局变量p、q、c1、c2,但在函数f1中只能使用全局变量p、q,而不能使用c1和c2。
在一个函数中既可以使用本函数中的局部变量,又可以使用有效的全局变量。
对全局变量的一些说明:
1)全局变量在编译时建立在全局数据区,在未给出初始化值时系统自动初始化为0。
2) 全局变量的作用是增加函数间数据联系的渠道,但要慎重使用,建议不在必要时不要使用全局变量,因为:
全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。
一般要求把程序中的函数做成一个封闭体,除了可以通过“实参——形参”的渠道与外界发生联系外,没有其他渠道。这样的程序移植性好,可读性强。
3) 如果在同一个源文件中,全局变量与局部变量同名,则在局部变量的作用范围内,全局变量被屏蔽,即它不起作用。
简单的说,在{...}中出现的都是局部变量(包括主函数这个大括号哦),否则就是全局变量。
变量作用域示例:
W
INTER
函数的参数传递
//
函数参数传递的三种方式(记下来,填空题会考哦!):
1)值传递(传值):
2)引用传递(传引用):
3)指针传递(传址):
下面通过例子说明。
☆值传递
值传递是指向函数传递自身的一个副本, 也可以认为是自身的克隆, 他最大的一个特点就是函数对传入的副本进行操作不会影响到实参的本身。值传递的简单例子:
可以看到, n的值并未发生任何改变。
☆引用传递
变量的引用,实际上是给变量起了一个“小名”,例如“李嘉珣”和“珣珣”都是指的同一个人。引用传递不是使用实参的"副本", 而是真实的实参值在内存中的地址, 因此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。引用传递的简单例子:
☆指针传递
指针变量中可以存放的是其它变量的地址, 向函数参数中传递指针变量,意味着指针变量这个形参指向实参变量的实际存储位置, 对实际位置中的内容进行操作, 实参的值自然就会跟着改变。关于指针参见教材第七章。指针传递的简单例子:
练习1
接下来我们做一道题来练习一下,下图程序的输出为:_____
答案:13
001101
[程序解析] 考查进制转换算法
1)函数调用后字符数组s1值为"15",则s1[0]-‘0’的值为1,s1[1]-‘0’的值为5,那么A行的循环语句实现tab[1]和 tab[5]两个字符串连接后复制到s2数组中,s2中邮"001101"
(2)B行循环实现将字符数组s2中的内容转换为十进制整数,并返回给主函数的有,第1行输出的y值为13。由于主函数中的ss2与s2共占同一内存单元,所以第2行输的内容001101。
W
INTER
内联函数
//
内联函数(inline函数)的作用就是优化被频繁调用的函数,就相当于把inline函数中的函数体直接复制到被调用的函数中一样, 不再使其频繁的中断。定义inline函数非常简单, 只要在定义时在前面加上 inline 关键字即可, inline 函数的函数体语句不适合过多,因为inline 函数“以空间换时间 ”;
W
INTER
递归函数
//
同学们第一次接触到递归程序,可能会比较懵,这就好比大一的同学第一次进入南理工的校园的时候,感觉很大、很陌生,当时熟悉一段时间之后,对学校的布局就会更加清晰。对递归的认识也是如此,希望同学们能够多画图多理解。
递归,顾名思义,其包含了两个意思:递 和 归,这正是递归思想的精华所在。运用递归的条件:每一步进行的操作基本相同,并且问题规模逐渐减小,直到达到“边界条件”,之后逐级返回。递归就是有去(递去)有回(归来),用递归求4的阶乘,如下图所示:
用递归求阶乘的代码:
练习2
下面这道递归的题目比较复杂哦
当程序输入:3 4 ,程序的输出为:__________
答案:The result is:3702
该程序所计算的表达式为:
result = m + m*m + m*m*m + ... + m*m*..*m(n个m)
递归的调用过程如下图所示:
函数fac中的变量n1的作用为记录递归函数的深度。
并且控制只有在回归到n1=0时,才显示最后结 果,所以 n1 这个变量必须设置为静态变量才行。
如果将程序中的 result和nl 前的 static 关键宇去除(当然还必须给它们赋初值为 0),
这时程序的输出就成为:
The result is:3
The result is:33
The result is:333
The result is:3333
W
INTER
编译预处理
//
给大家出一个填空题:
编译预处理有三种: 宏定义、 条件编译、 文件包含
我们使用编译器写出cpp文件之后,经过编译生成 .obj 文件,称为目标文件或中间文件,通过链接器和资源文件链接就成可执行 .exe文件了
下面我们重点介绍宏定义:
通过预处理器处理的源程序与以前的源程序有全部不一样, 在这个阶段所进行的工做只是 纯粹的替换与展开,没有任何计算功能,因此在学习#define命令时只要能真正理解这一点,这样才不会对此命令引发误解并误用。
下面,做两道题来练习一下吧!
练习3
以下程序的输出为:_______
答案:20
注意宏定义是简单的机械替换
替换后的表达式为:a+b/c+d = 15 + 10/20 + 5 = 20
练习4
如果采用A语句和B语句的宏替换,结果会有什么不同呢?
若采用A语句的宏代换:
q=m>(n+p)?m:(n+p)*10 = 4>3 ? 4:(2+1)*10 = 4;
若采用B语句的宏代换:
q=(m>(n+p)?m:(n+p))*10 = (4>3 ? 4:(2+1))*10 = 40;
其实,这一类题目并不难,只要细心就可以做对啦!
C++C++
宏定义的“黑科技”
在文章的最后,给大家展示一些宏定义的“黑科技”
define中的三个特殊符号:#,##,#@
#define Conn(x,y) x##y
#define ToChar(x) #@x
#define ToString(x) #x
(1)x##y表示什么?表示x连接y,举例说:
char* str = Conn("asdf", "adf");
/*结果就是 str = "asdfadf";*/
(2)其实就是给x加上单引号,结果返回是一个const char。举例说:
char a = ToChar(1);结果就是a='1';
做个越界试验char a = ToChar(123);结果就错了;
但是如果你的参数超过四个字符,编译器就给给你报错了!
error C2015: too many characters in constant :P
(3)最后看看#x,估计你也明白了,他是给x加双引号
分享几个常用的宏定义:
(1)将一个字母转换为大写:
#define UPCASE( c ) ( ((c) >= ''a'' && (c) <= ''z'') ? ((c) - 0x20) : (c) )
(2)返回数组元素的个数:
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
(3)for的宏定义
注意for前面是有下划线的哦,跟关键词for区分开,这种简洁的宏定义将极大的简化for在实例中的使用
#define _for(i,a,b) for( int i=(a); i<(b); ++i)
#define _rep(i,a,b) for( int i=(a); i<=(b); ++i)
_for(i, 0, 4)
printf("%d", i);
宏定义的使用非常灵活,也给编程带来了方便,很多程序员大佬都在使用。
今天的文章就分享到这里啦,希望同学们能够认真研读课本,好好做课后题,如果有学习上的问题,欢迎来学业指导中心(逸夫楼二楼)咨询哦!
文 字
李嘉珣
责 编
肖远筝
初 审
高 希
审 核
罗 勇返回搜狐,查看更多
责任编辑:}

我要回帖

更多关于 c++难度 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信