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

C语言实现:如何将CSV文件数字按首数字奇偶分至两个集合?

问题分析与修正方案

你的代码存在几个关键问题,导致无法按首数字奇偶性完成分类:

  1. 首数字判断逻辑完全错误:你用geo[0].latitud%2==0判断的是整个数值的奇偶,还错误引用了第一个元素geo[0]而非当前元素geo[i],完全没处理首数字的提取逻辑。
  2. 赋值方向颠倒:geo[i].latitud=conjunto1[i];是把集合的值覆盖到结构体里,反过来才对——应该把结构体中的数值存入集合。
  3. CSV字段读取错误:读取经度时用了sscanf(temp,"%f",&geo[i].longitud);,但strtok分割后应该用strtok(NULL,coma)的结果来读取,而非原字符串temp。
  4. 行数统计的feof陷阱:while(!feof(pFich))会导致多统计一行(因为最后一次fgets失败后feof才触发)。
  5. 内存检查位置错误:if(geo==NULL)的判断应该放在malloc之后,而不是循环内部。
  6. 打印格式错误:printf ("f",conjunto1[i]);缺少百分号,格式完全不正确。

修正后的代码

核心思路是从字符串层面提取首数字(避免浮点数取整的精度误差):跳过正负号,找到第一个数字字符,转成整数后判断奇偶,再分别存入两个集合,同时用独立计数器跟踪两个集合的元素数量。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// 假设你的tGeolocalizacion结构体定义如下
typedef struct {
    float latitud;
    float longitud;
} tGeolocalizacion;

void lectura() {
    float conjunto_par[1000], conjunto_impar[1000];
    int cnt_par = 0, cnt_impar = 0; // 两个集合的元素计数器
    char temp[1000];
    int cont = 0, i;
    char *numero;
    tGeolocalizacion *geo;
    const char *coma = ";"; // 改成const char*更规范
    
    char archivo[] = "fichnum.csv";
    FILE *pFich = fopen(archivo, "r");
    if (pFich == NULL) {
        printf("无法打开文件,错误!\n");
        exit(1);
    }

    // 修正:统计有效行数,避免feof陷阱
    while (fgets(temp, 1000, pFich) != NULL) {
        // 跳过空行(可选)
        if (strlen(temp) <= 1) continue;
        cont++;
    }

    rewind(pFich);

    // 分配内存并立即检查
    geo = malloc(cont * sizeof(tGeolocalizacion));
    if (geo == NULL) {
        printf("内存分配失败,错误!\n");
        fclose(pFich); // 记得关闭文件再退出
        exit(1);
    }

    for (i = 0; i < cont; i++) {
        fgets(temp, 1000, pFich);
        // 跳过空行(对应统计时的处理)
        if (strlen(temp) <= 1) {
            i--;
            continue;
        }

        // 正确读取CSV的两个字段
        numero = strtok(temp, coma);
        if (numero == NULL) break; // 处理格式错误的行
        sscanf(numero, "%f", &geo[i].latitud);

        numero = strtok(NULL, coma);
        if (numero == NULL) break;
        sscanf(numero, "%f", &geo[i].longitud);

        // 提取首数字并判断奇偶
        char *ptr = numero; // 若要按纬度首数字分类,替换成读取纬度的numero即可
        // 跳过正负号
        while (*ptr == '+' || *ptr == '-') {
            ptr++;
        }
        // 找到第一个数字字符
        while (*ptr != '\0' && !isdigit((unsigned char)*ptr)) {
            ptr++;
        }
        if (isdigit((unsigned char)*ptr)) {
            int primer_digito = *ptr - '0'; // 字符转数字
            if (primer_digito % 2 == 0) {
                conjunto_par[cnt_par++] = geo[i].latitud; // 存入偶首数集合
            } else {
                conjunto_impar[cnt_impar++] = geo[i].latitud; // 存入奇首数集合
            }
        }
    }

    // 打印结果
    printf("首数字为偶数的集合:\n");
    for (i = 0; i < cnt_par; i++) {
        printf("%.2f ", conjunto_par[i]);
    }
    printf("\n首数字为奇数的集合:\n");
    for (i = 0; i < cnt_impar; i++) {
        printf("%.2f ", conjunto_impar[i]);
    }
    printf("\n文件读取完成\n");

    // 释放资源
    free(geo);
    fclose(pFich);
}

int main() {
    lectura();
    return 0;
}

关键修改说明

  • 首数字提取:通过字符串遍历跳过正负号和非数字字符,直接取第一个数字字符转成整数,避免了浮点数取整时的精度问题(比如123.45取整是123,但首数字是1)。
  • 集合计数器:用cnt_par和cnt_impar分别跟踪两个集合的元素数量,避免原代码中用数组索引导致的空位问题。
  • 错误处理:增加了对strtok返回NULL的判断,处理格式错误的CSV行;内存分配后立即检查;退出前关闭文件避免资源泄漏。
  • 行数统计修正:用fgets != NULL代替!feof,避免多统计一行的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 05:25:13