简体   繁体   中英

How to read imaginary data from text file, with C

I am unable to read imaginary data from text file. Here is my.txt file

abc.txt

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

I want to read this data into a matrix and print it.

I found the solutions using C++ here and here . I don't know how to do the same in C.

I am able to read decimal and integer data in.txt and print them. I am also able to print imaginary data initialized at the declaration, using complex.h header. This is the program I have writtern

#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;
}

But I want to read it from the text, because I have an array of larger size, which I can't initialize at declaration, because of it's size.

There are two main issues with your code:

  • You need to add complex to the variables that hold complex values.
  • scanf() needs pointers to objects to store scanned values in them. But creal() returns a value, copied from its argument's contents. It is neither a pointer, nor could you get the address of the corresponding part of the complex argument.

Therefore, you need to provide temporary objects to scanf() which receive the scanned values. After successfully scanning, these values are combined to a complex value and assigned to the indexed matrix cell.

Minor issues not contributing to the core problem are:

  • The given source is "augmented" with unneeded #include s, unused variables, global variables, and experiments with constants. I removed them all to see the real thing.

  • The specifier "%f" (as many others) lets scanf() skip whitespace like blanks, tabs, newlines, and so on. Providing a "\n" mostly does more harm than one would expect.

    I kept the "*I" to check the correct format. However, an error will only be found on the next call of scanf() , when it cannot scan the next number.

  • You need to check the return value of scanf() , always. It returns the number of conversions that were successful.

  • It is a common and good habit to let the compiler calculate the number of elements in an array. Divide the total size by an element's size.

    Oh, and sizeof is an operator, not a function.

  • It is also best to return symbolic values to the caller, instead of magic numbers. Fortunately, the standard library defines these EXIT_... macros.

  • The signs are correctly handled by scanf() already. There is no need to tell it more. But for a nice output with printf() , you use the "+" as a flag to always output a sign.

  • Since the sign is now placed directly before the number, I moved the multiplication by I (you can change it to lower case, if you want) to the back of the imaginary part. This also matches the input format.

  • Error output is done via stderr instead of stdout . For example, this enables you to redirect the standard output to a pipe or file, without missing potential errors. You can also redirect errors somewhere else. And it is a well-known and appreciated standard.

This is a possible solution:

#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;
}

Here's a simple solution using scanf() and the format shown in the examples. It writes the values in the same format that it reads them — the output can be scanned by the program as input.

/* 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;
}

Sample input:

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

Output from sample input:

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

The numbers at the end with large exponents are Avogadro's Number and the Planck Constant.

The format is about as stringent are you can make it with scanf() , but, although it requires a sign ( + or - ) between the real and imaginary parts and requires the * and I to be immediately after the imaginary part (and the conversion will fail if the *I is missing), and accepts either i or I to indicate the imaginary value:

  • It doesn't stop the imaginary number having a second sign (so it will read a value such as " -6+-4*I ").
  • It doesn't stop there being white space after the mandatory sign (so it will read a value such as " -6+ 24*I ".
  • It doesn't stop the real part being on one line and the imaginary part on the next line.
  • It won't handle either a pure-real number or a pure-imaginary number properly.

The scanf() functions are very flexible about white space, and it is very hard to prevent them from accepting white space. It would require a custom parser to prevent unwanted spaces. You could do that by reading the numbers and the markers separately, as strings, and then verifying that there's no space and so on. That might be the best way to handle it. You'd use sscanf() to convert the string read after ensuring there's no embedded white space yet the format is correct.


I do not know which IDE you are using for C, so I do not understand this ./testprog <test.data .

I have yet to find an IDE that does not drive me bonkers. I use a Unix shell running in a terminal window. Assuming that your program name is testprog and the data file is test.data , typing ./testprog < test.data runs the program and feeds the contents of test.data as its standard input. On Windows, this would be a command window (and I think PowerShell would work much the same way).

I used fgets to read each line of the text file. Though I know the functionality of sscanf , I do not know how to parse an entire line, which has about 23 elements per line. If the number of elements in a line are few, I know how to parse it. Could you help me about it?

As I noted in a comment, the SO Q&A How to use sscanf() in loops? explains how to use sscanf() to read multiple entries from a line. In this case, you will need to read multiple complex numbers from a single line. Here is some code that shows it at work. It uses the POSIX getline() function to read arbitrarily long lines. If it isn't available to you, you can use fgets() instead, but you'll need to preallocate a big enough line buffer.

#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;
}

Here is a data file with 8 lines with 10 complex numbers per line):

-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

The output of the program is:

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

The code would handle lines with any number of entries on a line (up to 128 in total because of the limit on the size of the array of complex numbers — but that can be fixed too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM