从标准输入读取和打印矩阵

Posted

技术标签:

【中文标题】从标准输入读取和打印矩阵【英文标题】:reading and printing matrix from stdin 【发布时间】:2022-01-10 01:04:27 【问题描述】:

嗯,我之前发布过,但现在有所改进,我只有一个问题(我猜)。

任务是编写一个函数,该函数读取“.txt 文件”中给出的整数矩阵,使用 I/O 重定向,然后编写另一个函数来打印它。

我将 txt 读入一维数组 (arr),然后从中创建二维矩阵 (mat),在此之前,我动态分配内存,因为我们的教授要求这样做。问题是当我将它放在 for 循环并尝试为矩阵解决它时,它似乎正在改变。我会很感激任何想法......另外,如果你们能评论我分配内存的方式,那将会很有帮助。 (别忘了我们有 3 个不同的 input.txt,其中一些有类似 -5.58234 的值,或者在这个例子中它们没有用“,”分隔,所以我想让我的代码在任何情况下都可用)

示例 txt 文件:

 16,  11,  10,  16,  24,  40,  51,  61,
 12,  12,  14,  19,  26,  58,  60,  55,
 14,  13,  16,  24,  40,  57,  69,  56,
 14,  17,  22,  29,  51,  87,  80,  62,
 18,  22,  37,  56,  68, 109, 103,  77,
 24,  35,  55,  64,  81, 104, 113,  92,
 49,  64,  78,  87, 103, 121, 120, 101,
 72,  92,  95,  98, 112, 100, 103,  99

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int readMatrix(int *arr, int **mat);
void printMatrix(int **mat, int size);

int main()
    
    // declare 1D array and allocate memory
    
    int *arr;
    arr = malloc(sizeof(stdin)*sizeof(int));
    
    // declare 2D Matrix and allocate memory
    
    int **mat;
    mat = (int **)malloc(sizeof(stdin)*sizeof(int));
    
    // function implementations
    int size;   
    size = readMatrix(arr, mat);    
    
    printMatrix(mat,size);  
    
    return 0;


int readMatrix(int *arr, int **mat)
    
    // reading
    
    int i=0, size=0; // loop var i and size to count the elements of array  
    
    while(scanf("%d,", &arr[i]) != EOF)
    
        i++;
        size++;
    
    
    printf("arr[63] = %d \n\n",arr[63]); // VALUE IS CORRECT HERE   
    
    // finding row and column numbers
    int rows = sqrt(size), cols = rows; 

    // appending 1d array into matrix
    int m = 0;
    
    // test printf("rows = %d, cols = %d\n", rows, cols);
    for(int i=0; i<rows; i++)
        for(int j=0; j<cols; j++)
            
            printf("arr[%d] = %d\n",m, arr[m]); // VALUES OF arr[] BECAME WEIRD AFTER arr[12]

            //mat[i][j] = arr[m]; // segmentation fault
            //*(*(mat+i)+j) = arr[m]; // segmentation fault
            //*(*(mat+i)+j) = &arr[m]; // segmentation fault    
            *(mat + i*cols + j) = &arr[m]; // I don't know if this is the proper way but it works
            m++;
        
       
    printf("\narr[63] = %d\n",arr[63]); // HOWWWWW
    
    // return size for further implementations
    //
    return size;


void printMatrix(int **mat, int size)
    
    int rows = sqrt(size), cols = rows;

    printf("\nMATRIX A:\n");
        
    for(int i=0; i<rows; i++)
        for(int j=0; j<cols; j++)
           
            printf("%d     ", mat[i][j]);
            //if(mat[i][j]>=10 && mat[i][j]<100 )printf("%d      ", mat[i][j]);
            //else if(mat[i][j]>=100 )printf("%d     ", mat[i][j]);
            //elseprintf("%d       ", mat[i][j]);
        
        printf("\n");
    


输出:

$ ./secondtry < input1.txt
arr[63] = 99

