#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
.
Наконец, сделайте дополнительный уровень отступов в коде внутри {
и }
самой функции.