精确打印&从文件扫描(C)

时间:2014-12-14 23:29:40

标签: c arrays function char return

使用printArea()我想将一个数组打印到一个文件中, 使用scanArea()我想准确扫描这个文件并将其粘贴到我的数组中。

如果我做printArea()& scanArea()我应该得到与以前相同的结果?好吧,不。我有一些换行符。我的代码有什么想法吗?

int m = 0;
int n = 0;
int c = 0;

void printArea (int len, char p[][len])
{
FILE *out = fopen ("spielfeld.txt", "w");
for (int i = 0; i < len; i++)
{
    for (int j = 0; j < len; j++)
        fputc(p[i][j], out);
    fputc(10, out);
}
fclose(out);
}

int scanArea   (int len, char p[][len])
{
FILE *in = fopen ("spielfeld.txt", "r");

if (in == 0)
    return 1;
else
{
    while ((c=fgetc(in)) != EOF)
    {
        if ((c=fgetc(in)) == 10)
        {
            c++;
            m++;
            n = 0;
        }
            p[m][n] = (c=fgetc(in));
            n++;
    }
    return 0;
}
fclose(in);
}

呼叫:

int len;
len = 12;
char arr[len][len];

showArea (len, arr);
printArea(len, arr);
scanArea (len, arr);
showArea (len, arr);

第一和第二个showArea不同。

111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111

111111111111
1111
1111111
1111
1111111
1111
1111111
1111
1111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111

1 个答案:

答案 0 :(得分:0)

scanArea()中的主循环存在问题。目前:

while ((c=fgetc(in)) != EOF)
{
    if ((c=fgetc(in)) == 10)
    {
        c++;
        m++;
        n = 0;
    }
    p[m][n] = (c=fgetc(in));
    n++;
}

循环条件读取一个字符。 if语句立即读取下一个字符,抛弃第一个字符。然后你读了另一个角色来分配给阵列,也放弃了第二个角色。这意味着你跳过三分之二的字符。当它是换行符时,你也会增加c,这是奇怪的,没有意义。换行符应写为'\n'而不是10。

你需要一些不那么热衷于阅读角色的东西:

while ((c = fgetc(in)) != EOF)
{
    if (c == '\n')
    {
        m++;
        n = 0;
    }
    else
        p[m][n++] = c;
}

这仍然有点危险;它会将除换行符之外的任何数量的任何字符存储到数组中,而不用担心数组上的边界,无论是在一行还是在总行数上。但它不会跳过三分之二的数据。

在进一步审核时,我发现mnc显示为全局变量;它们应该是scanArea()的本地人。你应该尽可能避免使用全局变量。必要时,应在文件中将它们设为static,除非它们必须在源文件之间共享。然后,您需要遵循How do I use extern to share variables between source files中的指南,以确保一切都是一致的。

  

只有一个scanArea()mnc仅在那里使用。

然后没有理由让他们不在当地。实际上,如果你两次调用scanArea(),那么这些变量是全局的这一事实意味着在第二次调用时,索引将从一个超出界限的数组位置开始,并从此开始变得更糟。


工作代码

我创建函数static,直到确认需要它们在另一个源文件中可见。并非所有人都像我一样对此持肛门保护。

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

static void printArea(int len, char p[len][len])
{
    FILE *out = fopen("spielfeld.txt", "w");
    for (int i = 0; i < len; i++)
    {
        for (int j = 0; j < len; j++)
            putc(p[i][j], out);
        putc('\n', out);
    }
    fclose(out);
}

static int scanArea(int len, char p[len][len])
{
    FILE *in = fopen("spielfeld.txt", "r");

    if (in == 0)
        return 1;
    else
    {
        int m = 0;
        int n = 0;
        int c;
        while ((c = getc(in)) != EOF)
        {
            if (c == '\n')
            {
                m++;
                n = 0;
            }
            else if (n >= len || m >= len)
            {
                fprintf(stderr, "Accessing array out of bounds at p[%d][%d]\n", m, n);
                exit(1);
            }
            else
                p[m][n++] = c;
        }
    }
    fclose(in);
    return 0;
}

static void showArea(int len, char p[len][len])
{
    for (int i = 0; i < len; i++)
    {
        for (int j = 0; j < len; j++)
            putchar(p[i][j]);
        putchar('\n');
    }
}

int main(void)
{
    int len = 12;
    char arr[len][len];
    memset(arr, '1', len * len);

    puts("Before:");
    showArea(len, arr);
    printArea(len, arr);
    scanArea(len, arr);
    puts("After:");
    showArea(len, arr);
}

在Mac OS X 10.10.1(使用GCC 4.8.1编译)上运行时,我得到输出:

Before:
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
After:
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
111111111111
  

所有作品,除了我的第8行都是完全空白的,所以现在我有13行而不是12行。

我不能说明你的第8行。

我注意到文件名重复了;重复文件名之类的东西会导致错误。理想情况下,应该修改代码,以便读取和写入函数传递要使用的文件的名称,并且调用代码应该提供该名称。但是,这有点超出了当前问题的范围。

另请注意,如果showArea()被修改为采用文件流参数(void showArea(FILE *fp, int len, char p[len][len])并且I / O调用已被适当修改,那么printArea()中的代码可以修改为打开该文件,调用showArea(),然后关闭该文件。