Как читать воображаемые данные из текстового файла с помощью C

Я не могу прочитать воображаемые данные из текстового файла. Вот мой .txt файл

abc.txt

0.2e-3+0.3*I   0.1+0.1*I
0.3+0.1*I      0.1+0.4*I

Я хочу прочитать эти данные в матрицу и распечатать ее.

Я нашел решения с помощью C++ здесь и здесь. Я не знаю, как сделать то же самое в C.

Я могу читать десятичные и целые данные в .txt и печатать их. Я также могу распечатать воображаемые данные, инициализированные при объявлении, используя заголовок complex.h. Это программа, которую я написал

#include<stdio.h>
#include<stdlib.h>
#include<complex.h>
#include<math.h>
int M,N,i,j,k,l,p,q;
int b[2];
int main(void)
{
    FILE* ptr = fopen("abc.txt", "r");
        if (ptr == NULL) {
            printf("no such file.");
            return 0;
        }
    long double d=0.2e-3+0.3*I;
    long double c=0.0000000600415046630252;
    double matrixA[2][2];
    for(i=0;i<2; i++)
        for(j=0;j<2; j++)
            fscanf(ptr,"%lf+i%lf\n", creal(&matrixA[i][j]), cimag(&matrixA[i][j])); 
            //fscanf(ptr, "%lf", &matrixA[i][j]) for reading non-imainary data, It worked. 

    for(i=0;i<2; i++)
            for(j=0;j<2; j++)
                printf("%f+i%f\n", creal(matrixA[i][j]), cimag(matrixA[i][j]));
              //printf("%lf\n", matrixA[i][j]);  for printing non-imainary data, It worked. 

    printf("%f+i%f\n", creal(d), cimag(d));
    printf("%Lg\n",c);

    fclose(ptr);

    return 0;
}

Но я хочу прочитать это из текста, потому что у меня есть массив большего размера, который я не могу инициализировать при объявлении из-за его размера.

Вы должны быть более конкретными, чем «не знаю, как». Пожалуйста, покажите, что вы пробовали, в качестве минимального воспроизводимого примера и опишите, на каком конкретном этапе вы застряли.

kaylum 10.11.2022 07:12
fscanf, вероятно, первая функция, которую нужно попробовать, чтобы найти решение.
Joël Hecht 10.11.2022 07:31

Вы печатаете пробелы вокруг знака +, которых нет во входном формате. Нужно ли нам справляться с вашим форматом вывода, а также с форматом ввода? И, вероятно, у вас может быть -1.2-3.6*I- вместо +)? Обеспечение присутствия и чтения *I создает некоторые проблемы, но они не являются непреодолимыми. Что вы пробовали, и где вы столкнулись с проблемами?

Jonathan Leffler 10.11.2022 07:42

Я поместил минимальный воспроизводимый код примера, который я использовал. Согласно заявлению + или -, войдите в printf заявление. Я использовал только символ +. Я не проверял значения знака -. Я проверю и дам вам знать.

Palguna Gopireddy 10.11.2022 13:18

Ваш код не проверяет возвращаемое значение из fscanf(), поэтому вы понятия не имеете, что сработало. Ваш формат содержит %lf+i%lf, который не имеет отношения к примерам ввода, таким как 0.2e-3+0.3*I,

Jonathan Leffler 10.11.2022 20:48

Обратите внимание эффект завершающего пробела в строке формата scanf()

Jonathan Leffler 10.11.2022 20:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
104
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Есть две основные проблемы с вашим кодом:

  • Вам нужно добавить complex к переменным, которые содержат комплексные значения.
  • scanf() нужны указатели на объекты для хранения в них отсканированных значений. Но creal() возвращает значение, скопированное из содержимого его аргумента. Это не указатель, и вы не можете получить адрес соответствующей части сложного аргумента.

Поэтому вам необходимо предоставить временные объекты scanf(), которые получают отсканированные значения. После успешного сканирования эти значения объединяются в комплексное значение и присваиваются индексированной ячейке матрицы.

