如何使用二维数组使用c代码查找文件的尾部

时间:2016-01-17 14:30:29

标签: c arrays

我想使用 c 程序打印文件的最后n行。 我已经使用了fseek的方法。现在,我想通过使用数组来尝试它。我编写了代码,但它给出了分段错误(核心转储)错误。

请帮助修改此代码:

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

char s[10][100];

int main(int argc, char *argv[])
{
    FILE *in, *out;
    int count = 0;
    long pos;
    char c;

    if ((in = fopen("count.txt", "r")) == NULL)
    {
        perror("fopen");
        exit(EXIT_FAILURE);
    }
    if ((out = fopen("output.txt", "w")) == NULL)
    {
        printf("error in opening file");
        exit(EXIT_FAILURE);
    }

    if (argc < 2)
        fprintf(stderr, "Arguments which is to be passed should be 2\n");
    else if (argc > 2)
        printf("too many argumnets are passed");
    else
    {
        int n = atoi(argv[1]);
        if(n >= 1 &&  n< 100)
        {
            int j,i;
            for(i=0;i<=n;i++)
            {   
                j=0;
                c = fgetc(in);
                for (; j != EOF; ++j)
                {
                    s[i][j]=c;
                    fputc(c, out);
                    c = fgetc(in);
                    if(s[i][j]=='\n')
                        break;
                 }
            if(s[i][j] != EOF && i== n)
               i=0;
         }
         for (i = 0; i <= n; i++)
            for (j = 0; s[i][j] != '\n'; j++)
                 printf("%c", s[i][j]);
           }
           else
          printf("renter the value of n");
       }
        fclose(in);
        fclose(out);
        return 0;
     }

2 个答案:

答案 0 :(得分:1)

以下是您可以查看的一些问题:

  1. char s[10][100];查看尺寸是否与您使用s的方式相符:s[i][j]=c;
  2. for(i=0;i<=n;i++)您打印n或n + 1行吗?
  3. while (j != EOF)在循环内,您未从文件中设置j
  4. 另外:以下任务可能弊大于利:

            if(s[i][j] != EOF && i== n)
               i=0;
    

答案 1 :(得分:0)

虽然您可以使用面向字符的输入函数自由地读取一个字符行,但您的工作有点比它需要的更困难。 C提供了几个提供面向行的输入的函数(例如fgetsgetline),这些函数更适合于读取文本 line-at-a-时间

出于您的目的,您似乎需要读取/存储所有输入行,然后根据用户给定的数字(例如'n'),写入/显示最后'n'行输入到你给定的输出文件。虽然动态分配存储以容纳无限数量的行或字符并不需要花费太多精力,但下面我们将使用静态声明的数组,其最大行数为MAXL,每行最多包含MAXC字符数。 MAXLMAXC将是使用匿名 enum指定的代码的常量。使用enum的替代方法是将#define作为常量。

