Читать из любых данных - PullRequest
       36

Читать из любых данных

0 голосов
/ 01 ноября 2018

Я пытаюсь написать программу, которая позволяет любому имени файла (Makefile, 1.txt, abc.txt и т. Д.) Считывать вывод на экране. Кажется, что это работает, но вывести только одну строку из большинства 10 строк из любых файлов.

/**
 * Get a filename from the command line or print "Usage: p6 <filename>\n" if it
 * is not provided and exit.  Use fopen(3) to open the file for reading. Then 
 * use fgets(3) to read at most 10 lines from the file and print them out to the
 * console.  You may assume that a line of text will not exceed 4096 characters.
 * Example input/output:
 * ./p6 Makefile 
 * CC=gcc
 * 
 * PROGS=p1 p2 p3 p4 p5 p6 p7 p8 p9 p10
 * 
 * # Linux defaults:
 * CFLAGS=-ggdb -pedantic -Wall
 * #CFLAGS=-O4 -Wall
 * LDFLAGS=-s
 * 
 * all:    $(PROGS)
 */
#include <stdio.h>
int main (int argc, char *argv[])
{
  if (argc < 2)
    {
      printf ("Usage: p6 <filename>\n");
    }

    FILE *fp;
    char str[60];

    /* opening file for reading */
    fp = fopen ("Makefile", "r"); //In the instruction says Makefile
    // When I run check command, I must use       
    //"/u1/lecture/instructor/.check/text/1.txt" for ".check" file

    if (fgets (str, 10, fp) != NULL)
      {
  puts (str);
      }
    fclose (fp);

    return (0);
  }

ВЫВОД:

> p6:
> -2.5 output of program (p6) is not correct for input      '/u1/lecture/instructor/.check/text/1.txt':
> ------ Yours: ------ 
> man(1) General Commands Manual man(1)
> 
> ---- Reference: ---- 
> man(1) General Commands Manual man(1)
> 
> NAME
>        man - format and display the on-line manual pages
> 
> SYNOPSIS
>        man [-acdfFhkKtwW] [--path] [-m system] [-p string] [-C config_file]
>        [-M pathlist] [-P pager] [-B browser] [-H htmlpager] [-S section_list]
>        [section] name ...
> 
> --------------------

Для операционной системы я использую KDE Linux System, предоставленный CS Instructor.

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Вы делаете проблемы немного сложнее, чем нужно, сосредоточившись на слове Makefile. Это красная сельдь. Один из примеров, который вам дали, просто напечатал первые десять строк Make-файла. Это не имеет никакого отношения к написанию вашего кода, чтобы просто вывести первую десятую строку из любого имени файла, которое вы указываете в командной строке для чтения. Вы можете делать то же самое и использовать Makefile в качестве входных данных для вашей программы, но помимо этого выбора входного файла, это не имеет отношения к рассматриваемой проблеме.

Просматривая существующий код, вы в основном правильно подобрали базовый подход, однако вам не хватает обработки ошибки, если if (argc < 2). Вы должны сделать больше, чем просто напечатать оператор, вы должны обработать ошибку, вернув управление оболочке (например, return 1;), чтобы ваша программа не пыталась обработать данные из файла, который никогда не будет открыт.

В противном случае, ваша логика для печати строк не за горами. Следующее делает именно это, также выводя номер строки, отображаемый перед отображением строки, а затем отображая итоговое значение для количества строк, отображаемых в конце, например,

#include <stdio.h>

#define MAXC 4096   /* if you need a constant, #define one (or more) */
#define NLINES 10   /* number of lines to read */

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

    char line[MAXC];    /* buffer to hold each line */
    size_t ndx = 0;
    FILE *fp = NULL;

    if (argc < 2) { /* validate adequate number of arguments */
        fprintf (stderr, "error: insufficient input.\n"
                         "usage: %s <filename>\n", argv[0]);
        return 1;
    }
    /* open file / validate file open for reading */
    if ((fp = fopen (argv[1], "r")) == NULL) {
        perror ("fopen(argv[1],\"r\")");
        return 1;
    }

    /* read/output each line while ndx < NLINES */
    while (ndx < NLINES && fgets (line, MAXC, fp))
        printf ("line[%2zu]: %s", ndx++ + 1, line);

    printf ("\ntotal lines read: %zu\n", ndx); /* print total lines */

    fclose (fp);
}

