Я не могу прочитать воображаемые данные из текстового файла. Вот мой .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;
}
Но я хочу прочитать это из текста, потому что у меня есть массив большего размера, который я не могу инициализировать при объявлении из-за его размера.
fscanf, вероятно, первая функция, которую нужно попробовать, чтобы найти решение.
Вы печатаете пробелы вокруг знака +, которых нет во входном формате. Нужно ли нам справляться с вашим форматом вывода, а также с форматом ввода? И, вероятно, у вас может быть -1.2-3.6*I (с - вместо +)? Обеспечение присутствия и чтения *I создает некоторые проблемы, но они не являются непреодолимыми. Что вы пробовали, и где вы столкнулись с проблемами?
Я поместил минимальный воспроизводимый код примера, который я использовал. Согласно заявлению + или -, войдите в printf заявление. Я использовал только символ +. Я не проверял значения знака -. Я проверю и дам вам знать.
Ваш код не проверяет возвращаемое значение из fscanf(), поэтому вы понятия не имеете, что сработало. Ваш формат содержит %lf+i%lf, который не имеет отношения к примерам ввода, таким как 0.2e-3+0.3*I,
Обратите внимание эффект завершающего пробела в строке формата scanf()





Есть две основные проблемы с вашим кодом:
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;. В противном случае он дает неверный формат ввода. Большое спасибо.
Ну, у вас есть это в вашем примере ввода. ;-)
Вот простое решение с использованием 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.
Я не понимаю, что вы имеете в виду, говоря о печати до 5 выходов за раз.
Я имел в виду, что у меня есть текстовый файл со многими элементами. Я не могу ввести каждый элемент через клавиатуру. Я попытался скопировать, вставив все элементы за раз, но печатаются только первые пять элементов.
Должна быть проблема с шестой записью в файле. Показанный код считывается из стандартного ввода; это обычное упражнение, чтобы заставить его читать из других файлов. Действительно, функция сканирования уже считывает любой открытый входной файловый поток. Я использовал ./testprog <test.data для чтения показанного файла. Возможно, вам лучше читать целые строки из файла, а затем использовать sscanf() в цикле для анализа строки. Таким образом, вы можете лучше сообщать об ошибках.
Спасибо @Jonathan-Leffler. Я использовал fgets для чтения каждой строки текстового файла. Хотя я знаю функциональность sscanf, я не знаю, как разобрать всю строку, которая содержит около 23 элементов в строке. Если элементов в строке мало, я знаю, как ее разобрать. Не могли бы вы помочь мне с этим? . Также я не знаю, какую IDE вы используете для C. Поэтому я не понимаю, где это ./testprog <test.data
Вот код, который я использовал для получения строки с помощью getsдля чтения строки из текста. Я не знаю, как разобрать его с помощью sscanf, так как в строке 23 элемента.
Вопрос Как использовать sscanf() в циклах? показывает, как анализировать несколько значений из строки — спецификатор преобразования %n является ключевой частью решения.
Спасибо @ Джонатан-Леффлер. Я воспользуюсь этим и доберусь до вас с обновлением,
Вы должны быть более конкретными, чем «не знаю, как». Пожалуйста, покажите, что вы пробовали, в качестве минимального воспроизводимого примера и опишите, на каком конкретном этапе вы застряли.