这个作业4写起来相当难受,很大程度上来源于填空题只给出了一个函数,声明了一些奇奇怪怪的变量,也没有任何注释,题目要求也极其不明确,做题和解谜差不多,所以写篇博客简要分析一下。
注:填空第3题的第2空提交了几次还是不知道答案是多少
单选题
1. A
解析:函数名本身就是一个指针,指向函数的入口地址,这一点和数组比较像
2. B
解析:字符串本身也是一个指针,注意这个language是一个指针数组,因此每个元素相当于一个地址。
3. D
解析:这题比较奇怪,C和D都能编译成功。不过不选C的原因可能是因为这是一个野指针。注意,C选项是一个数组指针,但是没有初始化,打印出来的地址比较奇怪。
4. C
解析:注意运算符优先级问题。
5. C
解析:可以参考我写的 C / C++ 指针数组和数组指针 这篇文章中第一部分:优先级方面。这里不过多解释。
6. C
解析:同上,参考我写的 C / C++ 指针数组和数组指针 这篇文章。这里不过多解释。
7. A
解析:注意二维数组中要取两层地址才能获得元素的值。
8. D
解析:指针概念搞清楚。
填空题
1. 程序运行的结果
答案:
2,4,5,7,6,0,11,9,7,3,
解析:
IDE跑一下抄下结果。
2. 程序运行的结果
答案:
string_a=I am a teacher.
string_b=You are a student.
string_a=I am a teacher.
string_b=I am a teacher.
解析:
IDE跑一下抄下结果。
3. 字符串转换为整数
原题目:
/*下面函数的功能是将一个整数字符串转换为一个整数,例如:”-1234”转换为1234,请填空使程序完整。*/
int chnum(char *p)
{ int num=0,k,len,j ;
len = strlen(p) ;
for ( ;____1____; p++) { // len>0
k=____2____; // 不会
j=(--len) ;
while (____3____) // j--
k *= 10;
num += k ;
}
return (num);
}
答案:
第一空:len>0
第二空:(不会)
第三空:j--
解析:
第一空:首先关注到下面有一行:j=(--len)
;,大致可以知道最后len
一定会减到0。结合程序大致分析,要完成整个转换,那肯定得走len
次,所以这里通过合理猜测,得出填len>0
第二空:试了几次都不对,我填的是*p-'0'
,在IDE测试可以用,但这里答案不对,不知道为什么。这样填的理由是:因为注意到for
循环中每次都进行p++
,也就是把字符串指针往后移一个位置,所以*p
取出来的是当前位置的字符,通过与'0'
相减,可以得出两个字符相对 ASCII 码的差值,正好是当前位的数字。
第三空:由于我们从第一位开始往后移动指针p
,因此每一位要乘上10的len - 1
次方才能加到最终的数字上,而上面定义了j
就是我们要的len - 1
,所以此处填j--
。
4. 统计子串在母串中出现的次数
原题目:
/*函数的功能使统计子串substr 在母串str 中出现的次数,请填空使程序完整。*/
int count(char *str, char *substr) {
int i, j, k, num = 0;
for (i = 0; ___1___; i++)
for (___2___, k = 0; substr[k] == str[j]; k++, j++)
if (substr[___3___] == '\0') {
num++;
break;
}
return (num);
}
答案:
第一空:i<strlen(str)
第二空:j=i
第三空:k+1
解析:
变量解释:
int i; // 控制外层for循环遍历母串的下标
int j; // 控制内层for循环母串下标
int k; // 控制子串下标
int num; // 子串数量
第一空:这个很好理解,从第一个字符开始遍历,直到最后一个字符,所以一共循环strlen(str) - 1
次。
第二空:找字串,就是从母串当前(第i
个字符)开始,往后k个字符都跟子串一样,这样就算找到一个子串。所以内层for
循环是从i
开始的,因此填j=i
第三空:子串长度为k,所以判断子串中k+1
的位置是不是\0
,如果是,就说明子串结束,找到一个子串,num++
;如果不是,就break
跳出内层for循环,开始下一个外层for循环。
5. 整数转字符数组
原题目:
/*下面函数的功能是用递归法将一个整数存放到一个字符数组中,存放时按逆序存放,如483 存放成“384”,请填空使程序完整。*/
void convert(char *a, int n) {
int i;
if ((i = n / 10) != 0)
convert(___1___, i); // a+1
*a = ___2___ ; // n+'0'
}
答案:
第一空:a+1
第二空:n%10+'0'
解析:
第一空:a
是一个指针,指向传入的字符串的起始地址,因此递归时每次把指针往后移一个位置,即a+1
,直到最后一位。
第二空:和反位数算法有点像,不太想写了。提一下'0'
,和上面第3题里面的作用一样,通过ASCII码来进行字符和整数间相互转换。
6. 递归法求数组中的最大值及下标
原题目:
/*下面函数的功能是用递归法求数组中的最大值及下标值,请填空使程序完整。*/
void findmax(int *a,int n,int i,int *pk)
{
if (i<n) {
if (a[i]>a[*pk])
___1___; // *pk=i
findmax(___2___) ; // a, n, i+1, pk
}
答案:
第一空:*pk=i
第二空:a,n,i+1,pk
解析:
第一空:通过分析,我们可以发现既然求最大值,pk
这个指针指向的变量就是用来存最大值下标的,因此根据内层if
来看,如果数组a
中第i
个元素比第*pk
个大,那么就把i
赋值给*pk
。
第二空:分析+猜。因为是找数组中的最大元素,那数组就那一个a
数组,所以递归传递还得传a
,n
表示数组的元素个数,所以也原封不动传下去。只有i
需要每次递归递增一个,等同于for循环的向后遍历一个位置。pk
存放的是最大值的下标的地址,所以也原封不动传下去,如果有更大的修改pk
指向的值就是了。
7. 连接字符串s1和s2
原题目:
/*下面函数的功能是将两个字符串s1 和s2 连接起来,请填空使程序完整。*/
void conj(char *s1, char *s2) {
char *p = s1;
while (*s1) ____1____;
while (*s2) {
*s1 = ____2____;
s1++, s2++;
}
*s1 = '\0';
____3____;
}
答案:
第一空:s1++
第二空:*s2
第三空:s1=p
解析:
第一空:这里的拼接,是把s2直接拼在s1后面,效果等同于strcat(s1, s2)
。第一个while
的作用就是把指针s1指向s1字符串的末尾,所以填s1++
。
第二空:把s2
的字符逐一复制到s1
的后面,很简单。
第三空:这里我困惑了很久,因为一开始定义的指针p
根本没用上。后来明白了,因为s1
本来指向第一个字符串开头,但是复制操作完成以后s1
指针已经移到整个字符串末尾了,函数外面不能用。这里就用上了p
,p
记录了s1
的起始地址,现在重新赋给s1
就好。(用后归位)
8. 找出长度最大的字符串
原题目:
/*下面函数的功能是从输入的十个字符串中找出长度最大的那个串,请填空使程序完整。*/
void fun(char str[10][81],char **sp)
{ int i;
*sp = ___1___; //str[0]
for (i=1; i<10; i++)
if (strlen (*sp)<strlen(str[i]))
___2___; //**sp=i
}
答案:
第一空:str[0]
第二空:*sp=str[i]
解析:
第一空:这里需要引入二维数组的行指针,具体可以参考 C / C++ 指针数组和数组指针 这篇文章中行指针部分内容,这里不过多解释。这里需要把行指针sp
指向二维数组str
的第0行。
第二空:本质上就是遍历数组找最大值的算法,这里只要把if
判断那一行的strlen( )
括号里的东西赋值就行了。
结语
答案不重要(虽然算平时分),不过最好能理解里面的知识点。
C和C++基础语法几乎完全一致,所以理解了C语言,学习C++会更得力一些。
有遗忘的部分多翻翻书,或者在菜鸟教程 - C语言教程查看相关部分。
《C Primer Plus》就是这时候作工具书查找语法点使用的,而不应该作为睡前读物。
版权声明:内容为Switernal的原创文章,遵循 CC 4.0 BY-SA 版权协议。
允许转载,转载时请附上原文链接:https://switernal.cn/2020/02/13/面向对象程序设计延期开学作业4简析/