C: запись следующего кода в функции - PullRequest
2 голосов
/ 21 декабря 2010

Уважаемые уважаемые программисты.Пожалуйста, не могли бы вы мне помочь (снова), как добавить следующий код в функции для моей программы.Я читал в Интернете и понимаю, как работают функции, но когда я делаю это сам, все становится грушевидным / неправильным (я такой нуб).Не могли бы вы помочь с тем, как, например, написать приведенный ниже код в функции. (Например, открытие входного файла).


Мой исходный код выглядит так:

main (int argc, char **argv)
{
 int bytes_read, bytes_written;
 struct stat inode;
 int input_fd, output_fd;
 char buffer[64];
 int eof = 0;
 int i;

 /* Check the command line arguments */
 if (argc != 3) 
 {
   printf("syntax is:         %s \n", <fromfile> <tofile>\n", argv[0]);
  exit (1);
 }

 /* Check the input file exists and is a file */
 if ((stat(argv[1], &inode) == -1) || (!S_ISREG(inode.st_mode)))
 {
  printf("%s is not a file\n", argv[1]);
  exit(2);
 }

 /* Check that the output file doesnt exist */
 if (stat(argv[2], &inode) != -1)
 {
  printf("Warning: The file %s already exists. Not going to overwrite\n", argv[2]);
  exit(2);
 }

 /* Open the input file for reading */
 input_fd = open(argv[1], O_RDONLY, 0);
 if (input_fd == -1)
 {
  printf("%s cannot be opened\n", argv[1]);
  exit(3);
 }

 output_fd = open(argv[2], O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
 if (output_fd == -1)
 {
  printf("%s cannot be opened\n", argv[2]);
  exit(3);
 }

 /* Begin processing the input file here */
 while (!eof)
 {
  bytes_read = read(input_fd, buffer, sizeof(buffer));

  if (bytes_read == -1)
  {
   printf("%s cannot be read\n", argv[1]);
   exit(4);
  }

  if (bytes_read > > 0)
  {
   bytes_written = write(output_fd, buffer, bytes_read);
   if (bytes_written == -1)
   {
    printf("There was an error writing to the file %s\n",argv[2]);
    exit(4);
   }

   if (bytes_written != bytes_read)
   {
    printf("Devistating failure! Bytes have either magically appeared and been written or dissapeard and been skipped.  Data is inconsistant!\n");
    exit(101);
   }
  } 
  else
  {
   eof = 1;
  }
 }
   close(input_fd);
 close(output_fd);

}

Моя попытка открыть выходной файл:

void outputFile(int argc, char **argv)
{   
    /* Check that the output file doesnt exist */

    if (stat(argv[argc-1], &inode) != -1)
    {
        printf("Warning: The file %s already exists. Not going to overwrite\n", argv[argc-1]); 
        return -1;
    }

    /*Opening ouput files*/

    file_desc_out = open(argv[i],O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
    if(file_desc_out == -1)
    {
        printf("Error: %s cannot be opened. \n",argv[i]);           //insted of argv[2] have pointer i. 
        return -1;
    }
}

Любая помощь в том, как бы я сейчас ссылался на это в моей программе, ценится, спасибо.Я попробовал: ouputfile (но я не могу понять, что здесь и почему).

Ответы [ 3 ]

4 голосов
/ 21 декабря 2010

Может быть, самая полезная функция для вас:

#include <stdio.h>
#include <stdarg.h>

extern void error_exit(int rc, const char *format, ...);  /* In a header */

void error_exit(int rc, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    exit(rc);
}

Вы можете написать:

if (stat(argv[2], &inode) != -1)
    error_exit(2, "Warning: The file %s exists. Not going to overwrite\n",
              argv[2]);

Что имеет смысл краткости.

Вы пишете функции для выполнения подзадач. Решить, где разбить ваш код на функции, сложно - столько же, сколько наука. Ваш код не настолько велик, что просто ужасно оставлять его как есть - одну функцию (хотя обработку ошибок можно упростить, как указано выше).

Если вы хотите попрактиковаться в написании функций, рассмотрите возможность его разделения:

  • open_input_file()
  • open_output_file()
  • checked_read()
  • checked_write()
  • checked_close()

Эти функции позволят записать ваш основной код в виде:

int main(int argc, char **argv)
{
    int bytes_read;
    int input_fd, output_fd;
    char buffer[64];

    if (argc != 3) 
         error_exit(1, "Usage: %s <fromfile> <tofile>\n", argv[0]);

    input_fd  = open_input_file(argv[1]);
    output_fd = open_output_file(argv[2]);

    while ((bytes_read = checked_read(input_fd, buffer, sizeof(buffer)) > 0)
        check_write(output_fd, buffer, bytes_read);

    checked_close(input_fd);
    checked_close(output_fd);
    return 0;
}

Поскольку вы убрали обработку ошибок с глаз долой, теперь гораздо проще увидеть структуру программы. Если у вас еще недостаточно функций, вы можете похоронить цикл в функции void file_copy(int fd_in, int fd_out). Это удаляет больше беспорядка из main() и оставляет вас с очень простым кодом.


При первоначальной попытке функции открыть выходной файл:

void outputFile(int argc, char **argv)
{   
    /* Check that the output file doesnt exist */

    if (stat(argv[argc-1], &inode) != -1)
    {
        printf("Warning: The file %s already exists. Not going to overwrite\n", argv[argc-1]); 
        return -1;
    }

    /*Opening ouput files*/

    file_desc_out = open(argv[i],O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
    if(file_desc_out == -1)
    {
        printf("Error: %s cannot be opened. \n",argv[i]);           //insted of argv[2] have pointer i. 
        return -1;
    }
}

Критика:

  • Вы должны определить переменные, используемые функцией в функции (вам нужно как можно больше избегать глобальных переменных, и в этом коде нет вызова для любой глобальной переменной).
  • Вы должны определить тип возвращаемого значения. Вы открываете файл - как дескриптор файла будет возвращен вызывающему коду? Итак, тип возвращаемого значения должен быть int.
  • Вы передаете только информацию, необходимую для функции - простая форма «сокрытия информации». В этом случае вам нужно только передать имя файла; информация о режимах файлов и тому подобном подразумевается в названии функции.
  • В общем, вы должны решить, как обрабатывать ошибки. Если у вас нет других указаний от вашего сеттера, разумно выйти с ошибкой с соответствующим сообщением. Если вы возвращаете индикатор ошибки, то вызывающий код должен проверить его и решить, что делать с ошибкой.
  • Ошибки и предупреждения должны быть записаны в stderr, а не в stdout. Основной вывод программы (если есть) идет в stdout.
  • Ваш код не понимает, является ли argv[i] или argv[argc-1] именем выходного файла. В некотором смысле эта критика не имеет значения, когда вы передаете только имя файла функции. Однако согласованность является основным достоинством в программировании, и использование одного и того же выражения для определения одного и того же обычно является хорошей идеей.
  • Согласованность макета также важна. Не используйте в своих программах if( и if (; используйте каноническое обозначение if (, используемое отцами-основателями языка, K & R.
  • Аналогичным образом, не допускайте пробелов перед запятыми, пробелов после запятой и совместите с пробелами вокруг операторов, таких как '|'. Последовательность делает ваш код легче для чтения, и вы будете читать его гораздо чаще, чем пишете (по крайней мере, после того, как вы закончите курс, вы будете читать больше, чем писать).
  • Вы не можете иметь return -1; внутри функции, которая не возвращает значения.

Когда вы разбиваете код на функции, вам нужно скопировать / переместить извлекаемые абзацы кода, оставив после себя вызов новой функции. Вам также необходимо скопировать соответствующие локальные переменные из вызывающей функции в новую функцию - возможно, исключив переменные в вызывающей функции, если они там больше не используются. Вы компилируете с большинством включенных предупреждений, не так ли? Вы хотите знать о неиспользуемых переменных и т. Д.

Когда вы создаете новую функцию, одной из наиболее важных частей является определение правильной сигнатуры функции.Это возвращает значение?Если да, то какое значение и каков его тип?Если нет, то как он обрабатывает ошибки?В этом случае вы, вероятно, захотите, чтобы функция выручилась (завершила программу), если она сталкивается с ошибкой.В больших системах вам может потребоваться последовательно возвращать индикатор ошибки (0 означает успех, отрицательный означает сбой, разные отрицательные значения указывают на разные ошибки).Когда вы работаете с функцией, которая возвращает индикатор ошибки, почти всегда важно проверять индикаторы ошибок в вызывающем коде.Для больших программ большие участки кода могут быть связаны с обработкой ошибок.Точно так же вам нужно выяснить, какие значения передаются в функцию.

Я опускаю советы о таких вещах, как «будьте верны», как излишний для вашего этапа обучения программированию на C.

1 голос
/ 21 декабря 2010

вы, кажется, на самом деле понимаете, как сделать функцию.сделать функцию действительно не так сложно.Во-первых, вы должны понимать, что функция имеет тип.другими словами, argc имеет тип int, а argv имеет тип char *, ваша функция (в настоящее время) имеет тип void.void означает, что он не имеет значения, что означает, что когда вы возвращаете, вы ничего не возвращаете.похоже, вы хотите вернуть интергер.поэтому вы должны изменить верх с void outputfile(...) на int outputfile(...).

, затем ваша функция должна вернуться.он не будет компилироваться, если есть обстоятельства, когда он не вернется (кроме бесконечных циклов).так что в самом низу, если ошибок не произойдет, это дойдет до конца.так как вы больше не используете «void» в качестве возвращаемого типа, вы должны вернуть что-то до конца функции.поэтому я предлагаю поставить return 1;, чтобы показать, что все прошло отлично

1 голос
/ 21 декабря 2010

Есть несколько вещей.

Тип возвращаемого значения функции не тот, который вам нужен.Вы либо хотите вернуть дескриптор файла или код ошибки.IIRC, файловый дескриптор неотрицательный int, поэтому вы можете использовать тип возврата int вместо void.Вам также необходимо вернуть что-либо по любому пути, либо -1, либо file_desc_out.

Вы, вероятно, не хотите передавать аргументы командной строки в целом, а скорее что-то вроде argv[argc - 1].В этом случае аргумент должен быть что-то вроде char * filename, а не argc / argv, который он имеет сейчас.(Обратите внимание, что argv[i], который вы получили в последнем printf, почти наверняка неверен.)

Это означает, что это будет называться как

int file_desc_out = outputFile(argv[argc - 1]);

Вам необходимо иметьвсе переменные, объявленные в функции, в частности inode и file_desc_out.

Наконец, добавьте дополнительный уровень отступа для кода внутри { и } самой функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...