我试图以4X4格式显示输出。程序接收文本文件的名称,然后获取文本文件中的值并存储在2D数组中。然后稍后像这样显示它们
7 2 4 5
5 2 6 4
2 2 5 5
9 2 4 5
但问题是,它没有那样显示,我不确定它是不是我的循环或什么。有任何想法吗。它运行良好,没有错误,但数字显示不正确。这是我的代码
int main () {
int i = 0;
int j = 0;
int value = 0;
int a[4][4];
char ch, file_name[100];
FILE *fp;
printf("Enter file name?");
gets(file_name);
fp = fopen("file.txt", "r");
if (fp == NULL)
{
perror("Error \n");
}
else
{
// printf("\n");
while (!feof(fp) && fscanf (fp, "%d ", &value))
{
a[i][j] = value;
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
printf("%d ",a[i][j] );
}
printf("\n");
}
}
}
fclose(fp);
return 0;
}
答案 0 :(得分:1)
您的代码会遇到各种问题,因为您正在混合读取输入的代码和在一个while
循环中写入输出的代码。
分隔读取输入的代码和创建输出的代码。理想情况下,将它们放入不同的功能中。
将函数声明为:
void readData(FILE* in, int a[4][4]);
void writeData(FILE* out, int a[4][4]);
将它们用作:
int main()
{
int a[4][4];
// Your code to open the file.
readData(in, a);
writeData(stdout, a);
}
将它们实施为:
void readData(FILE* in, int a[4][4])
{
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
if ( fscanf(in, "%d", &a[i][j]) != 1 )
{
printf("Unable to read an array element.\n");
exit(0);
}
}
}
}
void writeData(FILE* out, int a[4][4])
{
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
fprintf(out, "%d ", a[i][j]);
}
fprintf(out, "\n");
}
}
答案 1 :(得分:0)
好吧,让我们一次把你的问题分开。首先,代码中关于输入和尝试输出的显着部分:
int i = 0;
int j = 0;
int value = 0;
int a[4][4];
...
while (!feof(fp) && fscanf (fp, "%d ", &value))
{
a[i][j] = value;
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
printf("%d ",a[i][j] );
}
printf("\n");
}
}
在我们查看!feof
问题之前。让我们看一下循环结构的整体逻辑。当您输入while
循环时,i = j = 0;
的值。假设您的文件是打开的并且有一个要读取的整数,您将使用文件中的第一个整数填充value
,然后将该值分配给数组的第一个元素:
a[i][j] = value;
现在,您已在a[0][0]
存储了1个整数。 (a
中的所有其他值都是未初始化和不确定)令人费解的是,您然后尝试输出整个数组,...未初始化的值以及所有数据。
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
printf("%d ",a[i][j] );
}
printf("\n");
}
尝试访问未初始化的值会调用未定义的行为(从首次尝试阅读a[0][1]
开始,您的程序完全不可靠)。它似乎可以正常运行,也可以SegFault
或其间的任何内容。
在开始迭代输出值的数组中的索引之前,您需要完成对所有值的读取。
但等等......还有更多...如果你没有SegFault,当你完成for
循环时,i
&amp;的价值是多少? j
现在?在i
和j
4
之前,您的循环才会完成,因此这些是while
循环第一次迭代结束时的值。< / p>
现在让我们进入while
循环的下一次迭代。假设您正在读取的文件中有两个整数值,则将第二个整数读入value
。 接下来会发生什么?你自己一个人。通过尝试读取15个未初始化的值a[0][1] -> a[3][3]
已经15次调用未定义的行为后,您尝试使用以下内容写入a
的范围:
a[4][4] = value; /* remember what i & j are now? */
然后,您再次点击for
循环...,a[0][1]
保持唯一有效初始化的值并重复循环。
但是等等......还有更多...在读完文件中的最后一个整数后,最后一次到达while
循环的开头:
while (!feof(fp) && fscanf (fp, "%d ", &value))
您测试!feof(fp)
并且未设置EOF
,因为您的上一次读取是对使用最后一个数字完成的最后一个整数的有效读取,并且没有触发流错误,因此您继续fscanf (fp, "%d ", &value)
现在返回EOF
(例如-1
),但由于您只是测试fscanf(..)
,-1
是否测试 TRUE 所以关闭你再循环整个循环体,至少再调用16次未定义的行为。
您是否开始理解为什么输出可能不是您想要的?
你已经对如何进行阅读和打印有了一个很好的答案。我将提供一种不使用任何功能的替代方案,因此它可以帮助您更好地遵循逻辑。以下代码仅从作为第一个参数给出的文件名中读取,或者如果没有给出参数则默认从stdin
读取。代码验证文件指针指向一个打开以供阅读的文件,然后输入一个while
循环,一次读取一个整数&array[rows][cols]
fscanf
}和验证 fscanf
的返回是1
。其他任何事情都被视为失败。
读取循环的其余部分只增加cols
,直到达到NCOLS
(此处4
- 是每行的列数),然后增加行数rows
并将列索引cols
设置为零。
在输出以确保NROWS
整数被读取之前执行最终的验证,并且在读取循环的最后一次迭代期间cols
被设置为零。然后输出array
的内容。代码非常简单:
#include <stdio.h>
#define NROWS 4
#define NCOLS NROWS
int main (int argc, char **argv) {
int array[NROWS][NCOLS] = {{0}}, /* declare and intialize array */
rows = 0, cols = 0; /* rows / columns index */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* validate no more than NROWS of NCOLS integers are read */
while (rows < NROWS && fscanf (fp, "%d", &array[rows][cols]) == 1) {
cols++; /* increment column */
if (cols == NCOLS) { /* if row full */
rows++; /* increment rows */
cols = 0; /* zero columns */
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
if (rows != NROWS || cols) { /* validate rows = NROWS & cols = 0 */
fprintf (stderr, "error: read only %d rows and %d cols.\n",
rows, cols);
return 1;
}
for (int i = 0; i < NROWS; i++) { /* output stored values */
for (int j = 0; j < NCOLS; j++)
printf (" %2d", array[i][j]);
putchar ('\n');
}
return 0;
}
(你已经被告知不要使用容易缓冲区溢出的gets
,因此不安全它已经完全从C11库中移除。如果你的教授继续建议使用它 - 去找一个新教授)
示例输入文件
$ cat dat/arr2dfscanf.txt
7 2 4 5
5 2 6 4
2 2 5 5
9 2 4 5
示例使用/输出
$ ./bin/arr2dfscanf <dat/arr2dfscanf.txt
7 2 4 5
5 2 6 4
2 2 5 5
9 2 4 5
另请注意,通过以这种方式阅读fscanf
,输入所处的格式无关紧要 - 只要它是所有整数值。这将产生相同的输出:
$ echo "7 2 4 5 5 2 6 4 2 2 5 5 9 2 4 5" | ./bin/arr2dfscanf
仔细看看,如果您有其他问题,请告诉我。