Незначительные проблемы, не влияющие на основную проблему:

  • Данный источник «дополнен» ненужными #includes, неиспользуемыми переменными, глобальными переменными и экспериментами с константами. Я удалил их все, чтобы увидеть реальную вещь.

  • Спецификатор "%f" (как и многие другие) позволяет scanf() пропускать пробелы, такие как пробелы, табуляции, символы новой строки и т. д. Предоставление "\n" в основном приносит больше вреда, чем можно было бы ожидать.

    Я сохранил "*I", чтобы проверить правильный формат. Однако ошибка будет обнаружена только при следующем вызове scanf(), когда он не сможет отсканировать следующий номер.

  • Вам нужно всегда проверять возвращаемое значение scanf()! Возвращает количество успешных конверсий.

  • Это обычная и хорошая привычка позволять компилятору вычислять количество элементов в массиве. Разделите общий размер на размер элемента.

    О, и sizeof — это оператор, а не функция.

  • Также лучше всего возвращать вызывающей стороне символические значения вместо магических чисел. К счастью, стандартная библиотека определяет эти EXIT_... макросы.

  • Знаки уже правильно обрабатываются scanf(). Нет нужды рассказывать об этом больше. Но для хорошего вывода с помощью printf() вы используете "+" в качестве флага, чтобы всегда выводить знак.

  • Поскольку знак теперь стоит непосредственно перед числом, я переместил умножение на I (вы можете изменить его на нижний регистр, если хотите) в конец мнимой части. Это также соответствует формату ввода.

  • Вывод ошибки осуществляется через stderr вместо stdout. Например, это позволяет перенаправить стандартный вывод в канал или файл, не пропуская возможные ошибки. Вы также можете перенаправить ошибки в другое место. И это хорошо известный и ценимый стандарт.

Это возможное решение:

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

int main(void)
{
    FILE* ptr = fopen("abc.txt", "r");
    if (ptr == NULL) {
        perror("\"abc.txt\"");
        return EXIT_FAILURE;
    }

    double complex matrixA[2][2];

    for (size_t i = 0; i < sizeof matrixA / sizeof matrixA[0]; i++)
        for (size_t j = 0; j < sizeof matrixA[0] / sizeof matrixA[0][0]; j++) {
            double real;
            double imag;
            if (fscanf(ptr, "%lf%lf*I", &real, &imag) != 2) {
                fclose(ptr);
                fprintf(stderr, "Wrong input format\n");
                return EXIT_FAILURE;
            }
            matrixA[i][j] = real + imag * I;
        }

    fclose(ptr);

    for (size_t i = 0; i < sizeof matrixA / sizeof matrixA[0]; i++)
        for (size_t j = 0; j < sizeof matrixA[0] / sizeof matrixA[0][0]; j++)
            printf("%+f%+f*I\n", creal(matrixA[i][j]), cimag(matrixA[i][j]));
    return EXIT_SUCCESS;
}

Спасибо @the-busybuy. Это хорошо работает даже при использовании маленького i вместо I. Единственное место, где нам нужно использовать I, — это цикл for. matrixA[i][j] = real + imag * I;. В противном случае он дает неверный формат ввода. Большое спасибо.

Palguna Gopireddy 11.11.2022 06:29

Ну, у вас есть это в вашем примере ввода. ;-)

the busybee 11.11.2022 07:36

Вот простое решение с использованием scanf() и формата, показанного в примерах. Он записывает значения в том же формате, в котором считывает их — вывод может сканироваться программой как ввод.

/* SO 7438-4793 */
#include <stdio.h>

static int read_complex(FILE *fp, double *r, double *i)
{
    int offset = 0;
    char sign[2];
    if (fscanf(fp, "%lg%[-+]%lg*%*[iI]%n", r, sign, i, &offset) != 3 || offset == 0)
        return EOF;
    if (sign[0] == '-')
        *i = -*i;
    return 0;
}

