C语言程序bug:atof()截断末尾字符,长输入运算结果错误
问题分析与修复方案
核心错误原因
问题根源在于局部数组的生命周期失效:getAndTokenize函数里的lit_in是栈上的局部变量,函数执行完毕返回时,该数组会被销毁。但你把strtok返回的指向lit_in内部的指针存在了return_struc->tokens里,后续在main中访问这些指针时,内存已被回收,行为完全不可预测,这就是数字被截断的诡异现象的本质。
修复步骤
1. 修正Token存储方式
不能直接保存strtok返回的局部数组指针,必须为每个Token单独分配内存并复制内容:
修改getAndTokenize函数中的Token存储逻辑:
// 原代码:直接保存指针 // return_struc->tokens[0] = token; // 替换为:分配内存并复制内容 return_struc->tokens[0] = malloc(strlen(token) + 1); strcpy(return_struc->tokens[0], token); // 循环内同理修改: // 原代码:return_struc->tokens[i] = token; // 替换为: return_struc->tokens[i] = malloc(strlen(token) + 1); strcpy(return_struc->tokens[i], token);
2. 调整结构体内存分配
原代码仅为结构体分配了基础空间,未给指针数组预留足够空间。需要按指针大小计算分配:
// 原代码:t_return *return_struc = malloc(sizeof(t_return) + MAX); // 替换为:为MAX个char*指针预留空间 t_return *return_struc = malloc(sizeof(t_return) + MAX * sizeof(char*));
3. 添加内存释放逻辑(避免泄漏)
在main函数使用完Token后,需释放每个Token的内存和结构体本身:
// 在main末尾添加 for (int j = 0; j < tokens->arrayMembers; j++) { free(tokens->tokens[j]); } free(tokens);
4. 处理输入换行符(可选优化)
fgets会读取输入末尾的换行符,可能导致最后一个Token带换行,手动去除可避免潜在问题:
// 在fgets读取后添加 input[strcspn(input, "\n")] = '\0';
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #define MAX 1024 typedef struct tokenReturn { int arrayMembers; char* tokens[]; } t_return; t_return *getAndTokenize(char* delim) { char* input = malloc(MAX); char lit_in[MAX]; if (fgets(input, MAX, stdin) == NULL) { perror("Error: "); exit(EXIT_FAILURE); } // 去除输入末尾的换行符 input[strcspn(input, "\n")] = '\0'; strncpy(lit_in, input, MAX); free(input); // 为结构体和指针数组分配足够空间 t_return *return_struc = malloc(sizeof(t_return) + MAX * sizeof(char*)); if (return_struc == NULL) { puts("Allocation error"); perror("Error"); exit(EXIT_FAILURE); } char *token = strtok(lit_in, delim); // 为第一个Token分配内存并复制 return_struc->tokens[0] = malloc(strlen(token) + 1); strcpy(return_struc->tokens[0], token); int i = 1; while (true) { if((token = strtok(NULL, delim)) == NULL) { break; } // 为每个Token分配内存并复制 return_struc->tokens[i] = malloc(strlen(token) + 1); strcpy(return_struc->tokens[i], token); i++; } return_struc->arrayMembers = i; return return_struc; } float sum(float x, float y) { return x + y; } float multiply(float x, float y) { return x * y; } float subs(float x, float y) { return x - y; } float division(float x, float y) { return x / y; } int main(void) { printf("Operation: "); t_return* tokens = getAndTokenize(" "); // 校验输入格式是否正确 if (tokens->arrayMembers != 3) { puts("Invalid input format! Use: number operator number"); // 提前释放内存 for (int j = 0; j < tokens->arrayMembers; j++) { free(tokens->tokens[j]); } free(tokens); exit(EXIT_FAILURE); } float a = atof(tokens->tokens[0]); char symbol = tokens->tokens[1][0]; float b = atof(tokens->tokens[2]); float result; switch (symbol) { case '+': result = sum(a, b); break; case '-': result = subs(a, b); break; case '/': result = division(a, b); break; case '*': result = multiply(a, b); break; default: puts("Operation not recognized!"); // 释放内存 for (int j = 0; j < tokens->arrayMembers; j++) { free(tokens->tokens[j]); } free(tokens); exit(EXIT_FAILURE); } printf("Result is: %.3lf\n", result); // 释放所有分配的内存 for (int j = 0; j < tokens->arrayMembers; j++) { free(tokens->tokens[j]); } free(tokens); exit(EXIT_SUCCESS); }
内容的提问来源于stack exchange,提问作者strreetfighter2
相关产品推荐
相关产品推荐