arr[0] = 16
arr[1] = 11
arr[2] = 10
arr[3] = 16
arr[4] = 24
arr[5] = 40
arr[6] = 51
arr[7] = 61
arr[8] = 12
arr[9] = 12
arr[10] = 14
arr[11] = 19
arr[12] = 976
arr[13] = 8
arr[14] = 980
arr[15] = 8
arr[16] = 984
arr[17] = 8
arr[18] = 988
arr[19] = 8
arr[20] = 992
arr[21] = 8
arr[22] = 996
arr[23] = 8
arr[24] = 1000
arr[25] = 8
arr[26] = 1004
arr[27] = 8
arr[28] = 1008
arr[29] = 8
arr[30] = 1012
arr[31] = 8
arr[32] = 1016
arr[33] = 8
arr[34] = 1020
arr[35] = 8
arr[36] = 1024
arr[37] = 8
arr[38] = 1028
arr[39] = 8
arr[40] = 1032
arr[41] = 8
arr[42] = 1036
arr[43] = 8
arr[44] = 1040
arr[45] = 8
arr[46] = 1044
arr[47] = 8
arr[48] = 1048
arr[49] = 8
arr[50] = 1052
arr[51] = 8
arr[52] = 1056
arr[53] = 8
arr[54] = 1060
arr[55] = 8
arr[56] = 1064
arr[57] = 8
arr[58] = 1068
arr[59] = 8
arr[60] = 1072
arr[61] = 8
arr[62] = 1076
arr[63] = 8

arr[63] = 8

MATRIX A:
16     11     10     16     24     40     51     61
11     10     16     24     40     51     61     12
10     16     24     40     51     61     12     12
16     24     40     51     61     12     12     14
24     40     51     61     12     12     14     19
40     51     61     12     12     14     19     976
51     61     12     12     14     19     976     8
61     12     12     14     19     976     8     980

【问题讨论】:

您对sizeof(stdin)的价值有什么期望? sizeof(stdin) 是指针的大小,与将从输入流中读取的数据量无关。几乎可以肯定这里的问题是您没有分配足够的空间并且正在覆盖缓冲区,从而导致未定义的行为。通常,在您阅读之前,您无法知道有多少数据可用。 (如果输入的是一个常规文件,你可以stat它来确定它的大小,这可以让你大致估计条目的数量,但这不是一个好主意。)。读取数据并根据需要扩展数据结构。 是的,我不确定它是否会起作用,我这周才开始处理指针、数组、内存分配。谢谢你的解释。 tbh,我们的教授在讲座中没有提到stat,我必须检查一下。所以我只是用arr = malloc(16*16*sizeof(int));mat = (int **)malloc(16*16*sizeof(int)); 16*16 尝试了它,因为其中有一个input.txt,其中包含16x16 矩阵。奇怪的数字消失了,但现在我打印了一个重复矩阵。我想我在将值迭代和附加到矩阵中时也遇到了一些问题。 int rows = sqrt(size) 强烈不推荐。如果要读取静态未知大小的矩阵,请在值之前的输入中提供大小,并将其设为行/列数,而不是元素总数。更好的是,分别为行和列提供 2 种大小。因此2 2 34 56 78 90 将指定一个包含元素 34 56 78 90 的 2x2 矩阵。 【参考方案1】:

因为我们正在阅读来自stdin,我们可以做一些简单的事情,比如:

    读取/解析第一个以确定列数 倒带文件 读取/解析所有行并存储在矩阵中(随时分配空间)

请注意,在计数上使用sqrt 来获取行数/列数有点“独特”。这是我第一次看到这样做。

在处理具有动态维度的二维矩阵时,定义一个控件struct 以便能够存储维度会有所帮助。然后,所有矩阵的相关信息可供所有人使用。

总的来说,比起scanf,我更喜欢fgets/strtok/strtol

