C语言博客作业--字符数组
一、PTA实验作业
题目1:7-2 统计一行文本的单词个数
1. 本题PTA提交列表
2. 设计思路
1.定义整型变量flag来存放情况,flag=1代表还没遇到回车 ,flag=0代表遇到了回车
2.定义整型变量count用来计算单词数目,定义一个字符型变量ch用来存放字符
3.输入字符
4.while(当字符为字母或者空格且不是回车时)
while(ch==' '){
利用循环把空格吃光
若ch为回车时
跳出循环
}
while(当ch不是空格,不是 . 且没有回车时){
count增加1
do{
利用循环把字母吃光
若ch为回车时
跳出循环
}while(ch!=' ') ;
}
}
5.输出count的值
3.代码截图
4.本题调试过程碰到问题及PTA提交列表情况说明。
- 1.第一次运行没有得到任何结果,于是进行调试后发现:循环出不去
分析可以发现跳出循环的条件是getchar()的值为空格,但是我们结尾输的是回车,于是无法跳出循环
解决方法:重新加一个情况变量flag来讨论这种情况,即遇到回车就令flag=0然后循环条件加一个flag==1,就可以实现遇到回车跳出全部循环
- 2.修改后得到正确答案后就跑去pta提交,得到了部分正确的结果
根据第二个测试的提示进行测试后发现
确实不对,于是再次进行调试:
发现最后ch='\n'时竟然会进入count++的循环里,分析发现:虽然读到了回车循环条件也有说不能为回车,但是flag的值来不及改变啊,于是在count++的上一个循环里就该在最后判断是否为回车然后改变flag的值啦
测试:
得到正确答案~
- 3.再次提交发现:测试2没有过但是竟然过了测试点4是什么鬼呀哎呦喂,于是进行的第三个测试点的数据尝试,发现
于是增加count++的条件:ch!='.' 然后再次尝试发现没有错误
也想不出其他特殊的情况,询问大神后,认识到一个更简洁的做法:
#include<stdio.h>
int main(void) {
int count = 0; //count用来计算单词数目
char cur,pre=' '; //ch用来存放字符
while ((cur = getchar()) != '\n') {
if (pre == ' ' && cur != ' ' && cur!='.') {
count++;
}
pre = cur;
}
printf("%d", count); //输出count
return 0;
}
这种做法的思路是:前一个字符是空格,现在的字符不是空格且不是'.' ,那就单词数就加1,显然这种思路比我一开始的思路要简单许多,不用再去想办法把空格或者是单词吃光。
题目2:7-3 找最长的字符串
1. 本题PTA提交列表
2. 设计思路
1.定义整数型变量n代表输入的行数,i代表循环变量,max代表最长字符串的长度,len代表字符串的长度,定义字符型型数组longest[]来存放每轮比较后,长度最长的字符串。定义字符型数组str[]来存放每次新输入待比较的字符串
2.输入n的值
3.利用getchar()吃掉输入n的时候留下的回车
4.for(i=0;i<n;i++){
输入字符串
利用函数strength来计算str字符串的长度len
如果这次的字符串长度大于max
则max=len
利用strcopy函数把str字符串放在longest[]数组中
5.输出最长的字符串
3.代码截图
4.本题调试过程碰到问题及PTA提交列表情况说明。
- 这题主要是对题意所说的不超过80的理解出现偏差,误以为每行每列都不超过80,然后char str[81][81] 企图把所有的字符串都放在数组里,然后再定义一个count[81]的数组来记录每行的字符串长度。但是实际上题目所说的只是每行不超过80个字符,但是对于N的上限并没有提及,于是就出现了pta提示的段错误;
解决方法:不再定义那么大的数组来存放所有内容,而是两两比较,然后把长的留下来。同时也感受到strength函数和strcopy函数很便利~~~
题目3:7-12 IP地址转换
1. 本题PTA提交列表
2. 设计思路
3.代码截图
4.本题调试过程碰到问题及PTA提交列表情况说明。
- 1.一开始忘记给k1,k2,k3,k4赋初值导致答案错误,后再次认真查看代码后发现这个愚蠢的错误
- 2.标点符号的错误导致答案错误:题目要求 ','隔开,但是我用中文, 反思:除了注释代码的时候应该时刻开着英文输入模式。不过这两个常见的小错误很快就找出来了~~再次提及加以警示~
二、截图本周题目集的PTA最后排名。
三、同学代码结对互评
1.互评同学名称
王林聪同学
2.我的代码、互评同学代码截图
3.我和同学代码不同在哪里?有哪些各自优势?你更喜欢哪种代码风格?
- 思路的不同:我是利用多个数组,然后把加权求和后的结果跟check数组里对应的数对比判断是否相等,若相等就是正确的身份证。
而王林聪同学是再自定义了一个函数,然后函数里利用switch来判断最后一个字符是否正确。 - 我的优势:更加的简洁一些但是容易出错而且没那么容易查错
- 他的优势:自定义函数的思想值得让人学习,而且利用switch虽然长了点,但是非常清晰明了,代码更加容易让人读懂
- 我更喜欢自己的代码风格:因为更加简洁一点点,代码的执行效率会更高一点。但是他的代码也有很多值得我学习的地方,比如善于利用函数,还有注释很详细,条理很清晰。
四、本周学习总结(3分)
1.你学会了什么?
1.1指针变量如何定义?
定义指针变量的一般形式为:
类型名 *指针变量名;
类型名指定指针变量所指向变量的类型,必须是有效的数据类型,
int,float, char等。
1.2 指针加法运算运用在哪种情况,2个指针变量能否相加?
- 1.运用在指向数组的指针变量
- 2.两个指针变量不能进行加法运算。 例如, pf1+pf2是什么意思呢?毫无实际意义。
- 补充~:
对于指向数组的指针变量,可以加上或减去一个整数n。设pa是指向数组a的指针变量,则pa+n,pa-n,pa++,++pa,pa--,--pa 运算都是合法的。指针变量加或减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。应该注意,数组指针变量向前或向后移 动一个位置和地址加1或减1 在概念上是不同的。因为数组可以有不同的类型, 各种类型的数组元素所占的字节长度是不同的。如指针变量加1,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。
例如:
int a[5],pa;
pa=a; /pa指向数组a,也是指向a[0]/
pa=pa+2; /pa指向a[2],即pa的值为&pa[2]*/ 指针变量的加减运算只能对数组指针变量进行, 对指向其它类型变量的指针变量作加减运算是毫无意义的。(3)两个指针变量之间的运算只有指向同一数组的两个指针变量之间才能进行运算, 否则运算毫无意义。
①两指针变量相减
两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。实际上是两个指针值(地 址) 相减之差再除以该数组元素的长度(字节数)。例如pf1和pf2 是指向同一浮点数组的两个指针变量,设pf1的值为2010H,pf2的值为2000H,而浮点数组每个元素占4个字节,所以pf1-pf2的结果为 (2000H-2010H)/4=4,表示pf1和 pf2之间相差4个元素。
②两指针变量进行关系运算
指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的关系。例如:
pf1==pf2表示pf1和pf2指向同一数组元素
pf1>pf2表示pf1处于高地址位置
pf1<pf2表示pf2处于低地址位置
1.3 指针不赋初值,直接使用,会出现什么情况,请用DEVC验证,并截图展示?
devc无法正常运行,指针不赋初值是个危险的状态
1.4 课堂派上关于分离浮点数的整数部分和小数部分那题,请用DEVC验证实现,并在此贴图展示,同时说明哪句是指针变量做函数形参,函数实参应该怎么表示。指针变量做函数形参有什么用处?
#include<stdio.h>
void splitfloat(float x, int *intpart, float *fracpart) { //指针变量 *intpart,*fracpart作函数的形参
*intpart = (int)x;
*fracpart = x - *intpart;
}
int main(void)
{
int m;
float n,f;
scanf("%f", &n);
splitfloat(n, &m, &f);
printf("%d %f", m, f);
return 0;
}
- 好处:1.可以在被调函数中,改变形参所指向变量的值
- 2.指针可以实现函数调用返回多个值
1.5 请把课本的冒泡排序的函数改成指针变量做形参格式,并把代码写在底下,注意用markdown语法渲染。
#include <stdio.h>
void bubble(int a[],int n);
int main (void){
int n,a[8];
int i;
printf("Enter n(n<=8):");
scanf("%d",&n);
printf("Enter a[%d]:",n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
bubble(a,n);
printf("After sorted,a[%d] =",n);
for(i=0;i<n;i++){
printf("%3d",a[i]);
}
return 0;
}
void bubble (int a[],int n)
{
int *p;
p=a;
int i,k,temp;
for(i=0;i<n;i++){
for(k=0;k<n-1-i;k++){
if(*(p+k)>*(p+k+1)){
temp=*(p+k);
*(p+k)=*(p+k+1);
*(p+1+k)=temp;
}
}
}
}
1.6 如何定义一个指针变量指向数组,如何用指针变量表示数组元素?
int a[100], *p;
p=a; // 或者 p=&a[0];
则*p==a[0] //此时*p表示a[0]
1.7 如何定义字符指针指向字符串?指针指向字符串后,初始位置在哪里?
定义:
char *cp = "abc"; //这个初始化过程,是将指针cp指向字符串的首地址,而并不是传递字符串的值。因为,在C语言里面,没有整体处理一个字符串的机制
初始位置:
字符串的首地址(即:p指向了字符串首地址)
赋值:
cp=''abc''
※cp=”abc” ; //错误!字符串常量传递的是它的首地址,不可以通过※cp修改该字符串的值,因为该字符串为常量,而它只是简单的将指针指向该字符串常量
1.8 利用字符指针操作字符串,如设计函数实现字符串连接,请在此贴图展示代码。说明指针表示字符的方法好处是什么?
#include <stdio.h>
#define MAXN 80
char *strmcat( char *str1, const char *str2 );//使用const来约束strSrc,提高程序的健壮性。如果函数体内的语句试图改动str2的内容,编译器将指出错误。
int main()
{
char s[MAXN], t[MAXN];
int m;
gets(s);
gets(t);
printf("%s\n",strmcat(s,t));
return 0;
}
指针表示字符的方法好处:通过自定义函数里定义的指针表示主函数里的字符就可以在自定义的函数里改变主函数里定义的字符数组,使用指针能使自定义的函数返回多个值。
2.本周你不会内容有什么?
- 1.指针变量作为函数的形参通过传地址来改变实参等的指针与函数调用相结合的题目还非常非常不熟练
- 2.这周字符数组的pta磕磕绊绊非常多,思路没有像之前那么清晰,可能是对字符和数组的掌握都不够好,所以做起来很不顺利,但是有请教了这章学的比较好的同学,他给我的建议是多去看看课堂派的题,去模仿它的代码思想,然后去学习,静言思之,林丽老师也曾这么建议,看来课堂派的题目好好利用起来一定会有很大的收获,这也是我在这次上机考试中受挫然后得到很大的感悟:平时老师讲解的题目再也不能拘泥于听懂了,而是要回来重新完整过一遍,因为这次的题几乎都有在课堂上讲解过,当时我是明白的,但是没想到等到真正做题的时候,随着时间的推移,一知半解早就变成了无从下手了。
2.1 课堂派错题罗列及如何订正。
- 错误分析:对指针变量的实质没有搞清楚
- 解析:p=&a,说明p才是a的地址,而p则表示指向a,即p等于a的值
而scanf函数传值实质是传给某个变量的地址,故应该用p
- 错误分析:没有掌握字符指针指向字符串的定义
- 解析:char *cp = "abc"; cp = "abc"; 都是正确的
2.2 其他不会的?打算怎么解决
- 其他不会的打算截图然后放在博客别的随笔中,先自己慢慢琢磨,如果实在看不懂的话可以向学得比较好的同学请教然后再自己总结。
3.数组上机考试小结
3.1 那题错了,请罗列?
3.2 错题如何订正,为什么错了?
- 6-1循环右移:上一周的pta有一题跟这题很像的是循环左移,但是我利用的是直接在输入的时候改变下标的做法,然后按下标顺序输出就可以实现。但是6-1这题是作为函数补充题,我必须按照它原来有的思想再去改变顺序,而这个做法是老师上课所讲解过的,但是当时我仍然自认为自己的做法比较简便,听过就没放在心上,等到上机考试出现的时候我的心态就崩了,然后努力去回想老师上课所讲的内容但是啥都想不起来,然后竟然又琢磨改变下标的方法和重新找一个数组来存放,但是因为分析错误还是当时思路出错,一直都没得到想要的答案。
- 6-2的转置我可以实现,但是排序我是利用了冒泡法排序,但是因为循环次数没搞清楚导致结果一直出错一直出错,也是反映出了我对排序法还是容易出错的致命现实。
- 7-3在前面那几题窒息的操作后,这题我根本没机会看到,然而在这周末我写pta字符数组的时候遇到这题才发现原来这题是不难的,是可以掌握的。