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

如何在C语言中读取文本文件中的复数矩阵?

C语言读取复数矩阵文件的问题

问题描述

文本文件中的复数格式为(%le%+lej),测试矩阵内容如下:

(0.000000000000000000e+00+0.000000000000000000e+00j)  (0.000000000000000000e+00+1.000000000000000056e-01j)  (0.000000000000000000e+00+2.000000000000000111e-01j)  (0.000000000000000000e+00+3.000000000000000444e-01j)
 (1.100000000000000089e+00+0.000000000000000000e+00j)  (1.100000000000000089e+00+1.000000000000000056e-01j)  (1.100000000000000089e+00+2.000000000000000111e-01j)  (1.100000000000000089e+00+3.000000000000000444e-01j)
 (2.200000000000000178e+00+0.000000000000000000e+00j)  (2.200000000000000178e+00+1.000000000000000056e-01j)  (2.200000000000000178e+00+2.000000000000000111e-01j)  (2.200000000000000178e+00+3.000000000000000444e-01j)

我已花费两天时间尝试读取该矩阵,需要一个简单且易于调试的解决方案。

我的尝试代码

#include <stdio.h>
#include <stdlib.h>
#include <complex.h>

int main(void)
{
    char fname[] = "test_matrix.dat";
    int m = 3;
    int n = 4;
    complex double * matrix = calloc(m * n, sizeof(complex double));
    FILE * ifile = fopen(fname, "r");
    int i, j, info;
    double zreal, zimag;
    for(i = 0; i < m; i++)
    {
        for(j = 0; j < n; j++)
        {
            info = fscanf(ifile, "(%le%lej)", &zreal, &zimag);
            // 以下写法也无效
            // info = fscanf(ifile, "(%le", &zreal);
            // info += fscanf(ifile, "%lej)", &zimag);
            if(info != 2)
            {
                fclose(ifile);
                fprintf(stderr, "Wrong input format, info = %d\n", info);
                exit(EXIT_FAILURE);
            }
            *(matrix + i + j*m) = zreal + I*zimag;
            // printf("%d ", info); 输出全为0
            printf("%6.1e%+7.1ej ", zreal, zimag);
        }
        printf("\n");
    }
    fclose(ifile);
    free(matrix);
    return(0);
}

我还尝试过用fgetc循环定位到(后再执行fscanf,但该方法逻辑复杂,调试困难,至今未成功。

补充:采用列主序是为了后续对接BLAS/LAPACK库,与当前问题无关。

解决方案

1. 修正fscanf格式字符串

原代码的核心问题是格式字符串不匹配:

  • 复数虚部前有+号,格式字符串需要包含%+le来匹配带符号的虚部数值
  • 每个复数前存在空格,格式字符串开头加空格可让fscanf自动跳过所有空白字符(空格、换行、制表符等)

修正后的读取语句:

info = fscanf(ifile, " (%le%+lej)", &zreal, &zimag);

完整修正代码:

#include <stdio.h>
#include <stdlib.h>
#include <complex.h>

int main(void)
{
    char fname[] = "test_matrix.dat";
    int m = 3;
    int n = 4;
    complex double * matrix = calloc(m * n, sizeof(complex double));
    if (!matrix) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }
    FILE * ifile = fopen(fname, "r");
    if (!ifile) {
        fprintf(stderr, "Failed to open file\n");
        free(matrix);
        exit(EXIT_FAILURE);
    }
    int i, j, info;
    double zreal, zimag;
    for(i = 0; i < m; i++)
    {
        for(j = 0; j < n; j++)
        {
            // 修正格式字符串:开头空格跳过空白,%+le匹配带符号的虚部
            info = fscanf(ifile, " (%le%+lej)", &zreal, &zimag);
            if(info != 2)
            {
                fprintf(stderr, "Wrong input format at row %d, column %d, info = %d\n", i+1, j+1, info);
                fclose(ifile);
                free(matrix);
                exit(EXIT_FAILURE);
            }
            *(matrix + i + j*m) = zreal + I*zimag;
            printf("%6.1e%+7.1ej ", zreal, zimag);
        }
        printf("\n");
    }
    fclose(ifile);
    free(matrix);
    return(0);
}

2. 逐行读取+sscanf(更易调试)

如果需要更方便调试,可以先逐行读取文件内容到缓冲区,再用sscanf解析每行的复数。这种方式可以直观查看每行的输入内容,便于定位格式错误。

示例代码:

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

#define BUFFER_SIZE 1024

int main(void)
{
    char fname[] = "test_matrix.dat";
    int m = 3;
    int n = 4;
    complex double * matrix = calloc(m * n, sizeof(complex double));
    if (!matrix) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }
    FILE * ifile = fopen(fname, "r");
    if (!ifile) {
        fprintf(stderr, "Failed to open file\n");
        free(matrix);
        exit(EXIT_FAILURE);
    }

    char buffer[BUFFER_SIZE];
    int i, j;
    double zreal, zimag;
    for(i = 0; i < m; i++)
    {
        // 读取整行到缓冲区
        if (!fgets(buffer, BUFFER_SIZE, ifile)) {
            fprintf(stderr, "Failed to read row %d\n", i+1);
            fclose(ifile);
            free(matrix);
            exit(EXIT_FAILURE);
        }
        // 移除换行符(如果存在)
        buffer[strcspn(buffer, "\n")] = '\0';
        
        char *ptr = buffer;
        int read_count = 0;
        for(j = 0; j < n; j++)
        {
            // 从当前指针位置解析复数
            int info = sscanf(ptr, " (%le%+lej)%n", &zreal, &zimag, &read_count);
            if(info != 2)
            {
                fprintf(stderr, "Wrong input format at row %d, column %d\n", i+1, j+1);
                fprintf(stderr, "Current line content: %s\n", buffer);
                fclose(ifile);
                free(matrix);
                exit(EXIT_FAILURE);
            }
            *(matrix + i + j*m) = zreal + I*zimag;
            printf("%6.1e%+7.1ej ", zreal, zimag);
            // 移动指针到下一个复数的起始位置
            ptr += read_count;
        }
        printf("\n");
    }

    fclose(ifile);
    free(matrix);
    return(0);
}

该方案的优势:

  • 可以直接打印出错行的内容,快速定位格式问题
  • 不受跨换行的空白字符影响,解析逻辑更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 14:20:42