Компиляция вашего кода

Всегда включайте предупреждения компилятора и позвольте компилятору помочь вам исправить ваш код. Чтобы включить предупреждения, добавьте -Wall -Wextra в строку компиляции gcc или clang. (добавьте -pedantic для нескольких дополнительных предупреждений). Для clang вместо этого вы можете использовать -Weverything. Для VS (cl.exe при windoze) добавьте /W3 (или используйте /Wall, но вы получите довольно много посторонних предупреждений, не связанных с кодом). Прочитайте и поймите каждое предупреждение. Они будут определять любые проблемы и точную линию, на которой они возникают. Не принимать код, пока он не скомпилируется без предупреждения . Вы можете многому научиться в Си, просто слушая, что ваш компилятор пытается вам сказать.

Пример входного файла

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

Пример использования / Вывод

$ ./bin/tenlines dat/captnjack.txt
line[ 1]: This is a tale
line[ 2]: Of Captain Jack Sparrow
line[ 3]: A Pirate So Brave
line[ 4]: On the Seven Seas.

total lines read: 4

Файл с более чем 10 строками:

$ ./bin/tenlines dat/structaddrout.txt
line[ 1]:  K1, K2      720 Eucalyptus Ave 105    Inglewood, CA           89030
line[ 2]:  O1, O2      7659 Mckinley Ave         Los Angeles, CA         90001
line[ 3]:  G1, G2      20253 Lorenzana Dr        Los Angeles, CA         90005
line[ 4]:  N1, N2      20044 Wells Dr            Beverly Hills, CA       90210
line[ 5]:  H1, H2      5241 Del Moreno Dr        Los Angeles, CA         91110
line[ 6]:  F1, F2      20225 Lorenzana Dr        Los Angeles, CA         91111
line[ 7]:  C1, C2      5142 Dumont Pl            Azusa, CA               91112
line[ 8]:  J1, J2      5135 Quakertown Ave       Thousand Oaks, CA       91362
line[ 9]:  M1, M2      4819 Quedo Pl             Westlake Village, CA    91362
line[10]:  E1, E2      4851 Poe Ave              Woodland Hills, CA      91364

total lines read: 10

Вы можете так же легко включить Makefile, как и файл для чтения (это просто текст), для чего это стоит.

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 01 ноября 2018

следующий предложенный код:

  1. чисто компилирует
  2. правильно проверяет и обрабатывает ошибки
  3. выполняет желаемую функциональность
  4. избегает «магических» чисел, давая им значимые имена
  5. выходит из программы с соответствующим возвращаемым значением при возникновении ошибки

и теперь предложенный код:

#include <stdio.h>    // fopen(), fclose(), fgets(), fprintf(), printf(), perror()
#include <stdlib.h>   // exit(), EXIT_FAILURE

#define MAX_LINE_LEN 4096
#define MAX_LINES    10

int main (int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf ( stderr, "Usage: %s <filename>\n", argv[0]);
        exit( EXIT_FAILURE );
    }

    char buffer[ MAX_LINE_LEN ];

    /* opening file for reading */
    FILE *fp = fopen ( argv[1], "r"); //In the instruction says Makefile
    if( !fp )
    {
        perror( "fopen failed" );
        exit( EXIT_FAILURE );
    }

    int i = 0; 
    while( (i<MAX_LINES) && (fgets ( buffer, sizeof( buffer ), fp)) )
    {
        printf( "%s", buffer );
        i++;
    }
    fclose (fp);

    return (0);
  }

Выполнение кода, в котором не задан параметр командной строки:

./untitled
Usage: ./untitled <filename>

Выполнение кода с допустимым именем файла:

./untitled untitled.c
#include <stdio.h>
#include <stdlib.h>

#define MAX_LINE_LEN 4096
#define MAX_LINES    10

int main (int argc, char *argv[])
{
    if (argc != 2)
    {

Выполнение кода с несуществующим именем файла:

./untitled nonexistent.txt
 fopen failed: No such file or directory
...