您可以轻松地将该信息作为参数传递给您的程序,而不是硬编码文件名和要显示的行数,而是利用getopt来选择要显示的结束(或尾部)行的数量。任何剩余的参数都将被视为输入/输出文件名(如果没有提供其他文件名作为参数,则使用stdinstdout作为默认值。

下面,两个辅助函数xfopenprocessopts仅用于将fopen的错误检查和getopt的选项处理移动到函数中以保持主体代码可读。

使用面向行的输入极大地简化了array中行的读取和存储。 面向行的输入函数的唯一转折是它们读取并包含尾随'\n'(换行符)字符作为其输入的一部分。这意味着您唯一的附加任务是删除尾随'\n',只需使用 nul-terminatedating 字符'\0'(或简称为0)覆盖它。因此,当使用fgets阅读行时,您通常会看到类似于:

的内容
while (fgets (array[idx], MAXC, ifp)) /* read each line of input */
{   
    size_t len = strlen (array[idx]); /* get length - used below */

    while (len && (array[idx][len-1] == '\r' || array[idx][len-1] == '\n'))
        array[idx][--len] = 0;  /* strip trailing '\r' & '\n' */

    if (++idx == MAXL) {    /* test if line limit reached */
        fprintf (stderr, "warning: MAXL lines read.\n");
        break;
    }
}

其中只是将一行信息读入缓冲区array[idx],包括文件流中最多MAXC个字符(包括 nul-terminatedating 字符){{ 1}}。使用ifp找到字符串读取的长度,然后使用长度作为索引向后工作strlen(或Windows上的'\n')将被 nul-terminated覆盖字符。最后,行索引'\r\n'递增并针对常量idx进行测试,以确保您不会超出数组的末尾。 (如果数组是动态分配的,那么你可以MAXL

这实际上就是面向行的输入所需的全部内容。只需通过每次调用realloc一次,然后删除行结尾(您可以执阅读等等。与此讨论无关 - 此处超过fgets个字符的行的任何部分都将被简单地读作下一行。)

将所有部分组合在一起,您可以执行以下操作:

MAXC

输入文件

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

enum { MAXL = 64, MAXC = 128 }; /* constants for max lines and max chars */

FILE *xfopen (const char *fn, const char *mode); /* helper for fopen */
void processopts (int argc, char **argv, size_t *nlines, FILE **ifp, FILE **ofp);

int main (int argc, char **argv) {

    char array[MAXL][MAXC] = enter image description here; /* array to hold MAXL strings */
    size_t i, idx = 0, nlines = 0;  /* index, num lines to print  */
    FILE *ifp, *ofp;

    processopts (argc, argv, &nlines, &ifp, &ofp);  /* handle option */

    while (fgets (array[idx], MAXC, ifp)) /* read each line of input */
    {   
        size_t len = strlen (array[idx]); /* get length - used below */

        while (len && (array[idx][len-1] == '\r' || array[idx][len-1] == '\n'))
            array[idx][--len] = 0;  /* strip trailing '\r' & '\n' */

        if (++idx == MAXL) {    /* test if line limit reached */
            fprintf (stderr, "warning: MAXL lines read.\n");
            break;
        }
    }
    if (ifp != stdin) fclose (ifp); /* close inputfile */

    if (nlines >= idx) nlines = 0;  /* validate nlines */

    if (nlines) {   /* tail only nlines lines */
        for (i = idx - nlines; i < idx; i++)
            fprintf (ofp, "%s\n", array[i]);
    }
    else {  /* print all lines */
        for (i = 0; i < idx; i++)
            fprintf (ofp, "%s\n", array[i]);    
    }
    if (ofp != stdout) fclose (ofp); /* close output fp  */

    return 0;
}

/* fopen with error checking */
FILE *xfopen (const char *fn, const char *mode)
{
    FILE *fp = fopen (fn, mode);

    if (!fp) {
        fprintf (stderr, "xfopen() error: file open failed '%s'.\n", fn);
        // return NULL;
        exit (EXIT_FAILURE);
    }

    return fp;
}

void processopts (int argc, char **argv, size_t *nlines, FILE **ifp, FILE **ofp)
{
    int opt;                        /* used with getopt to parse  */

    /* process '-n X' option to set number of tail lines */
    while ((opt = getopt (argc, argv, "n:")) != -1) {
        switch (opt) {
            case 'n':
                *nlines = atoi (optarg);
                break;
        }
    }
    /* infile/outfile are remaining args (default: stdin/stdout) */
    *ifp = argc > optind ? xfopen (argv[optind], "r") : stdin;
    *ofp = argc > optind + 1 ? xfopen (argv[optind + 1], "w") : stdout;
}

读取/写入所有stdin / stdout

$ cat dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

将最后2行记录到标准输出

$ ./bin/fgets_array_static_opt <dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

将最后3行记录到foo.txt

$ ./bin/fgets_array_static_opt <dat/captnjack.txt -n2
A Pirate So Brave
On the Seven Seas.

如果您有任何问题,请与我们联系。