这是自己的第一篇博客。留给自己做个纪念吧。
因为是洛谷的题,肯定有很多大神写了更简单的解法,我这个不够简洁应该没人会看到…
自己刚入门确实比较菜,要学习的还有很多。打算把C++学完了再重新刷一遍新手村,也能更好地理解大佬们的题解。
这题昨天下午敲了一小时,运行时发现连输出都没有…今早索性全部推倒重来,多写了几个函数。这题确实有一些坑,需要细心地注意0在整数部分和小数部分不同位置的各种情况。第一次提交有8个数据点没有过,后面修修补补才全部AC。
//开一个字符数组,存放原数据,输入,存入。
//遍历,查找特征符号,标记状态(自动机)。
//编写一个通用函数,malloc一个新的字符数组,直接将原字符串倒着存入。
//编写两个函数,用于整数和小数。根据前面确定的状态,分别调整新字符串。
//最后输出新字符串并补上特征符号。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//自动机的四种状态
#define INT 1 //整数
#define DEC 2 //小数
#define FRA 3 //分数
#define PER 4 //百分数
void input(char *); //把scanf和getchar合并
char* rotate(char *str, int length); //把字符串翻转
void forFRA(char *str, int length); //处理分数的函数
void forDEC(char *str, int length); //处理小数的函数
void forPER(char *str, int length); //处理百分数的函数
void forINT(char *str, int length); //处理整数的函数
char *function2(char *str); //处理末尾的0(用于小数部分翻转前、后)
char *function1(char *str); //处理开头的0 (用于翻转后的整数部分)
int status(char *str); //检测特殊字符,确定自动机状态
int main()
{
char original[21];
int type, length;
input(original);
type = status(original);
length = strlen(original);
switch(type)
{
case INT:
forINT(original, length);
break;
case DEC:
forDEC(original, length);
break;
case FRA:
forFRA(original, length);
break;
case PER:
forPER(original, length);
break;
}
}
void input(char *str)
{
scanf("%s", str);
getchar();
}
int status(char *str)
{
char *temp = str;
int flag = 1;
//若检测到特征字符,把该字符设置为空,把字符串分为两部分
//同时用flag来确定已经检测到了特殊字符,退出遍历
while (*temp && flag == 1)
{
if (*temp == '.')
{
flag = 2;
*temp = 0;
}
else if (*temp == '/')
{
flag = 3;
*temp = 0;
}
else if (*temp == '%')
{
flag = 4;
*temp = 0;
}
temp++;
}
return flag;
}
//重新malloc一个字符数组,倒着把源字符串存进去
//最后返回新字符串的指针
//要注意的是,malloc数量应该是length+1,不能漏了'\0'
char* rotate(char *str, int length)
{
int i;
char *temp = (char*)malloc(sizeof(char) * length + 1);
for (i = 0; i < length; i++)
temp[i] = str[length - i - 1];
temp[length] = 0;
return temp;
}
char *function1(char *str)//用于处理整数部分
{
int status = 0;
char *temp = str;
//从前往后遍历,在遇到非0数前状态为0。若遇到非零数,改变状态。
//因为是通过指针偏移进行访问,最后返回已经偏移的指针即可。
while(*temp && status == 0)
{
if (*temp != '0')
status = 1;
if (status == 0)
temp++;
}
return temp;
}
char *function2(char *str)
{
int length = strlen(str);
int status = 0;
//与整数部分不同,小数部分从后往前遍历。
for(; length - 1 >= 0 && status == 0; length--)
if(str[length - 1] == '0')
str[length - 1] = 0;
else
status = 1;
return str;
}
void forINT(char *str, int length)
{
//这里是踩的第一个坑。
//如果原字符串整数部分就是一个0,那么直接输出0即可。
//不用旋转和进入function1,否则是空字符。
if(*str == '0')
printf("0");
else
{
char* reverse = rotate(str, length);
printf("%s",function1(reverse));
//不要忘记free掉malloc的内存
free(reverse);
}
}
void forPER(char *str, int length)
{
forINT(str, length);
//这里也有个小细节,printf中百分号要打两个,否则编译器会认为是少了转换说明
printf("%%");
}
void forDEC(char *str, int length)
{
//这里是第二个坑
//对于源字符串的小数部分,如果原本末尾就有0,那应该是舍去的。
//例如12.560,应该是以21.65进行翻转。否则,21.065是错误的结果。
//因此,应该在翻转之前进行一次末尾去0,保证有效数字位数正确。
char* pfloat = function2(str + length + 1);
pfloat = rotate(pfloat, strlen(pfloat));
forINT(str, length);
printf(".");
//这里是第三个坑
//按照function2的做法,从后往前遍历,只要是遇到非零数前的0全部更改为空字符。
//这就导致,如果是如123.0这样的数,会被直接输出321.
//因此,应该在function2、翻转、function2之后,判断一下是否是空字符。
//若为空字符,则直接输出0.
if(*function2(pfloat) == 0)
printf("0");
else
puts(function2(pfloat));
free(pfloat);
}
void forFRA(char *str, int length)
{
char* pfloat = function2(str + length + 1);
pfloat = rotate(pfloat, strlen(pfloat));
forINT(str, length);
printf("/");
if(*function2(pfloat) == 0)
printf("0");
else
puts(function2(pfloat));
free(pfloat);
}
第一次写博客。
如果有人会看到的话,欢迎指点和沟通。
实在是刚入门,技术太菜。
但是要相信自己,会进步的~
新的学期,请多多指教。