[英]How do I read in a matrix of unknown length, without whitespaces?
我的输入文件如下所示:
1,12,5,14,0
4,6,2,3,24
1,2,3,4,5
每条线都有相同的长度,但没有指定有多少条线,以及它们有多长。 (最大尺寸为 20*20)。
我需要将它们读入一个 20*20 的数组,以便如果该行只有 2 个数字长,则数组的其余部分为空。
当文件中出现换行符时,我该怎么做,同时省略,
字符并从数组的下一行开始?
这是我的尝试:
int matrix[20][20];
for (int i=0; i<19; i++){
for (int j=0; j<19; j++){
fscanf(be, "%d,", &matrix[i][j]);
}
fscanf(be, "\n");
}
Ps:我只允许使用<stdio.h>
和<stdlib.h>
。
我有这个想法。 下面的代码为每个循环周期从文件中读取一行并扫描它,如果它不是空行。 使用函数(在代码中实现) mystrchr
检索分隔符SEP
#include <stdio.h>
#include <stdlib.h>
char * mystrchr(const char * s, char x);
char * mystrchr(const char * s, char x)
{
while(*s!=0 && *s!=x) s++;
return ((!*s)?NULL:(char *)s);
}
int main(void)
{
#define FILENAME "x.txt"
#define ROWS 20
#define MAXEL 20
#define BDIM 10240
#define SEP ','
int x[ROWS][MAXEL],elr[ROWS], ronum=0,elnum,i,j;
FILE * fptr;
char buffer[BDIM],* app;
/* --- Init the array --- */
for(i=0;i<ROWS; i++)
for(j=0;j<MAXEL; j++)
x[i][j]=0;
/* --- Open the file --- */
fptr=fopen(FILENAME,"r");
if (!fptr)
return 1;
/* --- Gets data from file --- */
while(ronum<ROWS && fgets(buffer,BDIM,fptr)) {
app = buffer;
/* Takes only non-void lines */
if (*app && *app!='\n' && *app!='\r') {
elnum=0;--app;
/* Scan the line */
do {
if (* ++app ) {
x[ronum][elnum++]=strtol(app,NULL,0);
}
app = mystrchr(app,SEP);
} while(app && elnum<MAXEL);
// -- save the number of element per row
if (elnum) {
elr[ronum]=elnum;
ronum++;
}
}
}
if (fptr)
fclose(fptr);
/* --- Prints data --- */
for(i=0;i<ronum;i++) {
for(j=0;j<elr[i];j++) {
printf("%d ",x[i][j]);
}
puts("");
}
return 0;
}
可以使用fgetc
逐个字符读取未指定长度的行。 在您的情况下,您必须检查每个字符是否符合以下条件:
如果你看到一个','
,你就看到了一个数字;
如果你看到一个'\\n'
,你就看到了一个数字,你看到了一条线。
您跳过每个非数字字符;
您将数字放在一个小的临时缓冲区中。 一旦你看到一个数字,你可以使用atoi
转换它;
如果不允许使用atoi
,则执行number= number*10 + c-'0';
用c
表示您看到的每个数字的数字。
从描述中不清楚一行是否可能为空。
假设所有行都是非空的,那么这是一个非常简单的scanf()
工作,但重要的一点是永远不要丢弃输入函数的返回值。
几种可能的方法:
%d
模式扫描每行的第一个数字(返回值 0 表示我们已读取所有行),然后使用,%d
扫描该行的后续数字。 当输入流中没有,
时, scanf()
将返回 0,然后我们移至下一行。%d%c
模式进行扫描以将数字后面的字符捕获到变量中(例如char sep
)。 当返回值为 0 时,我们已读取所有行,并中断循环。 当返回值为 2 时,我们可以检查sep
看它是,
还是\\n
并选择是否前进到下一行。 (如果返回值为 1,则最后一个数字在文件末尾,没有最后的换行符)。 如果某些或所有行可能为空,您将需要查看该行的第一个字符是否为换行符(可能使用getc()
和ungetc()
)。 那将指示一个空行。
实际上你只需要<stdio.h>
。 您可以通过使用fgets()
每一行读入缓冲区来分隔值。 您可以使用sscanf
解析缓冲区中的每个值,并使用"%n"
说明符维护缓冲区开头的偏移量,以确定每次转换为int
期间消耗的字符数。 您将该数字( +1
以考虑','
)添加到每个转换值的偏移量中。
(注意:理想情况下,给定stdlib.h
您可能希望使用strtol
来处理转换,因为它提供了完整的错误处理,允许您确定转换失败的原因并处理失败,但没有限制limits.h
和errno.h
您无法确定转换过程中是否发生下溢/溢出(不提供您自己的LONG_MIN/LONG_MAX
值),因此您只能检查字符是否已转换——您可以使用sscanf
)
在你的情况下,首先#define
常量为您的行,列和缓冲区的大小,例如数
#include <stdio.h>
#define ROWS 20 /* if you need a constant, #define one (or more) */
#define COLS ROWS
#define MAXC 1024
现在声明您的数组和缓冲区以及行和列变量,打开指定为程序第一个参数的文件名并验证它是否可以读取(如果没有给出参数,则默认从stdin
读取):
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold each line read */
int arr[ROWS][COLS] = {{0}}, row = 0, col = 0; /* array & bounds */
/* 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;
}
现在将文件中的每一行读入buf
并声明您将用于跟踪从buf
开头的offset
量、每次转换期间消耗的字符数n
、行中的列数ncol
和解析的值val
的变量:
while (row < ROWS && fgets (buf, MAXC, fp)) { /* read each line */
int offset = 0, /* offset from beginning of line */
n = 0, /* number of characters consumed in conversion */
ncol = 0, /* number of columns in line */
val; /* value from conversion */
现在循环维护您的偏移量并转换行中的每个值,将其添加到您的数组中:
while (ncol < COLS && sscanf (buf + offset, "%d%n", &val, &n) == 1) {
arr[row][ncol++] = val; /* assign val, increment ncol */
offset += n + 1; /* update offset + 1 for ',' */
}
现在一些家务。 如果需要确保数组中的每一行都有相同的列数,请根据第一行解析的值数设置列数。 然后对于所有其他行,与该值进行比较以确保每行具有相同数量的值:
if (!col) /* if number of columns not set */
col = ncol; /* set to no. columns in 1st row */
if (ncol != col) { /* force all other rows to have same no. cols */
fputs ("error: unequal number of columns.\n", stderr);
return 1;
}
解析所有值后,只需增加行计数器并转换下一行值:
row++; /* increment row count */
}
从本质上讲,这就是您需要做的所有事情。 剩下的就是关闭文件流(如果不是从stdin
读取)并根据需要使用数组中的值。 一个完整的例子可能是:
#include <stdio.h>
#define ROWS 20 /* if you need a constant, #define one (or more) */
#define COLS ROWS
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold each line read */
int arr[ROWS][COLS] = {{0}}, row = 0, col = 0; /* array & bounds */
/* 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;
}
while (row < ROWS && fgets (buf, MAXC, fp)) { /* read each line */
int offset = 0, /* offset from beginning of line */
n = 0, /* number of characters consumed in conversion */
ncol = 0, /* number of columns in line */
val; /* value from conversion */
/* loop over each value in line */
while (ncol < COLS && sscanf (buf + offset, "%d%n", &val, &n) == 1) {
arr[row][ncol++] = val; /* assign val, increment ncol */
offset += n + 1; /* update offset + 1 for ',' */
}
if (!col) /* if number of columns not set */
col = ncol; /* set to no. columns in 1st row */
if (ncol != col) { /* force all other rows to have same no. cols */
fputs ("error: unequal number of columns.\n", stderr);
return 1;
}
row++; /* increment row count */
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (int i = 0; i < row; i++) { /* output array */
for (int j = 0; j < col; j++)
printf (" %3d", arr[i][j]);
putchar ('\n');
}
}
该示例仅输出存储在数组中的值并退出。
示例输入文件
$ cat dat/2020max.txt
1,12,5,14,0
4,6,2,3,24
1,2,3,4,5
示例使用/输出
$ ./bin/read2020max dat/2020max.txt
1 12 5 14 0
4 6 2 3 24
1 2 3 4 5
仔细检查一下,如果您还有其他问题,请告诉我。
假设数据格式正确,用fgets()
读取一行,然后通过strtol()
解析它
#define COL_MAX 20
#define ROW_MAX 20
#define CHAR_PER_INTEGER (sizeof(long)*CHAR_BIT/3 + 3)
#define LINE_MAX (ROW_MAX * (CHAR_PER_INTEGER + 1) + 2)
long matrix[ROW_MAX][COL_MAX] = {0}; // better to use named constants than magic numbers
int col = 0;
int row;
// for (int i=0; i<19; i++){ Not to 19, but 20
for (row=0; row<ROW_MAX; row++){
char line[LINE_MAX*2]; // Generous buffer, but not insane size
if (fgets(line, sizeof line, be) == NULL)) {
break; // No more lines
}
char *s = line;
for (int j=0; j<COL_MAX; j++){
char *endptr;
errno = 0;
long value = strtol(s, &endptr, 10);
// no conversion, overflow, unexpected next character
if (s == endptr || errno || (*endptr != ',' && *endptr != '\n')) {
fprintf(stderr, "Invalid input <%s>\n", line);
exit(EXIT_FAILURE);
}
matrix[row][j] = value;
if (*endptr == '\n') { // no more in this line
col = j + 1;
break;
}
s = endptr + 1; // advance past the ','
}
}
// Use row*col portion of the matrix.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.