如何让我的代码从文件中读取任意数量的浮点数输入?

How to make my code read input from a file for an arbitrary number of floats?

我用 c 语言编写了一段代码,它从文本文件中读取数字并将它们放入数组中的矩阵格式。问题是我已经使我的代码适用于确定大小为 3x3 的矩阵。如果我必须增加大小,我必须直接在代码中更改它。我怎样才能改变我的代码,以便它自动创建一个所需大小的数组并读取文件而不考虑它的长度(假设输入文件将包含足够的数字来形成一个方阵)?例如,我可以给它一个输入文件,其中包含一个 nxn 矩阵的逗号分隔的数字,我的代码应该给我一个包含这些数字的 nxn 矩阵。 这是我的代码,

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

//Declaring Matrices
float A[3][3];

//Function to read the matrices from a file
int ReadMatrix(void){
    FILE * f_pointer;
    f_pointer = fopen("Input Matrix.txt","r");
    if(f_pointer==NULL){
        printf("Error 404:- File not found");
        return 1;
    }
    
    fscanf(f_pointer,"%f, %f, %f\n%f, %f, %f\n%f, %f, %f", &A[0][0], &A[0][1], &A[0][2], &A[1][0], &A[1][1], &A[1][2], &A[2][0], &A[2][1], &A[2][2]);
    return 0;
}

可能最简单的 single-pass 方法很简单,就是将文件中的浮点数读取到分配的内存块中,可以根据需要使用 realloc 扩展该内存块,直到读取所有值。然后您可以简单地循环并确定读取的值的数量是否会形成一个方阵——如果它们不会,则处理错误。然后,您将拥有一个有效存储的浮点数块,可以通过简单的算术将其作为二维数组进行操作。例如,如果您读取 9 个值,并且您的正方形大小为 3x3,则您可以访问 i, j 行和列值作为:

array [i * 3 + j];

(注意: 另一种选择——您可以分配 n 指针和 n 额外的 n 块 - 如果需要,可以浮动真正的二维索引,例如 array [i][j] -- 由你决定)

一个简单的实现可以是:

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

#define NELEM 16    /* initial number of floats to allocate */

/** realloc 'ptr' of 'nelem' of 'psz' to 'nelem * 2' of 'psz'.
 *  if *nelem == 0, initial allocation of NELEM psz block,
 *  returns pointer to reallocated block of memory with new
 *  memory initialized to 0/NULL. return must be assigned to
 *  original pointer in caller.
 */
void *xrealloc2 (void *ptr, size_t psz, size_t *nelem)
{
    void *memptr = NULL;
    if (!*nelem)
        *nelem = NELEM < 2 ? 2 : NELEM / 2;
    memptr = realloc (ptr, *nelem * 2 * psz);
    if (!memptr) {
        perror ("realloc(): virtual memory exhausted.");
        exit (EXIT_FAILURE);
        /* return NULL; */
    }   /* zero new memory (optional) */
    memset ((char *)memptr + *nelem * psz, 0, *nelem * psz);
    *nelem *= 2;
    return memptr;
}

int main (int argc, char **argv) {
    
    float *arr = NULL;      /* pointer to allocate block of floats */
    size_t  n = 0,          /* number of floats read */
            nelem = 0,      /* number allocated */
            sqsize = 0;     /* square size of 2D matrix */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }
    
    for (;;) {              /* loop continually reading float from file */
        if (n == nelem)     /* is realloc needed? */
            arr = xrealloc2 (arr, sizeof *arr, &nelem); /* realloc 2x current */
        if (fscanf (fp, "%f", &arr[n]) != 1) {          /* read/validate float */
            if (n)          /* if values stored, break loop */
                break;
            else            /* otherwise, error or EOF before values read */
                exit (EXIT_FAILURE);
        }
        n++;
    }
    
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);
    
    while (sqsize * sqsize < n)     /* determine size of square matrix */
        sqsize++;
    
    if (sqsize * sqsize != n) {     /* validate only that number read */
        fputs ("error: n not a square.\n", stderr);
        exit (EXIT_FAILURE);
    }
    
    for (size_t i = 0; i < sqsize; i++) {           /* output matrix */
        for (size_t j = 0; j < sqsize; j++)
            printf (" %2g", arr[i * sqsize + j]);
        putchar ('\n');
    }
    
    free (arr);     /* free allocated memory */
}

