C: запись следующего кода в функции

#c

#c

Вопрос:

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


Мой первоначальный код выглядит следующим образом:

 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], amp;inode) == -1) || (!S_ISREG(inode.st_mode)))
 {
  printf("%s is not a filen", argv[1]);
  exit(2);
 }

 /* Check that the output file doesnt exist */
 if (stat(argv[2], amp;inode) != -1)
 {
  printf("Warning: The file %s already exists. Not going to overwriten", 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 openedn", 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 openedn", 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 readn", 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 %sn",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], amp;inode) != -1)
    {
        printf("Warning: The file %s already exists. Not going to overwriten", 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 (но я тоже не могу понять, что здесь происходит и почему).

Комментарии:

1. Вы используете вызовы stat и низкого уровня и не знаете, как написать функцию?

2. Покажите нам, что у вас получилось, и мы дадим вам совет, как избежать грушевидной формы. Обычно мы не просто делаем домашнее задание для людей.

3. Но я не знаю, как выполнять функции, никаких советов о том, как я мог бы их выполнять. taskinoor да, я не знаю, как написать функцию, хотя я могу это сделать.

4. @donok: Если это домашнее задание, то вас научили писать функции, или информация каким-то образом доступна вам. Попробуй это. Напишите то, что у вас получилось выше, в виде функции и опубликуйте это. На самом деле не имеет значения, насколько сильно ты все испортил. Таким образом, мы увидим некоторые усилия с вашей стороны, и у нас будут конкретные вещи для критики.

5. @donok: Спасибо за сотрудничество с нами. У тебя здесь все должно получиться.

Ответ №1:

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

 #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], amp;inode) != -1)
    error_exit(2, "Warning: The file %s exists. Not going to overwriten",
              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], amp;inode) != -1)
    {
        printf("Warning: The file %s already exists. Not going to overwriten", 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 amp; R.
  • Аналогично, не допускайте пробелов перед запятыми, пробела после запятой и не допускайте пробелов вокруг операторов, таких как ‘ | ‘. Согласованность облегчает чтение вашего кода, и вы будете читать свой код намного чаще, чем писать его (по крайней мере, после окончания курса вы будете больше читать, чем писать).
  • Вы не можете иметь return -1; внутри функции, которая не возвращает значения.

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

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

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

Комментарии:

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

Ответ №2:

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

однако, если вы посмотрите на свой код, вы делаете return -1 . похоже, вы хотите вернуть промежуточное значение. поэтому вам следует изменить начало с void outputfile(...) на int outputfile(...) .

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

Ответ №3:

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

Тип возвращаемого значения функции — это не то, что вы хотите. Вы либо хотите вернуть файловый дескриптор, либо код ошибки. 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 .

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