题31 编写一个函数escape(a,b),将字符串a复制到字符串b中,并在复制过程中将换行符、制表符等不可见字符分别转换为\n、\t等相应的可见的转义字符序列。(用指针的方式)
做题过程:
1.最开始,先要能将字符串写进去,所以就找到了两种能读入\n的办法
法一:
char a[16];
for(int i=0;i<15;i++){
scanf("%c",&a[i]);
}
a[15]='\0';
//但是这种方法有一个缺点:就是当字母个数不确定时无法输入
法一改进版:
char a[16];
int i=0;
while(1){
scanf("%c",&a[i]);
if(a[i]=='$') break;
i++;
}
//法一的改进版比法二好很多
法二:
char a[40],b[40];
scanf("%[^$]",a);
//这里scanf(%[^$])的用法就是:字符串读到$时就终止读取
用法二试一下:
2.写escape(a,b)
函数
首先想到的是这样:
void escape(char *p1,char *p2){
int i=0;
int j=0;
while(p1[i]!='\0'){
//最后将这里本来的$留在了缓冲区,新增字符串结尾的'\0'
if(p1[i]=='\t'){
p2[j++]='\\';
p2[j++]='t';
i++;
}
else if(p1[i]=='\n'){
p2[j++]='\\';
p2[j++]='n';
i++;
}
else{
p2[j++]=p1[i++];
}
}
p2[j]='\0'; //一定注意末尾要有\0
}
int main(){
char a[40],b[40];
scanf("%[^$]",a);
escape(a,b);
printf("%s",b);
puts(a);
return 0;
}
通过这次调试弄清楚了一点:
当情况是这样时:scanf("%[\n]",a)
:
注意: '\n’确实也还在缓冲区,不过后续都是直接从缓冲区读取字符串而不是读取字符,所以会直接跳过(tab, 空格, ‘\n’)这类空白字符。
所以就有了这样的改进:
scanf("%[\n]%*c",a)
就是为了将’\n’字符吸收掉。
我做了一个小小的测试,发现结果确实是这样:
int main(){
char a[40],b[40];
scanf("%[^$]",a);
puts(a);
char c;
scanf("%c",&c);
printf("%c",c);
return 0;
}
输入为:
1$
输出结果为:
1
$
验证了$的确在缓冲区中
题6:输入一串字符串,以"$"结束,分别统计各大写字母出现的次数,并按照字母出现的多少输出(次数相同的字母按照字母表顺序输出,不出现的字母不输出)
这个题目拆分为3步:
1)要输出一个字符串,以$结尾且能被识别出来
2)统计每个大写字母出现的次数
3)按照字符出现的次数进行排序,
4)次数相同的字母按照字母表顺序输出(说明这种排序应该是稳定排序)
问题1解决办法同上个题目:
char a[16];
int i=0;
while(1){
scanf("%c",&a[i]);
if(a[i]=='$') break;
i++;
}
问题3的解决办法:用一个b[26]的数组来记录每个字符出现的次数
问题3,4的解决办法:选择一种稳定的排序算法:冒泡排序首选
源代码:
#include<bits/stdc++.h>
using namespace std;
char a[100];
int main(){
int i=0;
while(1){
//输入的改进
scanf("%c",&a[i]);
if(a[i]=='$'){
break;
}
i++;
}
int b[26]={
0};
for(i=0;a[i]!='$';i++){
if(a[i]>='A'&&a[i]<='Z') b[a[i]-'A']++;
}
int max=0;
for(int j=0;j<26;j++){
//选择排序,稳定
for(i=0;i<26;i++){
if(b[i]>b[max]) max=i;
}
if(b[max]==0) break;
printf("%c:%3d\n",'A'+max,b[max]);
b[max]=0;
}
return 0;
}