由于您一次阅读一个 float,因此数字是否全部排成一行、一个 per-line 或以 square-matrix 形式排列并不重要, fscanf() 跳过 whitespace 无论是 space 还是换行符。

例子Use/Output

2x2:

$ echo "1.1 2.2 3.3 4.4" | ./bin/array_1d2d_square_float
 1.1 2.2
 3.3 4.4

non-square:

$ echo "1.1 2.2 3.3 4.4 5.5" | ./bin/array_1d2d_square_float
error: n not a square.

3x3:

$ echo "1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9" | ./bin/array_1d2d_square_float
 1.1 2.2 3.3
 4.4 5.5 6.6
 7.7 8.8 9.9

9x9 来自文件 1-81:

$ ./bin/array_1d2d_square_float dat/81int.txt
  1  2  3  4  5  6  7  8  9
 10 11 12 13 14 15 16 17 18
 19 20 21 22 23 24 25 26 27
 28 29 30 31 32 33 34 35 36
 37 38 39 40 41 42 43 44 45
 46 47 48 49 50 51 52 53 54
 55 56 57 58 59 60 61 62 63
 64 65 66 67 68 69 70 71 72
 73 74 75 76 77 78 79 80 81

我也玩得很开心,也创建了一个程序,它可能更容易理解一些。 :-)

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

/* Program to read a square matrix from a file */
/* Syntax: <programname> <filename> */
int main(int argc, char *argv[])
{
    FILE *f_pointer = NULL;
    f_pointer = fopen(argv[1],"r");

    if(f_pointer==NULL)
    {
        printf("File not found\n");
        return 1;
    }
    else
    {
        char floatbuffer[32] = "";
        float matrix_member[256]; /* supports up to a 16x16 square matrix */
        int matrix_entries = 0;
        int matrix_columns_n_rows = 0;
        
        for(int i = 0; !feof(f_pointer); i = fgetc(f_pointer))
        {
            if(i=='\n'||i==' ')
            {
                /* do nothing */
            }
            else if(i==',')
            {
                /* read matrix member */
                sscanf(floatbuffer, "%f", &matrix_member[matrix_entries]);                
                matrix_entries++;
                
                floatbuffer[0] = '[=10=]'; /* reset floatbuffer */
            }
            else
            {
                char c[2] = {i&0b11111111, '[=10=]'}; /* transform unsigned char to string */
                strcat(floatbuffer, c);
            }
        }
        /* read last matrix member too */
        sscanf(floatbuffer, "%f", &matrix_member[matrix_entries]);        
        matrix_entries++;
        
        /* close file */
        fclose(f_pointer);
        
        printf("total matrix entries %i\n", matrix_entries);
        for(int i = 0; i<matrix_entries; i++)
        {
            printf("entry #%i: %f\n", i+1, matrix_member[i]);
        }
        
        /* check for plausbility */
        for(int i = 1; i<17; i++)
        {
            if(i*i==matrix_entries)
            {
                matrix_columns_n_rows=i;
            }
        }
        
        if(matrix_columns_n_rows)
        {
            printf("this is a valid square matrix with %i columns and %i rows\n", matrix_columns_n_rows, matrix_columns_n_rows);
            return 0;
        }
        else
        {
            printf("this isn't a valid square matrix\n");
            return 2;
        }
    }
}

输出

total matrix entries 9
entry #1: 0.100009
entry #2: 0.200008
entry #3: 0.300007
entry #4: 0.400006
entry #5: 0.500005
entry #6: 0.600004
entry #7: 0.700003
entry #8: 0.800002
entry #9: 0.900001
this is a valid square matrix with 3 columns and 3 rows