You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言如何从字符串提取多个double值存入动态double数组

核心问题

你之前提取double值始终拿到第一个数,本质是没有正确使用strtod的第二个参数记录解析结束位置,每次都从字符串头部开始解析,自然永远得到第一个浮点数。另外原代码还有几个隐藏bug:ifEnd判断没有做边界检查,输入字符数不足3个时访问index-2、index-3会触发内存越界;getchar()返回值是int类型,直接存入char变量会导致EOF判断失效;用字符串遍历索引当double数组下标,两者长度不对应,必然会出现数组越界或者值重复的问题。

实现思路
  • 读取输入时用int类型变量存储getchar()返回值,避免EOF判断错误,终止符判断加边界检查,不要访问负索引。
  • 提取浮点数时不需要手动逐字符遍历字符串挪位置,直接用strtod的第二个输出参数记录当前解析到的位置:每次解析完一个double,就把当前字符串指针移到解析结束的位置,跳过所有无关字符,直到遇到字符串结束符。
  • 单独维护double数组的元素计数,不要和字符串的索引混用,动态扩容时基于实际存入的元素个数判断。
可直接运行的修正代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>

// 修正终止符判断,避免数组越界
bool ifEnd(const char* userString, size_t len) {
    if (len >= 3 && strncmp(userString + len - 3, "END", 3) == 0) return true;
    if (len >= 4 && strncmp(userString + len - 4, "QUIT", 4) == 0) return true;
    return false;
}

int main()
{   
    size_t str_buf_size = 10;
    size_t str_len = 0;
    char* input_str = malloc(str_buf_size * sizeof(char));
    if (!input_str) {
        printf("内存分配失败,程序退出\n");
        return EXIT_FAILURE;
    }

    int ch;
    // 读取所有输入直到EOF或输入END
    while ((ch = getchar()) != EOF) {
        ch = toupper(ch);
        // 输入字符串动态扩容
        if (str_len == str_buf_size - 1) {
            str_buf_size *= 2;
            char* tmp = realloc(input_str, str_buf_size * sizeof(char));
            if (!tmp) {
                printf("内存不足,程序退出\n");
                free(input_str);
                return EXIT_FAILURE;
            }
            input_str = tmp;
        }
        input_str[str_len++] = (char)ch;
        // 换行符替换为空格方便后续解析
        if (input_str[str_len - 1] == '\n') input_str[str_len - 1] = ' ';
        // 判断是否输入了终止符
        if (ifEnd(input_str, str_len)) {
            // 截掉末尾的END标记
            str_len -= 3;
            break;
        }
    }
    input_str[str_len] = '\0';

    // 从输入字符串中提取所有double值
    size_t dbl_buf_size = 10;
    size_t dbl_count = 0;
    double* dbl_arr = malloc(dbl_buf_size * sizeof(double));
    if (!dbl_arr) {
        printf("内存分配失败,程序退出\n");
        free(input_str);
        return EXIT_FAILURE;
    }

    char* cur_pos = input_str;
    char* end_pos = NULL;
    while (*cur_pos != '\0') {
        // 跳过当前位置所有和浮点数无关的字符
        while (*cur_pos != '\0' && *cur_pos != '.' && *cur_pos != '-' && *cur_pos != '+' && !isdigit((unsigned char)*cur_pos)) {
            cur_pos++;
        }
        if (*cur_pos == '\0') break;

        // 解析当前位置的浮点数
        double val = strtod(cur_pos, &end_pos);
        // 过滤无效解析,比如单独的+、-、.不能算有效浮点数
        if (end_pos == cur_pos) {
            cur_pos++;
            continue;
        }

        // double数组动态扩容
        if (dbl_count == dbl_buf_size) {
            dbl_buf_size *= 2;
            double* tmp = realloc(dbl_arr, dbl_buf_size * sizeof(double));
            if (!tmp) {
                printf("内存不足,程序退出\n");
                free(input_str);
                free(dbl_arr);
                return EXIT_FAILURE;
            }
            dbl_arr = tmp;
        }
        dbl_arr[dbl_count++] = val;
        // 将当前解析位置移到本次解析结束的位置,准备下一轮提取
        cur_pos = end_pos;
    }

    // 以下是测试逻辑,可自行替换为后续业务逻辑
    printf("共提取到%zu个double类型数值:\n", dbl_count);
    for (size_t i = 0; i < dbl_count; i++) {
        printf("%lf ", dbl_arr[i]);
    }
    printf("\n");

    free(input_str);
    free(dbl_arr);
    return EXIT_SUCCESS;
}
关键注意点
  • strtod的第二个参数是输出参数,函数执行完成后会把「第一个无法解析为浮点数的字符地址」写入该指针,只要每次从这个地址继续向后查找下一个合法浮点数即可,不需要手动维护遍历索引。
  • 不要把getchar()的返回值直接存入char类型变量:EOF的值为-1,如果当前环境的char是无符号类型,将永远无法匹配到EOF。
  • 判断字符串前后缀直接用strncmp实现,不要手动写索引遍历,很容易出现越界问题。
  • 每次调用strtod后要校验返回的结束指针是否和传入的起始指针相等,如果相等说明当前位置没有合法浮点数,需要跳过当前字符继续向后查找。

内容的提问来源于stack exchange,提问作者SarcasticLeo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 17:09:14