思考题L.docx
- 文档编号:12474400
- 上传时间:2023-04-19
- 格式:DOCX
- 页数:31
- 大小:25.29KB
思考题L.docx
《思考题L.docx》由会员分享,可在线阅读,更多相关《思考题L.docx(31页珍藏版)》请在冰豆网上搜索。
思考题L
思考题
本组成员:
Q12010101马宇洁Q12010102刘倩君
Q12010103吕朝萍Q12010104张娇娇
(以上排名不分先后)
一、简答类:
1、为什么先定义的自动局部变量的地址大?
自动局部变量存储在动态存储区的栈空间中,栈底的地址值最大,栈顶的地址值最小。
由于栈空间按后进先出的方式管理,即先定义的自变量存储在栈底,后定义的自变量存储在栈顶,因而先定义的自变量地址大。
2、printf函数调用时,其中的格式控制串与后面的参数应当一一对应,为什么格式控制串个数少于后面的参数个数时,%开头的控制串会被忽略?
但是当格式控制串个数多于后面的参数个数时,会有输出?
多余的输出结果是什么,有没有遵循什么规律?
格式控制串个数少于后面的参数个数时,则printf从左向右扫描%,发现一个%就将一个对应变量转换成相应的格式,多出的参数忽略;当格式控制串个数多于后面的参数个数时,会输出,多余的输出情况如下:
%d-------------2367460
%c--------------?
%f---------------0.000000
%x--------------241fe4
(根据系统而定)
3、相邻的局部变量的地址差值为多少?
根据什么来确定?
相邻的局部变量的地址差值为sizeof(类型),因类型不同而不同
4、同一个程序在不同编译器(比如VC或TC)下第一个变量的地址是否相同,均为ox12ff7c?
如果相同,为什么?
如果不同,为什么?
不同。
根据堆栈的知识可知,系统的第一个变量的地址应该是ox12ff7c+sizeof(类型)。
VC——对应的是32位,而TC——对应的是16位,所以即使是同一种类型的变量,在不同的编译器下,其所占空间是不一样的,就以int为例,在VC下占4个字节,在TC下占两个字节,因此,对应的第一个变量的地址也就不一样。
5、为什么指针变量占4字节,指针变量所占空间大小取决于什么?
为什么与基类型无关?
指针变量代表一个存储单元地址,占用存储单元一般为4个字节-即一个存储单元,(32位计算机)。
与其基类型数组无关,因为它仅代表一个地址。
如果一个变量占用多个单元,使用的时候还是以第一个字节的地址为变量地址。
因此,指针变量的都用4个字节。
(常见且多了无用)
指针变量占用的存储单元与编译器有关。
16位计算机为2个字节,32位计算机为4个字节。
与基类型无关。
6、数组中为什么12ff7c作为最后一个元素的地址?
12ff7c是系统调用堆栈的栈顶地址。
数组元素是前后相邻的一组变量,最后一个元素是最后定义的,因而地址最小,存储在栈顶。
(参见题1)
7、不增设其他变量,用其他什么方法可以实现交换两个变量的值?
写出代码。
1算术法
inta,b;
(2)
a=10;b=12;a=10;b=12;
a=b-a;//a=2;b=12a=b/a;
b=b-a;//a=2;b=10b=b/a;
a=b+a;//a=12;b=10a=b*a;
2.异或法
a=10,b=12;//a=1010^b=1100;
a=a^b;//a=0110^b=1100;
b=a^b;//a=0110^b=1010;
a=a^b;//a=1100=12;b=1010;
8、教材117页中说到:
“复合语句相当于一个无返回值和参数列表为空的函数,复合函数体就是这个函数体。
”这个描述是否正确,请给出正确或不正确的理由。
9、总结一下变量的生命期与作用域的关系(综合第六、七章的知识)。
首先简单说说各类型变量。
1:
自动型(auto型):
此变量是在函数内部定义的一种变量,它局限于该函数或所在的函数,故也称为局部变
量,更加确切的说定义在某一对花括号之内,生命起始终止于这个大括号;
2:
外部型(extern):
此变量又称为外部变量,是一种全局变量,在函数之外定义,
3:
寄存器型(register)又称为寄存器型变量,只有int,short,char类型的变量才能定义为寄存器型变量,
它只适用于auto型变量和函数的形式参数,所以它只有在函数内定义,并且作用域和生命周期同auto一样.
4:
静态型(static):
分为内部静态变量和外部静态变量;
内部静态变量同auto变量,也是在函数内部定义,它局限于定义它的函数,但是在退出函数的时候并部消失,而是在整个程序中都存在;用一句话说就是,内部静态变量有的可见性和全局的生命期;
外部静态变量:
是在函数外部定义的变量,作用域是定义它的源文件,即对定义它的源文件是全程知道的;对源文件之外的文件是部可见的;
综上,我们将变量的生命域与作用域关系总结成一张表格。
变量的存储类型
函数内
函数外
文件外
作用域与生存期是否一致
自动局部变量
作用域
本函数体内
√
×
×
是
生存期
一次函数调用过程
√
×
×
静态局部变量(内部静态变量)
作用域
本函数体内
√
×
×
否
生存期
第一次执行其定义语句到程序结束
√
√
√
寄存器变量
作用域
同自变量
√
×
×
是
生存期
√
×
×
文件作用域的外部变量(外部静态变量)
作用域
本文件内
√
√
×
是
生存期
第一次执行其定义语句到文件结束
√
√
×
全局作用域的外部变量
作用域
其定义点以下所有除去同名局部变量的部分
√
√
√
是
生存期
从编译到程序结束
√
√
√
10、为什么在C语言中字符常量占4个字节而字符变量只占1个字节(VC环境下)?
首先编程检验。
#include
intmain()
{
charch;
printf(“%d,%d,%d\n”,sizeof(char),sizeof(ch),sizeof(‘A’));
return0;
}
运行结果为:
1,1,4
原因:
在C语言中常量统一用32位二进制数表示,占四字节;
128个字符和0-127(ASCII码)一一对应,因而字符型变量能以一个字节的整数形式存储。
11、探讨25/6、25/-6、-25/6、-25/-6、25%6、25%-6、-25%6、-25%-6的结果,上机测试并总结规律。
结果分别为25/6=4-25/-6=425/-6=-4-25/6=-4
25%6=1-25%-6=-125/-6=1-25%6=-1
规律:
对于“/”除号,遵循同号为正,异号为负的原则。
对于“%”取余号,结果的正负只看“%”号前的数的正负,%前为正,则余数为正,反之为负。
12、在C语言中,表达式中的结合性有什么意义?
它与计算的优先级有什么联系?
我们可以做个比喻:
结合性是仲裁者,在几个操作符具有相同的优先级时决定先执行哪一个。
许多操作符的优先级都是相同的。
这时,操作符的结合性就开始发挥作用了。
在表达式中如果有几个优先级相同的操作符,结合性就起仲裁的作用,由它决定哪个操作符先执行。
结合性只用于表达式中出现两个以上相同优先级的操作符的情况,用于消除歧义
优先级决定表达式中各种不同的运算符起作用的优先次序,而结合性则在相邻的运算符的具有同等优先级时,决定表达式的结合方向。
13、对于二维数组inta[3][5],&a[0][0]、a[0]、&a[0]、*a、a的值是否一样?
各代表什么含义?
全部相同。
&a[0][0]=a[0]
表示第0行第0列元素的地址,是一维数组指针。
*a=a=&a[0]
表示第0行元素的行址,是二维指针常量。
14、是不是所有的递归函数都可以用非递归函数等效实现?
反之,是不是所有的非递归函数都可以用递归函数实现?
说出理由并给出例示程序。
任何递归程序都可以通过引入堆栈转化为非递归的形式。
这种转化其实就是模拟计算机实现递归的过程,因为任何递归计算过程最后总是要用堆栈转化为循环来实现的,你可以考虑人脑来计算递归的过程:
先倒过来向前递归,到达最初点以后再正过来向后递推,堆栈的作用就是记住过程中的临时变量。
非递归化就是指不引入堆栈等辅助空间进行计算的算法。
更确切地说,非递归是指辅助的空间为O
(1)的算法(辅助空间的规模和问题的输入规模无关)。
不引入堆栈的所谓非递归本质上还是递归,只不过原来由编译器做的事让你的程序来模拟实现了。
不是所有的可计算问题都可以由递归转化为递推的。
例如著名的Ackermann函数,就没有递推算法。
Ackermann函数定义如下:
若m=0,返回n+1。
若m>0且n=0,返回Ackermann(m-1,1)。
若m>0且n>0,返回Ackermann(m-1,Ackermann(m,n-1))
意义
从Ackermann函数的定义中可以看出,Ackermann函数可以看成关于n的一个函数序列,其中第0个函数返回n+1,而第m个函数则是将第m-1个函数对1迭代n+1遍。
对较小的m,该函数为:
Ackermann(0,n)=n+1
Ackermann(1,n)=n+2
Ackermann(2,n)=2*n+3
Ackermann(3,n)=2^(n+3)-3
Ackermann(4,n)=2^2^2^……^2-3,乘幂中共有n+3个2。
当m≥4,Ackermann函数的增长快得惊人。
Ackermann(4,0)=13,Ackermann(4,1)=65533,Ackermann(4,2)=2^65536-3有19729位,而Ackermann(4,3)则即使是位数也不易估计。
Ackermann(5,0)=65533,Ackermann(5,1)=Ackermann(4,65533)……
二、编程类:
1、编程测试程序可以通过指针申请多少个字节的动态空间。
可以申请25*10000000*8个字节。
测试程序如下:
#include
#include
#defineN10000000
voidf(void);
intmain()
{
while
(1)
f();
return0;
}
voidf(void)
{
double*p;
staticintc=0;
c++;
p=(double*)malloc(N*sizeof(double));
if(p==NULL)
{
printf("allocationfailure");
exit
(1);
}
printf("c=%d\t",c);
}
输出结果为:
c=1c=2..............................c=25allocationfailure
2、向有序数组中插入一个元素,请改进教材中例5.10的算法,将定位和移位两个循环合并为一个循环来实现。
#include
intmain()
{
inta[7]={12,23,34,45,56,67};
inti,x;
printf("pleaseinputxbeinserted:
\n");
scanf("%d",&x);
for(i=5;i>=0&&a[i]>x;i--)
a[i+1]=a[i];
a[i+1]=x;
printf("thenewarrayis:
\n");
for(i=0;i<7;i++)
printf("%d",a[i]);
printf("\n");
return0;
}
3、用函数FindAll实现查找变量x是否是数组中的元素,如果是,返回所有的存在下标,而不是只返回第一个元素的下标,主函数调用该函数输出所有的值等于x的元素的下标。
#include
voidFindAll(int*p,intn,intx);
intmain()
{
inta[10]={2,2,2,2,4,4,5,6,7,7};
FindAll(a,10,7);
return0;
}
voidFindAll(int*p,intn,intx)
{
inti;
intIndex[10],count=0;
for(i=0;i if(p[i]==x) { Index[count++]=i; } if(count>0) { printf("所有下标为: "); for(i=0;i { printf("%d",Index[i]); } } else printf("不存在\n"); } 4、通过编程说明一个递归函数在哪些情况下无法终止。 例: intAddFn(inta) { a+=1; if(a>8) {a=AddFn(a);} returna; } (1).如上所示,AddFn为一个简单的递归函数,假设以下为使用时的代码 intj=2; j=AddFn(j); returnj; 此时j的值为: 3,程序成功结束。 (2).假设调用方式改成下面的 intj=8; j=AddFn(j); returnj; 此时递归函数无法被中止,因为递归函数中的条件a>8永远为true! 5、编程实现一个约会问题: 女朋友对男朋友说,你等我,如果我三分钟内不来,你就再等我,直到我来为止。 (建议调用系统时钟来运行本程序,时间可以设定为一分钟不来) #include #include #include #include intmain() { ints; clock_tstart; srand(time(NULL)); start=clock(); do { srand(time(NULL)); s=rand()%2;//1设置为等,0设置为女友来 if(s==0) { printf("come"); break; } }while((clock()-start)/1000! =60);//时间设置为一分钟 if(s) printf("wait"); return0; 6、改进教材中的删除算法,要求删除所有的值等于x的元素,分别用两层循环和一层循环实现。 (根据编程需要来定义数组和普通变量,个数不限但不允许定义不使用的变量) 一层循环: #include intmain() { inta[]={1,2,2,2,3,5,6,9,18,34,2,23,2,2,14,51,34,5,2,2},b[20]; inti,j=0,x; printf("pleaseinputxbedeleted: \n"); scanf("%d",&x); for(i=0;i<20;i++) if(a[i]! =x) b[j++]=a[i]; printf("thenewarrayis: \n"); for(i=0;i printf("%d",b[i]); printf("\n"); return0; } 二层循环: #include intmain() { inta[]={1,2,2,2,3,5,6,9,18,34,2,23,2,2,14,51,34,5,2,2}; inti,j,x,n=20; printf("pleaseinputxbedeleted: \n"); scanf("%d",&x); for(i=0;i { if(a[i]==x) { n--; for(j=i;j a[j]=a[j+1]; i--; } } printf("thenewarrayis: \n"); for(i=0;i printf("%d",a[i]); printf("\n"); return0; } 7、打印九九乘法表,要求打印表头,两个乘法因子都要能清晰显示,下面的表是完整表,请完成程序分别打印上三角和下三角的乘法表,表头和每行的最左侧参照下面的结果。 九九乘法表: =========================================== 123456789 ----------------------------------------------------------------------- 1|123456789 2|24681012141618 3|369121518212427 4|4812162024283236 5|51015202530354045 6|61218243036424854 7|71421283542495663 8|81624324048566472 9|91827364554637281 //打印九九乘法表的上三角和下三角 #include voidprint1(); voidprint2(); intmain() { print1(); print2(); return0; } voidprint1() { inti,j; printf("九九乘法表: \n"); printf("===========================================================================\n"); printf("\t1\t2\t3\t4\t5\t6\t7\t8\t9\n"); printf("---------------------------------------------------------------------------\n"); for(i=0;i<9;i++) { printf("%d|\t",i+1); for(j=0;j<=i;j++) { printf("%d\t",(i+1)*(j+1)); } printf("\n"); } } voidprint2() { inti,j,m; printf("九九乘法表: \n"); printf("===========================================================================\n"); printf("\t1\t2\t3\t4\t5\t6\t7\t8\t9\n"); printf("---------------------------------------------------------------------------\n"); for(i=0;i<9;i++) { printf("%d|",i+1); for(m=0;m<=i;m++) { printf("\t"); } for(j=i;j<9;j++) { printf("%d\t",(i+1)*(j+1)); } printf("\n"); } } 8、下面是汉诺塔程序的递归代码,请将每一层递与归的过程及参数的变化情况用图表达出来。 汉诺塔问题描述: 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。 大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。 大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。 并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。 汉诺塔求解代码: voidHanoi(intn,chara,charb,charc) {if(n>=1) {Hanoi(n-1,a,c,b); printf("%c--->%c\n",a,c); Hanoi(n-1,b,a,c); } } 主函数中调用: Hanoi(3,'A','B','C');表示将三个盘子从A柱借助于B柱移动到C柱上。 请完成完整的程序写出运行结果,并画出“递”与“归”及每层调用情况的图示 //汉诺塔问题,主函数中调用: Hanoi(3,'A','B','C'); //表示将三个盘子从A柱借助于B柱移动到C柱上。 请完成完整的程序写出运行结果, #include voidHanoi(intn,chara,charb,charc); intmain() { printf("移动三个圆盘的步骤: \n"); Hanoi(3,'A','B','C'); return0; } voidHanoi(intn,chara,charb,charc) {if(n>=1) {Hanoi(n-1,a,c,b); printf("%c--->%c\n",a,c); Hanoi(n-1,b,a,c); } } 9、请用递归改写教材中程序6.19,用二分法实现在有序数组中查找某一个元素,若存在则返回其下标。 主函数中调用该递归函数实现相应功能。 #include intbisearch(int*pa,intm,intn,intitem) { intlow=m,high=n-1,mid=0; mid=(low+high)/2; if(low>high) return(-1); else { if(item==pa[mid]) return(mid); else { if(item bisearch(pa,m,mid,item); else { bisearch(pa,mid+1,n,item); } } } } intmain() { inta[10]={12,23,34,45,56,67,78,89,90,100}; intx,pos; printf("INPUTXBESEARCHED: \n"); scanf("%d",&x); pos=bisearch(a,0,10,x); if(pos! =-1) printf("pos=%d\n",pos); else printf("Notfound! \n"); return0; } 10、编程打印用“*”组成的图形,如心形、正五边形、正六边形、耐克商标、蝙蝠侠标记等,至少完成三个。 打印心形(两个,一正一倒): #include voidA(intn)//A函数: 输
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 思考题