C语言博客作业05——指针

1.本章学习总结

1.1思维导图

1.2本章学习体会及代码量

1.2.1学习体会

可能因为之前数组那块儿的作业拖得太久了,以至于我觉得指针学的好快,还没反应过来就教完了,然后一开始做题的时候,就是一脸懵逼得状态。然后前段时间也都在不数组的作业,指针也没好好看看书,也就上课的时候听听老师讲课,然后后面做题,一不会就去翻书,一来二去的虽然还是不很明白指针到底怎么回事,但是大概的题目也都会做了。然后现在我把指针跟结构体的题目集都刷完了,也该好好补补指针的知识点了。

1.2.2代码累计

2.PTA总分

2.1截图PTA中指针题目集的排名得分

2.2我的总分

PTA总分:110

3.PTA实验作业

3.1PTA题目1

反话-加强版 
给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。

3.1.1算法分析

定义整型变量:i、j、k=0、count=0、length、temp
定义字符型指针:ch
ch=(char *)malloc(500001*sizeof(ch));//通过malloc把较大的数组放到堆区,防止爆栈 
输入字符串ch
通过strlen函数得到字符串ch的长度
temp=length-1    //解决末尾为空格的情况
while length-- do
  while ch[k]为空格 do    //解决前面有连续空格的情况
    k++
  end while
  if length=0 且 ch[0]!=' ' then
    for j=0 to count do
      putchar(*(ch+j))    //输出开头不为空格时的单词
    end for
  end if
  if ch[length] 不为空格 then
    count++
  else if ch[length]为空格 且 ch[length+1]不为空格 且 length不是字符串尾 then 
    for i=1 to count do
      putchar(*(ch+length+i))
    end for
    if length+1!=k then 
      printf(" ")
    end if
    count=0
  else if ch[length]为空格 且 ch[length+1]为空格 或者 ch[length]为空格 then 
    continue
  end if
end while

3.1.2代码截图


3.1.3PTA提交列表及说明

  • Q:一开始直接用printf输出,然后输出的都是这样子的
  • A:运行之前,我一直把printf认为是跟scanf一样的,遇到空格就停下来,结果是我太天真了…然后当时可能脑子有点抽了,一直想不到除了printf和puts()还有什么输出方式,然后又用循环和printf一个一个字符的输出,结果…不知道为什么输出了一堆乱七八糟的东西。然后过了好久好久才想到了putchar()这个家伙,运行了一下结果对了,就提交了。
  • Q:兴致冲冲的提交完之后他告诉我:部分正确…
  • A:然后看了一眼测试点,三个没过:一个词,末尾有空格、最小词,前有空格、只有空格,然后经过一番改动,自认为可以过了,结果一提交,还是部分正确…再看一眼,最小词,前有空格这个点还是没过,我想着我已经把开头第一个是空格的情况加进去了,怎么会还错,然后一调试,发现当开头是连续空格的时候,我的输出是错的,输出多了空格。突然想起来大作业里消除非法字符串的做法,想想这里的情况也差不多,就用了一个while解决了开头的连续空格的问题。

4.大作业

题目:实现小学四则运算。

在函数那章,我们已经实现小学四则运算这份作业,现在要求大家把之前设计函数升级改造,原来的函数大家都是用全局变量实现不同函数参数传递,这次作业要求改地址传递,减少全局变量的使用。

题目要求:

题目有3个难度级别,分别为:

  • 第一级是1位数的一步加减乘除计算
  • 第二级是2位数的2步加减运算
  • 第三级是3位数的2步加减运算

4.1改造函数介绍

1.构造字符数组存放算术表达式

*char CreateExp(char exp,char level);

  • 伪代码
定义整型变量num、op(获取随机数)、i,字符型数组str[10](用于整型转字符型存放)
srand(time(NULL)) //获取随机数种子
if level=='1' then 
  i=3 //一级运算数及运算符的总和
  while --i do
    if i为偶数 then
      num=rand()%10;
      itoa(num,str,10)//将整型变量num转化为字符型变量存入数组str中
      strcat(exp,str);//将str数组中的字符串接在exp数组后
    else
      op=rand()%4;
      switch(op)//随机获取运算符,并接在数组exp后
        case 0: strcat(exp,"+");;break;
        case 1: strcat(exp,"-");break
	case 2: strcat(exp,"*");break;
    	case 3: strcat(exp,"/");break;
    end if
  end while
else//当level为2或3时
  i=5 //二(三)级运算数及运算符的总和
  while --i do
    if i为偶数 then 
      if level=='2' then
        num=rand()%100
      else
        num=rand()%1000
      end if
      itoa(num,str,10)//将整型变量num转化为字符型变量存入数组str中
      strcat(exp,str);//将str数组中的字符串接在exp数组后
    else
      op=rand()%4;
      switch(op)//随机获取运算符,并接在数组exp后
        case 0: strcat(exp,"+");;break;
        case 1: strcat(exp,"-");break
    end if
  end while
