完善以下代码 #define _LCD_Data sprintf #define _LCD_Buffer (char *)char_x sprintf(_LCD_Buffer,"jedkfsldz"); LCD_ShowString(30,210,100,240,24,_LCD_Buffer);
时间: 2024-02-17 14:00:10 浏览: 114
这段代码中,`_LCD_Data` 和 `_LCD_Buffer` 都是宏定义,它们的作用是简化代码中的字符串格式化操作。其中,`_LCD_Data` 宏定义了一个名为 `_LCD_Data` 的函数,其实质就是调用了 `sprintf` 函数。`_LCD_Buffer` 宏定义了一个名为 `_LCD_Buffer` 的字符数组,用于存储格式化后的字符串。
完善这段代码的过程中,需要修改 `_LCD_Buffer` 的定义,让它能够存储任意长度的字符串,而不是固定长度的字符串。可以将 `_LCD_Buffer` 定义为一个指针,然后在使用前根据需要进行内存分配。修改后的代码如下:
```c
#define _LCD_Data sprintf
char* _LCD_Buffer;
_LCD_Buffer = (char*)malloc(100); // 分配 100 字节的内存
sprintf(_LCD_Buffer, "jedkfsldz");
LCD_ShowString(30, 210, 100, 240, 24, _LCD_Buffer);
free(_LCD_Buffer); // 释放内存
```
这段代码在使用 `_LCD_Buffer` 前,先将其定义为一个指针,并分配了 100 字节的内存。然后使用 `sprintf` 函数将字符串格式化后存储到 `_LCD_Buffer` 中,最后将其传递给 `LCD_ShowString` 函数进行显示。注意,在使用完 `_LCD_Buffer` 后,需要使用 `free` 函数将其释放掉,以避免内存泄漏。
相关问题
完善以下代码 u8 i=9; #define _LCD_Data sprintf #define _LCD_Buffer (char *)char_x sprintf(_LCD_Buffer,"%d",i);
这段代码中,定义了一个整型变量 `i`,其值为 9。接下来使用了两个宏定义,`_LCD_Data` 和 `_LCD_Buffer`,其中 `_LCD_Data` 宏定义了一个名为 `_LCD_Data` 的函数,其实质就是调用了 `sprintf` 函数;`_LCD_Buffer` 宏定义了一个名为 `_LCD_Buffer` 的字符数组,用于存储格式化后的字符串。
这段代码的目的是将整型变量 `i` 转换为字符串,并存储到 `_LCD_Buffer` 中,最终将其传递给某个函数进行显示。但是,这段代码存在一些问题:
1. `_LCD_Buffer` 的定义不正确,应该是 `char*` 类型,而不是 `(char*)` 类型;
2. `sprintf` 函数的第二个参数应该是一个格式化字符串,指定了占位符的位置和类型,例如 `"%d"` 表示输出一个十进制整数;
3. 在使用完 `_LCD_Buffer` 后,需要使用 `free` 函数将其释放掉,以避免内存泄漏。
完善后的代码如下:
```c
u8 i = 9;
#define _LCD_Data sprintf
char* _LCD_Buffer;
_LCD_Buffer = (char*)malloc(20); // 分配 20 字节的内存
sprintf(_LCD_Buffer, "%d", i);
LCD_ShowString(30, 210, 100, 240, 24, _LCD_Buffer);
free(_LCD_Buffer); // 释放内存
```
这段代码中,将 `_LCD_Buffer` 定义为一个 `char*` 类型的指针,并分配了 20 字节的内存。使用 `sprintf` 函数将整型变量 `i` 转换为字符串,并存储到 `_LCD_Buffer` 中,最终将其传递给 `LCD_ShowString` 函数进行显示。注意,在使用完 `_LCD_Buffer` 后,需要使用 `free` 函数将其释放掉,以避免内存泄漏。
#include "stm32f10x.h" // Device header #include "Delay.h" #include "Key.h" #include "Led.h" #include "serial.h" #include "OLED.h" #include "Time.h" #include "Stack.h" static unsigned char Clear_Index=0; //清零检索 static unsigned char Count_Index=0; //计算检索 static uint32_t Index=0; static unsigned char Firmula[100]; //存储算数式子 static unsigned int Result; //存储结果 void USART1_IRQHandler(void); unsigned char a=19; int main(void) { Key_Init(); OLED_Init(); Serial_Init(); while(1) { if(Key_GetNum1()) //计算算数式 { Result=Deposit(Firmula); Count_Index=1; } if(Count_Index) //发送结果 { if(Key_GetNum2()) { printf("结果=%d",Result); OLED_ShowNum(1,1,Result,4); Index=0; Clear_Index=1; Count_Index=0; } } if(Clear_Index) //清零 { if(Key_GetNum3()) { Clear_Index=0; Init(); } } else if(!Clear_Index) { if(Key_GetNum3()) { printf("请输入运算式"); } } } } void USART1_IRQHandler(void) //串口中断函数 { Firmula[Index]=Serial_Getbyte(); printf("%c",Firmula[Index]); Index++; }#include "stm32f10x.h"// Device header #include "Stack.h" #include<ctype.h> #include "Serial.h" Stack_char Stack_CHAR; Stack_num Stack_NUM; uint8_t Push_char(Stack_char *stack,uint8_t CH); uint8_t Pop_char(Stack_char *stack,uint8_t *c); uint8_t Push_num(Stack_num *stack,unsigned int NUM); uint8_t Pop_num(Stack_num *stack,unsigned int *n); void Eval(void); uint16_t Priority(uint8_t ch); void Init(void) { Stack_NUM.top=0; Stack_CHAR.top=0; } uint16_t Priority(uint8_t ch) { switch(ch) { case '(' : case ')' : return 3; case '*' : case '/' : return 2; case '+' : case '-' : return 1; default : return 0; //分化优先级 } } uint32_t Deposit(uint8_t *String) { unsigned int i,j,index=0; uint8_t C; Init(); for(i = 0;String[i]!='\0'&&i < Stack_Size ;i++) { if(isdigit(String[i])) //判断是否 '0'<=string<='9' { index=0; j=i; for(;isdigit(String[j])&&j< Stack_Size;j++) { index=index*10+(String[j]-'0'); } Push_num(&Stack_NUM,index); i=j-1; //因为for循环多加了1,所以减去1 } else if(String[i]=='(') { Push_char(&Stack_CHAR,String[i]); } else if(String[i]==')') { while(Stack_CHAR.ch[Stack_CHAR.top] != '(') {Eval();} //直到遇到左括号,并且计算 if(Stack_CHAR.top != 0 && Stack_CHAR.ch[Stack_CHAR.top] == '(') { Pop_char(&Stack_CHAR,&C); //弹出左括号 } } else { while(Stack_CHAR.top!=0&&Stack_CHAR.ch[Stack_CHAR.top]!='('&&Priority(Stack_CHAR.ch[Stack_CHAR.top])>=Priority(String[i])) { Eval(); } Push_char(&Stack_CHAR,String[i]); } } while(Stack_CHAR.top) { Eval(); } //循环直至操作符为空 return Stack_NUM.num[Stack_NUM.top]; //此时数栈顶元素即为表达式值 } void Eval(void) { uint32_t a,x,b; uint8_t cha; Pop_num(&Stack_NUM,&b); Pop_num(&Stack_NUM,&a); //由于栈是陷进后出,与队列有区别(先进出) Pop_char(&Stack_CHAR,&cha); switch(cha) { case '*' : x=a*b;break; //计算 case '/' : { if(b==0) {printf("除数不能为0");x=0;} else {x=a/b;} break; } case '+' : {x=a+b;break;} case '-' : {x=a-b;break;} default :break; } Push_num(&Stack_NUM,x); } uint8_t Push_char(Stack_char *stack,uint8_t CH) { if(stack->top>=Stack_Size) { return 0; } stack->top++; stack->ch[stack->top]=CH; return 1; } uint8_t Push_num(Stack_num *stack,unsigned int NUM) { if(stack->top>=Stack_Size) { return 0; } stack->top++; stack->num[stack->top]=NUM; return 1; } uint8_t Pop_char(Stack_char *stack,uint8_t *c) { if(stack->top<=0) { return 0; } *c=stack->ch[stack->top]; stack->top--; return 1; } uint8_t Pop_num(Stack_num *stack,unsigned int *n) { if(stack->top<=0) { return 0; } *n=stack->num[stack->top]; stack->top--; return 1; } /* Copyright (C) ARM Ltd., 1999,2014 */ /* All rights reserved */ /* * RCS $Revision$ * Checkin $Date$ * Revising $Author: agrant $ */ #ifndef __stdint_h #define __stdint_h #define __ARMCLIB_VERSION 5060034 #ifdef __INT64_TYPE__ /* armclang predefines '__INT64_TYPE__' and '__INT64_C_SUFFIX__' */ #define __INT64 __INT64_TYPE__ #else /* armcc has builtin '__int64' which can be used in --strict mode */ #define __INT64 __int64 #define __INT64_C_SUFFIX__ ll #endif #define __PASTE2(x, y) x ## y #define __PASTE(x, y) __PASTE2(x, y) #define __INT64_C(x) __ESCAPE__(__PASTE(x, __INT64_C_SUFFIX__)) #define __UINT64_C(x) __ESCAPE__(__PASTE(x ## u, __INT64_C_SUFFIX__)) #if defined(__clang__) || (defined(__ARMCC_VERSION) && !defined(__STRICT_ANSI__)) /* armclang and non-strict armcc allow 'long long' in system headers */ #define __LONGLONG long long #else /* strict armcc has '__int64' */ #define __LONGLONG __int64 #endif #ifndef __STDINT_DECLS #define __STDINT_DECLS #undef __CLIBNS #ifdef __cplusplus namespace std { #define __CLIBNS std:: extern "C" { #else #define __CLIBNS #endif /* __cplusplus */ /* * 'signed' is redundant below, except for 'signed char' and if * the typedef is used to declare a bitfield. */ /* 7.18.1.1 */ /* exact-width signed integer types */ typedef signed char int8_t; typedef signed short int int16_t; typedef signed int int32_t; typedef signed __INT64 int64_t; /* exact-width unsigned integer types */ typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; typedef unsigned __INT64 uint64_t; /* 7.18.1.2 */ /* smallest type of at least n bits */ /* minimum-width signed integer types */ typedef signed char int_least8_t; typedef signed short int int_least16_t; typedef signed int int_least32_t; typedef signed __INT64 int_least64_t; /* minimum-width unsigned integer types */ typedef unsigned char uint_least8_t; typedef unsigned short int uint_least16_t; typedef unsigned int uint_least32_t; typedef unsigned __INT64 uint_least64_t; /* 7.18.1.3 */ /* fastest minimum-width signed integer types */ typedef signed int int_fast8_t; typedef signed int int_fast16_t; typedef signed int int_fast32_t; typedef signed __INT64 int_fast64_t; /* fastest minimum-width unsigned integer types */ typedef unsigned int uint_fast8_t; typedef unsigned int uint_fast16_t; typedef unsigned int uint_fast32_t; typedef unsigned __INT64 uint_fast64_t; /* 7.18.1.4 integer types capable of holding object pointers */ #if __sizeof_ptr == 8 typedef signed __INT64 intptr_t; typedef unsigned __INT64 uintptr_t; #else typedef signed int intptr_t; typedef unsigned int uintptr_t; #endif /* 7.18.1.5 greatest-width integer types */ typedef signed __LONGLONG intmax_t; typedef unsigned __LONGLONG uintmax_t; #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) /* 7.18.2.1 */ /* minimum values of exact-width signed integer types */ #define INT8_MIN -128 #define INT16_MIN -32768 #define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */ #define INT64_MIN __INT64_C(~0x7fffffffffffffff) /* -9223372036854775808 is unsigned */ /* maximum values of exact-width signed integer types */ #define INT8_MAX 127 #define INT16_MAX 32767 #define INT32_MAX 2147483647 #define INT64_MAX __INT64_C(9223372036854775807) /* maximum values of exact-width unsigned integer types */ #define UINT8_MAX 255 #define UINT16_MAX 65535 #define UINT32_MAX 4294967295u #define UINT64_MAX __UINT64_C(18446744073709551615) /* 7.18.2.2 */ /* minimum values of minimum-width signed integer types */ #define INT_LEAST8_MIN -128 #define INT_LEAST16_MIN -32768 #define INT_LEAST32_MIN (~0x7fffffff) #define INT_LEAST64_MIN __INT64_C(~0x7fffffffffffffff) /* maximum values of minimum-width signed integer types */ #define INT_LEAST8_MAX 127 #define INT_LEAST16_MAX 32767 #define INT_LEAST32_MAX 2147483647 #define INT_LEAST64_MAX __INT64_C(9223372036854775807) /* maximum values of minimum-width unsigned integer types */ #define UINT_LEAST8_MAX 255 #define UINT_LEAST16_MAX 65535 #define UINT_LEAST32_MAX 4294967295u #define UINT_LEAST64_MAX __UINT64_C(18446744073709551615) /* 7.18.2.3 */ /* minimum values of fastest minimum-width signed integer types */ #define INT_FAST8_MIN (~0x7fffffff) #define INT_FAST16_MIN (~0x7fffffff) #define INT_FAST32_MIN (~0x7fffffff) #define INT_FAST64_MIN __INT64_C(~0x7fffffffffffffff) /* maximum values of fastest minimum-width signed integer types */ #define INT_FAST8_MAX 2147483647 #define INT_FAST16_MAX 2147483647 #define INT_FAST32_MAX 2147483647 #define INT_FAST64_MAX __INT64_C(9223372036854775807) /* maximum values of fastest minimum-width unsigned integer types */ #define UINT_FAST8_MAX 4294967295u #define UINT_FAST16_MAX 4294967295u #define UINT_FAST32_MAX 4294967295u #define UINT_FAST64_MAX __UINT64_C(18446744073709551615) /* 7.18.2.4 */ /* minimum value of pointer-holding signed integer type */ #if __sizeof_ptr == 8 #define INTPTR_MIN INT64_MIN #else #define INTPTR_MIN INT32_MIN #endif /* maximum value of pointer-holding signed integer type */ #if __sizeof_ptr == 8 #define INTPTR_MAX INT64_MAX #else #define INTPTR_MAX INT32_MAX #endif /* maximum value of pointer-holding unsigned integer type */ #if __sizeof_ptr == 8 #define UINTPTR_MAX UINT64_MAX #else #define UINTPTR_MAX UINT32_MAX #endif /* 7.18.2.5 */ /* minimum value of greatest-width signed integer type */ #define INTMAX_MIN __ESCAPE__(~0x7fffffffffffffffll) /* maximum value of greatest-width signed integer type */ #define INTMAX_MAX __ESCAPE__(9223372036854775807ll) /* maximum value of greatest-width unsigned integer type */ #define UINTMAX_MAX __ESCAPE__(18446744073709551615ull) /* 7.18.3 */ /* limits of ptrdiff_t */ #if __sizeof_ptr == 8 #define PTRDIFF_MIN INT64_MIN #define PTRDIFF_MAX INT64_MAX #else #define PTRDIFF_MIN INT32_MIN #define PTRDIFF_MAX INT32_MAX #endif /* limits of sig_atomic_t */ #define SIG_ATOMIC_MIN (~0x7fffffff) #define SIG_ATOMIC_MAX 2147483647 /* limit of size_t */ #if __sizeof_ptr == 8 #define SIZE_MAX UINT64_MAX #else #define SIZE_MAX UINT32_MAX #endif /* limits of wchar_t */ /* NB we have to undef and redef because they're defined in both * stdint.h and wchar.h */ #undef WCHAR_MIN #undef WCHAR_MAX #if defined(__WCHAR32) || (defined(__ARM_SIZEOF_WCHAR_T) && __ARM_SIZEOF_WCHAR_T == 4) #define WCHAR_MIN 0 #define WCHAR_MAX 0xffffffffU #else #define WCHAR_MIN 0 #define WCHAR_MAX 65535 #endif /* limits of wint_t */ #define WINT_MIN (~0x7fffffff) #define WINT_MAX 2147483647 #endif /* __STDC_LIMIT_MACROS */ #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) /* 7.18.4.1 macros for minimum-width integer constants */ #define INT8_C(x) (x) #define INT16_C(x) (x) #define INT32_C(x) (x) #define INT64_C(x) __INT64_C(x) #define UINT8_C(x) (x ## u) #define UINT16_C(x) (x ## u) #define UINT32_C(x) (x ## u) #define UINT64_C(x) __UINT64_C(x) /* 7.18.4.2 macros for greatest-width integer constants */ #define INTMAX_C(x) __ESCAPE__(x ## ll) #define UINTMAX_C(x) __ESCAPE__(x ## ull) #endif /* __STDC_CONSTANT_MACROS */ #ifdef __cplusplus } /* extern "C" */ } /* namespace std */ #endif /* __cplusplus */ #endif /* __STDINT_DECLS */ #ifdef __cplusplus #ifndef __STDINT_NO_EXPORTS using ::std::int8_t; using ::std::int16_t; using ::std::int32_t; using ::std::int64_t; using ::std::uint8_t; using ::std::uint16_t; using ::std::uint32_t; using ::std::uint64_t; using ::std::int_least8_t; using ::std::int_least16_t; using ::std::int_least32_t; using ::std::int_least64_t; using ::std::uint_least8_t; using ::std::uint_least16_t; using ::std::uint_least32_t; using ::std::uint_least64_t; using ::std::int_fast8_t; using ::std::int_fast16_t; using ::std::int_fast32_t; using ::std::int_fast64_t; using ::std::uint_fast8_t; using ::std::uint_fast16_t; using ::std::uint_fast32_t; using ::std::uint_fast64_t; using ::std::intptr_t; using ::std::uintptr_t; using ::std::intmax_t; using ::std::uintmax_t; #endif #endif /* __cplusplus */ #undef __INT64 #undef __LONGLONG #endif /* __stdint_h */ /* end of stdint.h */ 在不改变原代码变量名情况下,实现小数点预算
<think>我们需要在现有的计算器程序中添加对小数点的支持。现有的代码只支持整数运算,我们需要修改以支持浮点数。
主要修改点:
1. 将操作数栈(Stack_num)的数据类型从unsigned int改为float(或double),以便存储小数。
2. 修改表达式解析过程,使其能够解析带小数点的数字。
3. 修改计算函数(Eval)以支持浮点运算。
4. 注意在显示和串口输出时,可能需要格式化输出浮点数。
但是,注意题目要求:不改变原代码变量名。因此,我们尽量保留原有的变量名,只修改类型和逻辑。
步骤:
1. 修改Stack_num结构体中的num数组为float类型(或double,但考虑到STM32资源,使用float可能更合适)。
2. 修改Push_num和Pop_num函数,使其操作float类型数据。
3. 在Deposit函数中,解析数字时,需要能够解析小数点。我们将整数部分和小数部分组合成一个浮点数。
4. 修改Eval函数,使用浮点数运算。
5. 修改主函数中Result的类型为float,并修改输出格式(printf和OLED显示)。
注意:原代码中使用了标准库的isdigit函数,我们还需要处理小数点。
具体修改:
1. 修改Stack.h中的栈定义:
原代码:
typedef struct
{
unsigned int num[Stack_Size];
unsigned int top;
}Stack_num;
改为:
typedef struct
{
float num[Stack_Size]; // 改为浮点数
unsigned int top;
}Stack_num;
2. 修改Stack.c中的Push_num和Pop_num函数,使其操作float类型。
3. 在Deposit函数中,解析数字的部分需要修改,以支持浮点数:
原整数解析:
if(isdigit(String[i]))
{
index=0;
j=i;
for(;isdigit(String[j])&&j< Stack_Size;j++)
{
index=index*10+(String[j]-'0');
}
Push_num(&Stack_NUM,index);
i=j-1;
}
改为浮点数解析:
if(isdigit(String[i]) || String[i]=='.') // 注意,小数点开头的情况(如.5)也要考虑,但通常我们可能要求0.5,所以这里我们假设数字至少有一位数字,或者小数点后跟数字。
{
float num = 0.0;
float fraction = 0.1;
int decimal = 0; // 标记是否遇到小数点
j = i;
// 先处理整数部分
while (isdigit(String[j]) || (String[j]=='.' && !decimal))
{
if (String[j]=='.')
{
decimal = 1;
j++;
break;
}
num = num * 10 + (String[j] - '0');
j++;
}
// 如果有小数部分
if (decimal)
{
while (isdigit(String[j]) && j < Stack_Size)
{
num += (String[j] - '0') * fraction;
fraction *= 0.1;
j++;
}
}
Push_num(&Stack_NUM, num);
i = j - 1;
}
但是注意:上面的解析逻辑在遇到连续两个小数点时会出错。我们可以改进为:
if(isdigit(String[i]) || String[i]=='.')
{
float num = 0.0;
float base = 1.0;
int decimal = 0; // 0表示整数部分,1表示小数部分
j = i;
// 先处理整数部分(如果有)
while (j < Stack_Size && (isdigit(String[j]) || String[j]=='.'))
{
if (String[j]=='.')
{
if (decimal) break; // 已经遇到小数点了,再次遇到则退出(错误情况,但这里简单处理为退出)
decimal = 1;
j++;
continue;
}
if (!decimal)
{
num = num * 10 + (String[j] - '0');
}
else
{
num += (String[j] - '0') * base;
base *= 0.1;
}
j++;
}
Push_num(&Stack_NUM, num);
i = j - 1;
}
但是,上面的代码不能处理没有整数部分的小数(如.5)。为了支持这种情况,我们可以:
if(isdigit(String[i]) || String[i]=='.')
{
float num = 0.0;
float base = 1.0;
int decimal = 0;
j = i;
// 先检查第一个字符是否是小数点
if (String[j]=='.')
{
decimal = 1;
j++;
}
// 整数部分
while (j < Stack_Size && isdigit(String[j]))
{
num = num * 10 + (String[j] - '0');
j++;
}
// 如果接下来是小数点,且之前没有遇到小数点,则开始小数部分
if (String[j]=='.' && !decimal)
{
decimal = 1;
j++;
}
// 小数部分
if (decimal)
{
float fraction = 0.1;
while (j < Stack_Size && isdigit(String[j]))
{
num += (String[j] - '0') * fraction;
fraction *= 0.1;
j++;
}
}
Push_num(&Stack_NUM, num);
i = j - 1;
}
但是,这样写比较复杂,而且可能不能处理多个小数点的情况。我们采用一个更通用的方法:先读取整个数字字符串(包括小数点),然后用atof或者自己解析。
由于我们是在嵌入式系统中,可能不想用atof(因为可能占用空间大),我们可以自己解析。
这里我们采用一个简单的方法:先计算整数部分,然后如果有小数点,再计算小数部分。
修改后的解析代码:
if (isdigit(String[i]) || String[i] == '.')
{
char num_str[32]; // 临时存储数字字符串,假设数字长度不超过31
int k = 0;
j = i;
// 收集连续的数字和小数点
while (j < Stack_Size && (isdigit(String[j]) || String[j] == '.'))
{
// 如果遇到第二个小数点,则停止
if (String[j] == '.' && k > 0 && num_str[k-1] == '.')
break;
num_str[k++] = String[j++];
}
num_str[k] = '\0'; // 字符串结束
// 转换为浮点数
float num = 0.0;
int decimal_part = 0;
float decimal_multiplier = 0.1;
int has_decimal = 0;
for (int m = 0; m < k; m++)
{
if (num_str[m] == '.')
{
has_decimal = 1;
decimal_part = 1;
continue;
}
if (!decimal_part)
{
num = num * 10 + (num_str[m] - '0');
}
else
{
num += (num_str[m] - '0') * decimal_multiplier;
decimal_multiplier *= 0.1;
}
}
Push_num(&Stack_NUM, num);
i = j - 1;
}
但是,这个方法需要额外的字符数组,并且循环次数较多。考虑到嵌入式系统的资源,我们可以采用之前的分步解析,但改进以支持无整数部分的小数。
这里我们采用一个更高效的方法:
if (isdigit(String[i]) || String[i] == '.')
{
float num = 0.0;
float divisor = 1.0; // 用于小数部分的除数
int decimal_found = 0; // 是否遇到小数点
j = i;
// 处理整数部分(如果有)
if (isdigit(String[j]))
{
num = String[j] - '0';
j++;
while (isdigit(String[j]))
{
num = num * 10 + (String[j] - '0');
j++;
}
}
// 检查小数点
if (String[j] == '.')
{
decimal_found = 1;
j++;
}
// 处理小数部分
if (decimal_found)
{
divisor = 10.0;
while (isdigit(String[j]))
{
num += (String[j] - '0') / divisor;
divisor *= 10.0;
j++;
}
}
// 还有一种情况:一开始就是小数点,那么整数部分为0,然后处理小数部分
if (String[i] == '.' && !isdigit(String[i]))
{
num = 0.0;
j = i + 1; // 跳过小数点
divisor = 10.0;
while (isdigit(String[j]))
{
num += (String[j] - '0') / divisor;
divisor *= 10.0;
j++;
}
}
Push_num(&Stack_NUM, num);
i = j - 1;
}
但是,上面的代码在遇到第一个字符是小数点时,会进入第一个if吗?不会,因为第一个if的条件是:isdigit(String[i])为假,但String[i]=='.'为真,所以进入。
然后,第一个isdigit(String[j])(此时j=i)为假,所以整数部分跳过。然后遇到小数点(String[j]=='.'),设置decimal_found,然后j++,然后处理小数部分。
但是,此时如果小数点后面没有数字,那么小数部分循环不会执行,num还是0。这样,我们就把单独的小数点解析为0,这可能是错误的。所以,我们需要避免这种情况。
我们可以这样:如果遇到小数点,但后面没有数字,那么我们就认为这个小数点无效,不将其作为数字的一部分?但这样会破坏表达式。
实际上,在表达式中,单独的小数点是非法的。我们可以在解析时要求小数点后面至少有一个数字。
为了简单,我们假设输入是合法的。在非法输入时,程序可能会出错。
4. 修改Eval函数中的运算部分,使用浮点数。注意,除法现在要使用浮点除法,而且除数不能为0的检查仍然需要。
原代码:
switch(cha)
{
case '*' : x=a*b;break;
case '/' :
{
if(b==0) {printf("除数不能为0");x=0;}
else {x=a/b;}
break;
}
case '+' : {x=a+b;break;}
case '-' : {x=a-b;break;}
default :break;
}
改为:
switch(cha)
{
case '*' : x = a * b; break;
case '/' :
{
if (b == 0) { printf("除数不能为0"); x = 0; }
else { x = a / b; }
break;
}
case '+' : x = a + b; break;
case '-' : x = a - b; break;
default : break;
}
5. 修改主函数中的Result类型为float,并修改输出:
原代码:
printf("结果=%d",Result);
OLED_ShowNum(1,1,Result,4);
改为:
printf("结果=%.2f",Result); // 保留两位小数
// OLED显示浮点数可能需要自己实现,因为原OLED_ShowNum可能只支持整数
// 我们可以添加一个显示浮点数的函数,或者将浮点数转换为字符串显示
由于原OLED_ShowNum只支持整数,我们需要修改显示部分。我们可以使用sprintf将浮点数格式化为字符串,然后用OLED_ShowString显示。
例如:
char buf[20];
sprintf(buf, "%.2f", Result); // 保留两位小数
OLED_ShowString(1, 1, buf);
6. 另外,注意在串口接收中断中,我们接收的是字符,包括小数点,所以不需要修改。
7. 修改Init函数,将栈的top置0,这个不需要改。
8. 修改Pop_num和Push_num函数,使其操作float类型。
由于修改较多,我们需要确保所有使用到Stack_num的地方都改为float。
但是,注意题目要求不改变原变量名,所以我们只改变类型,变量名不变。
由于原代码中,栈操作函数都是通过指针操作栈结构体的,所以修改结构体成员类型后,函数内部也要修改。
例如,原来的:
uint8_t Push_num(Stack_num *stack,unsigned int NUM)
{
if(stack->top>=Stack_Size)
{
return 0;
}
stack->top++;
stack->num[stack->top]=NUM;
return 1;
}
改为:
uint8_t Push_num(Stack_num *stack, float NUM)
{
if(stack->top>=Stack_Size)
{
return 0;
}
stack->top++;
stack->num[stack->top] = NUM;
return 1;
}
同样,Pop_num也要修改:
uint8_t Pop_num(Stack_num *stack, float *n)
{
if(stack->top<=0)
{
return 0;
}
*n = stack->num[stack->top];
stack->top--;
return 1;
}
9. 在Deposit函数中,变量a,x,b的类型也要改为float。
10. 注意,在表达式解析中,index变量原来是整数,现在改为float。
11. 由于浮点数有精度问题,我们需要注意比较时不要直接比较相等,但这里我们只做简单处理。
考虑到代码改动较大,我们逐步修改。
但是,由于原代码中使用了大量的unsigned int,我们需要将所有涉及操作数栈的地方改为float。同时,注意在计算过程中,都是浮点数运算。
由于原代码中Priority函数等不受影响,所以不需要修改。
总结修改步骤:
1. 修改Stack.h中的Stack_num结构体,将num数组改为float类型。
2. 修改Stack.c中Push_num和Pop_num的参数类型为float。
3. 修改Deposit函数中解析数字的部分,支持浮点数解析。
4. 修改Eval函数,使用float类型计算,并处理除0错误(注意浮点数除0不会导致异常,而是得到无穷大,但我们仍然可以检查并报错)。
5. 修改main函数中的Result为float类型,并修改输出为浮点数格式。
注意:浮点数输出在嵌入式系统中可能比较占用资源,特别是使用printf的浮点数格式化,这可能会增加代码量。如果资源紧张,可以考虑使用整数代替(乘以100等)或者使用简化版的浮点转字符串函数。
由于我们添加了浮点支持,需要确保编译器支持浮点数运算(通常默认支持),并且链接了相应的库。
最后,由于修改了栈的数据类型,其他使用到操作数栈的地方都要修改。目前,只有Deposit和Eval函数使用操作数栈。
下面,我们将修改后的代码列出(只列出修改的部分,因为原代码较长,我们只修改关键部分)。
注意:由于题目要求不改变原变量名,所以变量名我们都不变,只改变类型和部分逻辑。
由于代码较长,我们只给出修改后的关键函数,并省略未修改的部分。
修改Stack.h:
typedef struct
{
float num[Stack_Size]; // 改为float
unsigned int top;
}Stack_num;
修改Stack.c:
uint8_t Push_num(Stack_num *stack, float NUM) // 参数类型改为float
{
... // 函数体不变,只是赋值给float数组
}
uint8_t Pop_num(Stack_num *stack, float *n) // 改为float指针
{
... // 函数体不变
}
修改Deposit函数(在Stack.c中):
uint32_t Deposit(uint8_t *String) // 注意,这个函数的返回类型现在是float?但是原函数返回uint32_t,我们需要改为float
{
// 但是,原函数返回类型是uint32_t,我们需要改为float,因为结果可能是小数。
// 所以修改函数返回类型为float
}
但是,原函数声明在头文件中,也需要修改。
所以,我们修改Stack.h中的Deposit声明:
float Deposit(uint8_t *String);
然后在Stack.c中修改Deposit函数:
float Deposit(uint8_t *String)
{
// 将原来的index改为float类型?不需要,因为我们在解析时已经用局部变量存储了浮点数。
unsigned int i, j;
float num_val; // 用于存储解析出的浮点数
// 删除原来的index,因为现在解析的是浮点数
... // 其他变量定义
// 修改解析数字的代码段,使用上面讨论的解析方法(这里采用第二种方法,分整数和小数部分)
// 具体实现我们采用支持无整数部分的方法:
if (isdigit(String[i]) || String[i] == '.')
{
num_val = 0.0;
int decimal_found = 0;
float decimal_divisor = 10.0; // 小数部分的除数
j = i;
// 如果第一个字符是小数点,则整数部分为0,并标记小数部分开始
if (String[j] == '.')
{
decimal_found = 1;
j++;
}
else
{
// 解析整数部分
num_val = String[j] - '0';
j++;
while (isdigit(String[j]))
{
num_val = num_val * 10 + (String[j] - '0');
j++;
}
// 检查是否有小数点
if (String[j] == '.')
{
decimal_found = 1;
j++;
}
}
// 解析小数部分
if (decimal_found)
{
while (isdigit(String[j]))
{
num_val += (String[j] - '0') / decimal_divisor;
decimal_divisor *= 10.0;
j++;
}
}
Push_num(&Stack_NUM, num_val);
i = j - 1;
}
... // 其他部分不变
return Stack_NUM.num[Stack_NUM.top]; // 返回栈顶的浮点数
}
注意:在解析数字时,我们假设输入的数字字符串是合法的。如果遇到非法字符(如两个小数点),则解析会提前结束。
修改Eval函数:
void Eval(void)
{
float a, b, x; // 改为float
uint8_t cha;
Pop_num(&Stack_NUM, &b);
Pop_num(&Stack_NUM, &a);
Pop_char(&Stack_CHAR, &cha);
switch(cha)
{
... // 改为浮点运算
}
Push_num(&Stack_NUM, x);
}
修改main.c:
// 将Result改为float
static float Result;
// 在计算按键处理中
if(Key_GetNum1())
{
Result = Deposit(Firmula);
Count_Index=1;
}
// 在发送结果部分
if(Count_Index)
{
if(Key_GetNum2())
{
// 使用sprintf将浮点数转为字符串,然后发送和显示
char buf[20];
sprintf(buf, "%.2f", Result); // 需要包含stdio.h
printf("结果=%s", buf);
OLED_ShowString(1,1,buf); // 假设有OLED_ShowString函数,如果没有,需要实现或使用其他方式显示
// 或者,如果OLED_ShowNum不支持浮点数,我们可以显示整数部分,但这样会丢失小数。所以最好实现OLED_ShowString。
// 如果之前没有OLED_ShowString,需要实现。
Index=0;
Clear_Index=1;
Count_Index=0;
}
}
注意:sprintf会占用较多资源,特别是浮点格式化。如果资源紧张,可以自己实现一个简单的浮点数转字符串函数。
另外,需要确保在工程设置中启用了浮点数支持(在printf中输出浮点数)。
由于改动较大,需要测试整数运算和浮点数运算。
最后,由于题目要求不改变原变量名,我们只改变了类型,变量名都保持不变。
以上是修改方案。由于代码较长,这里无法完整重写,但提供了详细的修改步骤和关键代码。</think>为了在现有代码中支持小数点运算而不改变变量名,需要进行以下关键修改:
### 核心修改方案:
1. **修改栈数据类型**(Stack.h):
```c
// 原整数栈
typedef struct {
unsigned int num[Stack_Size]; // 改为 float 类型
unsigned int top;
} Stack_num;
```
2. **数字解析逻辑**(Deposit函数):
```c
if (isdigit(String[i]) || String[i] == '.') {
float num_val = 0.0;
float decimal_place = 0.1;
int decimal_found = 0;
j = i;
while (isdigit(String[j]) || String[j] == '.') {
if (String[j] == '.') {
if (decimal_found) break; // 防止多个小数点
decimal_found = 1;
j++;
continue;
}
if (!decimal_found) {
num_val = num_val * 10 + (String[j] - '0');
} else {
num_val += (String[j] - '0') * decimal_place;
decimal_place *= 0.1;
}
j++;
}
Push_num(&Stack_NUM, num_val);
i = j - 1;
}
```
3. **运算函数改造**(Eval函数):
```c
void Eval(void) {
float a, b, x; // 改为浮点类型
Pop_num(&Stack_NUM, &b);
Pop_num(&Stack_NUM, &a);
Pop_char(&Stack_CHAR, &cha);
switch(cha) {
case '*': x = a * b; break;
case '/':
if (fabs(b) < 1e-6) { // 浮点零判断
printf("除数不能为0");
x = 0;
} else {
x = a / b;
}
break;
case '+': x = a + b; break;
case '-': x = a - b; break;
}
Push_num(&Stack_NUM, x);
}
```
4. **结果输出处理**(main函数):
```c
// 修改Result类型
static float Result;
// 输出时格式化为浮点数
printf("结果=%.2f", Result);
OLED_ShowFloat(1, 1, Result, 2); // 需实现浮点显示函数
```
### 需要新增的OLED显示函数:
```c
// OLED显示浮点数(示例)
void OLED_ShowFloat(uint8_t line, uint8_t col, float num, uint8_t decimals) {
char buf[20];
sprintf(buf, "%.*f", decimals, num);
OLED_ShowString(line, col, buf);
}
```
### 关键注意事项:
1. **栈操作函数改造**:
- 修改 `Push_num()` 和 `Pop_num()` 的参数类型为 `float`
- 保留原函数名和参数名,仅修改数据类型
2. **除零处理优化**:
使用 `fabs(b) < 1e-6` 替代 `b == 0` 进行浮点零判断
3. **精度控制**:
- 运算过程保持float精度
- 显示时通过 `%.2f` 控制小数位数
4. **输入验证**:
添加小数点合法性检查(禁止连续小数点)
此方案完整保留了所有原始变量名和函数名,仅通过修改数据类型和运算逻辑实现浮点支持。需注意在工程配置中启用浮点打印支持(`-u _printf_float` 链接器选项)。
阅读全文
相关推荐