在这个用例中,我确定scanf("%d,",&amp;val)是否可以解析(例如)103,99。也就是说,输入文件的最后一个数字后面有no逗号。

因此,我不得不对代码进行相当多的重构。有注释:

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

#ifdef DEBUG
#define dbgprt(_fmt...) \
    printf(_fmt)
#else
#define dbgprt(_fmt...) \
    do   while (0)
#endif

// matrix control
typedef struct 
    int mtx_cols;                       // number of columns
    int mtx_rows;                       // number of rows (input lines)
    int *mtx_base;                      // pointer to matrix data
 mtx_t;

// helper macro to access a given matrix coordinate
#define MTX(_mtx,_irow,_icol) \
    _mtx->mtx_base[((_irow) * _mtx->mtx_cols) + _icol]

// newMatrix -- get new matrix control
mtx_t *
newMatrix(void)

    mtx_t *mtx;

    mtx = calloc(1,sizeof(*mtx));

    return mtx;


// readMatrix -- read in matrix from stream
void
readMatrix(mtx_t *mtx,FILE *xfin)

    char *bp;
    char *cp;
    char buf[1000];

    // get first line as a special case to calculate the number of columns
    fgets(buf,sizeof(buf),xfin);

    // we need to preserve the original data for the second loop below
    char tmp[1000];
    strcpy(tmp,buf);

    // calculate number of columns
    bp = tmp;
    while (1) 
        char *cp = strtok(bp," ,\n");
        bp = NULL;

        if (cp == NULL)
            break;

        mtx->mtx_cols += 1;
    

    // read in row by row
    while (1) 
        // get current row index and advance the row count
        int irow = mtx->mtx_rows++;

        dbgprt("BUF/%d: %s",irow,buf);

        // add space for this row
        mtx->mtx_base = realloc(mtx->mtx_base,
            sizeof(*mtx->mtx_base) * mtx->mtx_rows * mtx->mtx_cols);
        if (mtx->mtx_base == NULL) 
            perror("realloc");
            exit(2);
        

        // parse this row
        bp = buf;
        for (int icol = 0;  icol < mtx->mtx_cols;  ++icol) 
            char *cp = strtok(bp," ,\n");
            bp = NULL;

            if (cp == NULL)
                break;

            MTX(mtx,irow,icol) = strtol(cp,&cp,10);
            dbgprt(" %d\n",MTX(mtx,irow,icol));
        

        // get data for next row
        if (fgets(buf,sizeof(buf),xfin) == NULL)
            break;
    


void
printMatrix(const mtx_t *mtx)


    printf("\nMATRIX A:\n");

    for (int irow = 0;  irow < mtx->mtx_rows;  ++irow) 
        for (int icol = 0;  icol < mtx->mtx_cols;  ++icol)
            printf(" %d",MTX(mtx,irow,icol));
        printf("\n");
    


int
main(int argc,char **argv)


    --argc;
    ++argv;

    FILE *xfin;
    if (argc > 0)
        xfin = fopen(*argv,"r");
    else
        xfin = stdin;
    if (xfin == NULL)
        exit(1);

    // declare 1D array and allocate memory
    mtx_t *mtx = newMatrix();

    readMatrix(mtx,xfin);
    printMatrix(mtx);

    return 0;

【讨论】:

如果stdin是普通文件,可以倒带。 @WilliamPursell 是的,当然,但是正如 OP 描述的问题,我们必须使用 stdin,所以我们不能依赖它。我只是将fopen 用作调试辅助(对我而言)

以上是关于从标准输入读取和打印矩阵的主要内容,如果未能解决你的问题,请参考以下文章

如何将多行输入从标准输入读取到变量中以及如何在 shell(sh,bash)中打印出来?

从文件或标准输入读取

在 C 中使用 fread 从标准输入缓冲读取

从标准输入读取字符串,将读取的内容连接成一个大字符串

使用指针符号从矩阵中读取数据

从标准输入将原始类型的值读入变量