int main(void)
{
    double r;
    double i;

    while (read_complex(stdin, &r, &i) == 0)
        printf("%g%+g*I\n", r, i);

    return 0;
}

Пример ввода:

0.2e-3+0.3*I   0.1+0.1*I
0.3+0.1*I      0.1+0.4*I
-1.2-3.6*I     -6.02214076e23-6.62607015E-34*I

Выход из примера ввода:

0.0002+0.3*I
0.1+0.1*I
0.3+0.1*I
0.1+0.4*I
-1.2-3.6*I
-6.02214e+23-6.62607e-34*I

Числа в конце с большими показателями - это число Авогадро и постоянная Планка.

Формат примерно такой же строгий, что вы можете сделать его с помощью scanf(), но, хотя он требует знака (+ или -) между реальной и мнимой частями и требует, чтобы * и I были сразу после мнимой части (и преобразование будет терпит неудачу, если *I отсутствует), и принимает либо i, либо I для обозначения мнимого значения:

  • Это не останавливает мнимое число, имеющее второй знак (поэтому оно будет читать значение, такое как «-6+-4*I»).
  • Это не останавливает наличие пробела после обязательного знака (поэтому он будет читать такое значение, как «-6+ 24*I».
  • Это не мешает тому, чтобы реальная часть находилась в одной строке, а мнимая — в следующей.
  • Он не будет правильно обрабатывать ни чисто вещественные числа, ни чисто мнимые числа.

Функции scanf() очень гибки в отношении пробелов, и очень сложно запретить им принимать пробелы. Для предотвращения нежелательных пробелов потребуется собственный синтаксический анализатор. Вы можете сделать это, прочитав числа и маркеры отдельно, как строки, а затем проверив, что нет места и так далее. Это может быть лучшим способом справиться с этим. Вы должны использовать sscanf() для преобразования прочитанной строки после того, как убедитесь, что нет встроенного пробела, но формат правильный.


Я не знаю, какую IDE вы используете для C, поэтому я этого не понимаю ./testprog <test.data.

Мне еще предстоит найти IDE, которая не сводит меня с ума. Я использую оболочку Unix, работающую в окне терминала. Предполагая, что имя вашей программы — testprog, а файл данных — test.data, ввод ./testprog < test.data запускает программу и передает содержимое test.data в качестве стандартного ввода. В Windows это будет командное окно (и я думаю, что PowerShell будет работать точно так же).

Я использовал fgets для чтения каждой строки текстового файла. Хотя я знаю функциональность sscanf, я не знаю, как разобрать всю строку, которая содержит около 23 элементов в строке. Если элементов в строке мало, я знаю, как ее разобрать. Не могли бы вы помочь мне с этим?

Как я отметил в комментарии, SO Q&A Как использовать sscanf() в циклах? объясняет, как использовать sscanf() для чтения нескольких записей в строке. В этом случае вам нужно будет прочитать несколько комплексных чисел из одной строки. Вот некоторый код, который показывает это в работе. Он использует функцию POSIX getline() для чтения произвольно длинных строк. Если он вам недоступен, вы можете вместо него использовать fgets(), но вам потребуется предварительно выделить достаточно большой буфер строк.

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

#ifndef CMPLX
#define CMPLX(r, i)     ((double complex)((double)(r) + I * (double)(i)))
#endif

static size_t scan_multi_complex(const char *string, size_t nvalues,
                                 complex double *v, const char **eoc)
{
    size_t nread = 0;
    const char *buffer = string;
    while (nread < nvalues)
    {
        int offset = 0;
        char sign[2];
        double r, i;
        if (sscanf(buffer, "%lg%[-+]%lg*%*[iI]%n", &r, sign, &i, &offset) != 3 || offset == 0)
            break;
        if (sign[0] == '-')
            i = -i;
        v[nread++] = CMPLX(r, i);
        buffer += offset;
    }

    *eoc = buffer;
    return nread;
}

static void dump_complex(size_t nvalues, complex double values[nvalues])
{
    for (size_t i = 0; i < nvalues; i++)
        printf("%g%+g*I\n", creal(values[i]), cimag(values[i]));
}

enum { NUM_VALUES = 128 };

int main(void)
{
    double complex values[NUM_VALUES];
    size_t nvalues = 0;
    char *buffer = 0;
    size_t buflen = 0;
    int length;
    size_t lineno = 0;

    while ((length = getline(&buffer, &buflen, stdin)) > 0 && nvalues < NUM_VALUES)
    {
        const char *eoc;
        printf("Line: %zu [[%.*s]]\n", ++lineno, length - 1, buffer);
        size_t nread = scan_multi_complex(buffer, NUM_VALUES - nvalues, &values[nvalues], &eoc);
        if (*eoc != '\0' && *eoc != '\n')
            printf("EOC:  [[%s]]\n", eoc);
        if (nread == 0)
            break;
        dump_complex(nread, &values[nvalues]);
        nvalues += nread;
    }
    free(buffer);

    printf("All done:\n");
    dump_complex(nvalues, values);

    return 0;
}

Вот файл данных с 8 строками по 10 комплексных чисел в каждой):