end if
strcat(exp,"=")//将等号接在表达式后
if 表达式合法 then
  输出表达式
else
  返回CreateExp(exp,level)函数,重新创建表达式
return *exp//返回指针*exp
  • 函数代码
char CreateExp(char *exp,char level)//构造字符数组存放算术表达式
{
	int num,i;
	int op;
	char str[10];
	srand(time(NULL));
	if(level=='1')
	{
		i=3;//运算数及运算符的总和 
		do
		{
			if(i%2)
			{
				num=rand()%10;
				itoa(num, str, 10);
				strcat(exp,str);
			}
			else
			{
				op=rand()%4;
		        switch(op)
	        	{
		         	case 0: strcat(exp,"+");;break;
		        	case 1: strcat(exp,"-");break;
		        	case 2: strcat(exp,"*");break;
		        	case 3: strcat(exp,"/");break;
	        	}
		    }
		}while(--i);
	}
	else
	{
		i=5;//运算数及运算符的总和 
		do
		{
			if(i%2)
			{
				if(level=='2')
				    num=rand()%100;
				else
				    num=rand()%1000;
				itoa(num, str, 10);
				strcat(exp,str);
			}
			else
			{
				op=rand()%2;
		        switch(op)
	        	{
		         	case 0: strcat(exp,"+");break;
		        	case 1: strcat(exp,"-");break;
	        	}
		    }
		}while(--i);
	}
	strcat(exp,"=");
	if(IsExp(exp,level))//判断表达式是否合法
	    printf("
				%s",exp);
	else
	    return CreateExp(exp,level);//表达式不合法时返回CreateExp(exp,level)函数,重新创建表达式
	return *exp;
}

2.表达式是否合法

*int IsExp(char exp,char level);

  • 伪代码
if 等级为二、三级 then //二三等级不含除法,即不存在表达式不合法情况
  return 1;
定义整型变量m=0,sum=0,i=0、字符型变量c=exp[i],oldc='+'
while c!='=' do
  c=exp[i]
  if c为数字 then 
    m=10*m+c-'0'//将字符型数字转化为整型数字
  else
    if oldc=='+' then 
      sum+=m
    else if oldc=='/' then
      if m==0 或者 sum%m!=0 then //不合法情况,即除数为零、不能整除
        return 0
      end if
    end if
    m=0//初始化 ,用于下一轮转化整型变量
    oldc=c
  end if
  i++
end while
return 1
  • 函数代码
int IsExp(char *exp,char level)//表达式是否合法
{
	if(level=='2'||level=='3')//二三等级不含除法,即不存在表达式不合法情况
	    return 1;
	int m=0, sum=0,i=0;
        char c, oldc='+';
        do 
	{
        c = exp[i];
        if( c<='9'&&c>='0' ) 
            m = 10*m + c - '0';
        else 
        {
            if( oldc == '+' )
                sum += m;
            else if(oldc == '/')
            {
            	if(m==0 || sum%m!=0)//不合法情况,即除数为零、不能整除
            	return 0;
			}
            m = 0;
            oldc = c;
          }
          i++;
    } while(c!='=');
    return 1;
}

3.表达式运算

*int ComputeExp(char exp);

  • 伪代码
定义整型变量m=0,sum=0,i=0、字符型变量c=exp[i],oldc='+'
while c!='=' do
  c=exp[i]
  if c为数字 then
    m=10*m+c-'0'//将字符型数字转化为整型数字
  else
    if oldc是+ then
      sum+=m
    else if oldc是- then 
      sum-=m
    else if oldc是* then 
      sum*=m
    else if oldc是/ then 
      sum/=m
    end if
    m=0//初始化
    oldc=c
  end if
  i++
end while
return sum
  • 函数代码
int ComputeExp(char *exp)//表达式运算
{
	int m=0, sum=0,i=0;
        char c, oldc='+';
        do 
	{
        c = exp[i];
        if( c<='9'&&c>='0' ) 
            m = 10*m + c - '0';//将字符型数字转化为整型数字
        else //计算表达式
        {
            if( oldc == '+' )
                sum += m;
            else if(oldc == '-')
                sum -= m;
            else if(oldc == '*')
                sum*=m;
            else if(oldc == '/')
                sum/=m;
            m = 0;//初始化
            oldc = c;
        }
        i++;
   } while(c!='=');
   return sum;
}

4.3与原有函数代码比较

  • 函数的功能上
    因为上一回做大作业的时候时间有点赶,代码功能不够齐全,函数的设计上自我感觉也不够理想,于是这次的大作业是我在上回大作业的思路的基础上重新打的,与原来默认每轮只做十道题相比,多了一个题数选择的功能。
  • 函数分装上
    将原来void Screen();//提示界面 、void Menu();//显示菜单这两个函数整合成一个函数void Screen();//提示界面
  • 创建表达式上
    · 原代码
void NumberGet()
{
	if(levelChoice=='1')
	{
		srand(time(NULL));
		number1=rand()%10;
		number2=rand()%10;
	}
	else if(levelChoice=='2')
	{
		srand(time(NULL));
		number1=rand()%100;
		number2=rand()%100;
		number3=rand()%100;
	}
	else
	{
		srand(time(NULL));
		number1=rand()%1000;
		number2=rand()%1000;
		number3=rand()%1000; 
	}
}
void OperatorGet()
{
	if(levelChoice=='1')
	{
		srand(time(NULL));
		operator_ch1=rand()%4;
		switch(operator_ch1)
		{
			case 0:ch1='+';break;
			case 1:ch1='-';break;
			case 2:ch1='*';break;
			case 3:ch1='/';break;
		}
	}
	else
	{
		srand(time(NULL));
		operator_ch1=rand()%2;
		operator_ch2=rand()%2;
		switch(operator_ch1)
		{
			case 0:ch1='+';break;
			case 1:ch1='-';break;
		}
		switch(operator_ch2)
		{
			case 0:ch2='+';break;
			case 1:ch2='-';break;
		}
	}
}
//函数void GameBegin()中的一部分
if(levelChoice=='1')
{
	NumberGet(); //获取随机数 
	OperatorGet(); //随机获取运算符 
	printf("%.0f %c %.0f = ",number1,ch1,number2);
	scanf("%lf",&yourAnswer);
	rightAnswer=Calculate();
	if(yourAnswer==rightAnswer)
	{
	 printf("
				Good job!^_^
");
	 i++;
	}
	else
	{
		printf("
				回答错误!>_<
");
		printf("
	                                  正确答案是:%.0f %c %.0f = %.2lf
",number1,ch1,number2,rightAnswer);
		j++;
	}
}
else
{
	NumberGet(); //获取随机数 
	OperatorGet(); //随机获取运算符 
	printf("%.0f %c %.0f %c %.0f = ",number1,ch1,number2,ch2,number3);
	scanf("%lf",&yourAnswer);
	rightAnswer=Calculate();
	if(yourAnswer==rightAnswer)
	{
	        printf("
				Good job!
");
	        i++;
	}
	else
	{
		printf("
				回答错误!>_<
");
		printf("
				正确答案是:%.0f %c %.0f %c %.0f = %.0lf
",number1,ch1,number2,ch2,number3,rightAnswer);
		j++;
	}
}

· 改造后的代码(如上char CreateExp(char *exp,char level);函数)

1.原函数中,随机数与随机运算符的获取分装为两个函数,表达式的输出也只是由一个简单的printf()输出
而改进后的代码,将随机数与随机运算符的获取再加上表达式的整合放在同一个函数中,使代码更加简洁
2.原代码中,多次调用随机数和随机运算符的获取函数,在效率上拖慢了程序的运行,而改进后的代码则不存在多次重复调用的情况出现
  • 在判断表达式是否合法上
    在原来的程序中,我并没有设置判断表达式是否合理的函数,而是针对除法不能整除时,令结果保留两位小数(代码如下)

    而为了解决除数为0的情况,我直接将除数的取值范围定在1到9之间,就不存在除数为0的情况了

    指针版的大作业中老师明确要求了,将除法不能整除和除数为0的情况设为不合法表达式,受老师博客中计算字符串表达式代码的影响,我的判断表达式是否合法的函数如下

然后其余的函数基本都大同小异

4.4改进大作业总结

  • 其实两次大作业做下来,都有一个让我很闹心的地方,就是我在函数调用上出了点小问题,我的主函数中只有void GameBegin();这一个子函数。在做指针版的大作业时,我在主函数中已经打好框架了,(就是void GameBegin();函数中的内容)但是在我的所有函数都补充完了之后,我想要做一个每轮结束之后再次进入程序的函数,但是不能用 return main 所以我只好将主函数中的所有内容都放到一个函数中,再将这个函数放入主函数中,这样就导致了我的主函数中只有一行代码(让我自己看的很难受,但是又不知道怎么解决)
  • 老师在课上提到了整型数字转化为字符型数字有专门的函数时,我就回去百度了一下,然后按照先获取整形随机数,再将其转化为字符型数字的思路做了。
  • 然后顺着老师提供的如何计算字符串表达式的方法,我在想反正不合法表达式只存在与一级题目的除法运算中,那这种方法也可以用来判断表达式是否合法。
  • 其实从总体上看,我这次大作业更多的是依赖于老师博客上提供的思路与做法进行改进的,自我感觉并没有太多的自己思考的地方。
  • 老师博客上提供的算法其实是之前课堂派上的一道题目,让我知道其实我们可以多多学习平常课堂派中题目的思路。
原文地址:https://www.cnblogs.com/Lay-549/p/10127341.html