-1.95+11.00*I +21.72+64.12*I -95.16-1.81*I +64.23+64.55*I +28.42-29.29*I -49.25+7.87*I +44.98+79.62*I +69.80-1.24*I +61.99+37.01*I +72.43+56.88*I
-9.15+31.41*I +63.84-15.82*I -0.77-76.80*I -85.59+74.86*I +93.00-35.10*I -93.82+52.80*I +85.45+82.42*I +0.67-55.77*I -58.32+72.63*I -27.66-81.15*I
+87.97+9.03*I +7.05-74.91*I +27.60+65.89*I +49.81+25.08*I +44.33+77.00*I +93.27-7.74*I +61.62-5.01*I +99.33-82.80*I +8.83+62.96*I +7.45+73.70*I
+40.99-12.44*I +53.34+21.74*I +75.77-62.56*I +54.16-26.97*I -37.02-31.93*I +78.20-20.91*I +79.64+74.71*I +67.95-40.73*I +58.19+61.25*I +62.29-22.43*I
+47.36-16.19*I +68.48-15.00*I +6.85+61.50*I -6.62+55.18*I +34.95-69.81*I -88.62-81.15*I +75.92-74.65*I +85.17-3.84*I -37.20-96.98*I +74.97+78.88*I
+56.80+63.63*I +92.83-16.18*I -11.47+8.81*I +90.74+42.86*I +19.11-56.70*I -77.93-70.47*I +6.73+86.12*I +2.70-57.93*I +57.87+29.44*I +6.65-63.09*I
-35.35-70.67*I +8.08-21.82*I +86.72-93.82*I -28.96-24.69*I +68.73-15.36*I +52.85+94.65*I +85.07-84.04*I +9.98+29.56*I -78.01-81.23*I -10.67+13.68*I
+83.10-33.86*I +56.87+30.23*I -78.56+3.73*I +31.41+10.30*I +91.98+29.04*I -9.20+24.59*I +70.82-19.41*I +29.21+84.74*I +56.62+92.29*I +70.66-48.35*I

Вывод программы:

Line: 1 [[-1.95+11.00*I +21.72+64.12*I -95.16-1.81*I +64.23+64.55*I +28.42-29.29*I -49.25+7.87*I +44.98+79.62*I +69.80-1.24*I +61.99+37.01*I +72.43+56.88*I]]
-1.95+11*I
21.72+64.12*I
-95.16-1.81*I
64.23+64.55*I
28.42-29.29*I
-49.25+7.87*I
44.98+79.62*I
69.8-1.24*I
61.99+37.01*I
72.43+56.88*I
Line: 2 [[-9.15+31.41*I +63.84-15.82*I -0.77-76.80*I -85.59+74.86*I +93.00-35.10*I -93.82+52.80*I +85.45+82.42*I +0.67-55.77*I -58.32+72.63*I -27.66-81.15*I]]
-9.15+31.41*I
63.84-15.82*I
-0.77-76.8*I
-85.59+74.86*I
93-35.1*I
-93.82+52.8*I
85.45+82.42*I
0.67-55.77*I
-58.32+72.63*I
-27.66-81.15*I
Line: 3 [[+87.97+9.03*I +7.05-74.91*I +27.60+65.89*I +49.81+25.08*I +44.33+77.00*I +93.27-7.74*I +61.62-5.01*I +99.33-82.80*I +8.83+62.96*I +7.45+73.70*I]]
87.97+9.03*I
7.05-74.91*I
27.6+65.89*I
49.81+25.08*I
44.33+77*I
93.27-7.74*I
61.62-5.01*I
99.33-82.8*I
8.83+62.96*I
7.45+73.7*I
Line: 4 [[+40.99-12.44*I +53.34+21.74*I +75.77-62.56*I +54.16-26.97*I -37.02-31.93*I +78.20-20.91*I +79.64+74.71*I +67.95-40.73*I +58.19+61.25*I +62.29-22.43*I]]
40.99-12.44*I
53.34+21.74*I
75.77-62.56*I
54.16-26.97*I
-37.02-31.93*I
78.2-20.91*I
79.64+74.71*I
67.95-40.73*I
58.19+61.25*I
62.29-22.43*I
Line: 5 [[+47.36-16.19*I +68.48-15.00*I +6.85+61.50*I -6.62+55.18*I +34.95-69.81*I -88.62-81.15*I +75.92-74.65*I +85.17-3.84*I -37.20-96.98*I +74.97+78.88*I]]
47.36-16.19*I
68.48-15*I
6.85+61.5*I
-6.62+55.18*I
34.95-69.81*I
-88.62-81.15*I
75.92-74.65*I
85.17-3.84*I
-37.2-96.98*I
74.97+78.88*I
Line: 6 [[+56.80+63.63*I +92.83-16.18*I -11.47+8.81*I +90.74+42.86*I +19.11-56.70*I -77.93-70.47*I +6.73+86.12*I +2.70-57.93*I +57.87+29.44*I +6.65-63.09*I]]
56.8+63.63*I
92.83-16.18*I
-11.47+8.81*I
90.74+42.86*I
19.11-56.7*I
-77.93-70.47*I
6.73+86.12*I
2.7-57.93*I
57.87+29.44*I
6.65-63.09*I
Line: 7 [[-35.35-70.67*I +8.08-21.82*I +86.72-93.82*I -28.96-24.69*I +68.73-15.36*I +52.85+94.65*I +85.07-84.04*I +9.98+29.56*I -78.01-81.23*I -10.67+13.68*I]]
-35.35-70.67*I
8.08-21.82*I
86.72-93.82*I
-28.96-24.69*I
68.73-15.36*I
52.85+94.65*I
85.07-84.04*I
9.98+29.56*I
-78.01-81.23*I
-10.67+13.68*I
Line: 8 [[+83.10-33.86*I +56.87+30.23*I -78.56+3.73*I +31.41+10.30*I +91.98+29.04*I -9.20+24.59*I +70.82-19.41*I +29.21+84.74*I +56.62+92.29*I +70.66-48.35*I]]
83.1-33.86*I
56.87+30.23*I
-78.56+3.73*I
31.41+10.3*I
91.98+29.04*I
-9.2+24.59*I
70.82-19.41*I
29.21+84.74*I
56.62+92.29*I
70.66-48.35*I
All done:
-1.95+11*I
21.72+64.12*I
-95.16-1.81*I
64.23+64.55*I
28.42-29.29*I
-49.25+7.87*I
44.98+79.62*I
69.8-1.24*I
61.99+37.01*I
72.43+56.88*I
-9.15+31.41*I
63.84-15.82*I
-0.77-76.8*I
-85.59+74.86*I
93-35.1*I
-93.82+52.8*I
85.45+82.42*I
0.67-55.77*I
-58.32+72.63*I
-27.66-81.15*I
87.97+9.03*I
7.05-74.91*I
27.6+65.89*I
49.81+25.08*I
44.33+77*I
93.27-7.74*I
61.62-5.01*I
99.33-82.8*I
8.83+62.96*I
7.45+73.7*I
40.99-12.44*I
53.34+21.74*I
75.77-62.56*I
54.16-26.97*I
-37.02-31.93*I
78.2-20.91*I
79.64+74.71*I
67.95-40.73*I
58.19+61.25*I
62.29-22.43*I
47.36-16.19*I
68.48-15*I
6.85+61.5*I
-6.62+55.18*I
34.95-69.81*I
-88.62-81.15*I
75.92-74.65*I
85.17-3.84*I
-37.2-96.98*I
74.97+78.88*I
56.8+63.63*I
92.83-16.18*I
-11.47+8.81*I
90.74+42.86*I
19.11-56.7*I
-77.93-70.47*I
6.73+86.12*I
2.7-57.93*I
57.87+29.44*I
6.65-63.09*I
-35.35-70.67*I
8.08-21.82*I
86.72-93.82*I
-28.96-24.69*I
68.73-15.36*I
52.85+94.65*I
85.07-84.04*I
9.98+29.56*I
-78.01-81.23*I
-10.67+13.68*I
83.1-33.86*I
56.87+30.23*I
-78.56+3.73*I
31.41+10.3*I
91.98+29.04*I
-9.2+24.59*I
70.82-19.41*I
29.21+84.74*I
56.62+92.29*I
70.66-48.35*I

Код будет обрабатывать строки с любым количеством записей в строке (всего до 128 из-за ограничения на размер массива комплексных чисел — но это тоже можно исправить.

Спасибо @jonathan-Leffer. Но он печатает до 5 выходов одновременно в CCS.

Palguna Gopireddy 11.11.2022 11:24

Я не понимаю, что вы имеете в виду, говоря о печати до 5 выходов за раз.

Jonathan Leffler 11.11.2022 15:23

Я имел в виду, что у меня есть текстовый файл со многими элементами. Я не могу ввести каждый элемент через клавиатуру. Я попытался скопировать, вставив все элементы за раз, но печатаются только первые пять элементов.

Palguna Gopireddy 14.11.2022 07:33

Должна быть проблема с шестой записью в файле. Показанный код считывается из стандартного ввода; это обычное упражнение, чтобы заставить его читать из других файлов. Действительно, функция сканирования уже считывает любой открытый входной файловый поток. Я использовал ./testprog <test.data для чтения показанного файла. Возможно, вам лучше читать целые строки из файла, а затем использовать sscanf() в цикле для анализа строки. Таким образом, вы можете лучше сообщать об ошибках.

Jonathan Leffler 14.11.2022 13:34

Спасибо @Jonathan-Leffler. Я использовал fgets для чтения каждой строки текстового файла. Хотя я знаю функциональность sscanf, я не знаю, как разобрать всю строку, которая содержит около 23 элементов в строке. Если элементов в строке мало, я знаю, как ее разобрать. Не могли бы вы помочь мне с этим? . Также я не знаю, какую IDE вы используете для C. Поэтому я не понимаю, где это ./testprog <test.data

Palguna Gopireddy 15.11.2022 12:20

Вот код, который я использовал для получения строки с помощью getsдля чтения строки из текста. Я не знаю, как разобрать его с помощью sscanf, так как в строке 23 элемента.

Palguna Gopireddy 15.11.2022 12:31

Вопрос Как использовать sscanf() в циклах? показывает, как анализировать несколько значений из строки — спецификатор преобразования %n является ключевой частью решения.

Jonathan Leffler 15.11.2022 15:32

Спасибо @ Джонатан-Леффлер. Я воспользуюсь этим и доберусь до вас с обновлением,

Palguna Gopireddy 16.11.2022 04:54

Другие вопросы по теме