Вы «Танцуете на наземной мине» и заигрываете с Неопределенное поведение , объединяя текст без проверки, достаточно ли символов в filename
перед вызовом strcat
.Что делать, если пользователь вводит 26 символов filename
(или более)?(подсказка: неопределенное поведение)
Это усугубляется тем фактом, что вы используете gets
для ввода.gets
настолько небезопасен и подвержен переполнению буфера, что был полностью удален в C11.Если ваш профессор предлагает использовать gets
- обратитесь к другому профессору.См .: Почему get () настолько опасен, что его никогда не следует использовать!
Вместо этого используйте fgets
или POSIX getline
, чтобы прочитать filename
, защищая границы ваших массивов с помощью fgets
или динамически выделяя столько памяти, сколько необходимо для filename
в случае getline
.
Все линейно-ориентированный ввод функции, такие как fgets
и getline
read и включают завершающий '\n'
в буферах, которые онизаполнить.Вам просто нужно обрезать '\n'
от конца строки.Вы можете сделать это путем получения длины с помощью strlen
и установки buffer[strlen(buffer) - 1] = '\0';
или с помощью функции strcspn
, которая обеспечивает немного больше функциональности за один вызов.
В целом, вы можете сделать что-то подобноек следующему (это просто выводит вызов fopen
вместо фактического открытия файла):
#include <stdio.h>
#include <string.h>
#define MAXC 30 /* if you need a constant, #define one (or more) */
#define FEXT ".txt" /* (including string constants) */
int main (void) {
char filename[MAXC];
size_t available = MAXC - 1, /* chars available in filename */
length = 0,
extlen = strlen (FEXT);
FILE *fp;
fputs (" Enter the filename: ", stdout); /* no conversion needed */
if (!fgets (filename, MAXC, stdin)) {
fputs ("(user canceled input)\n", stderr);
return 1;
}
/* trim '\n' from end of filename saving length using strcspn() */
filename[(length = strcspn (filename, "\r\n"))] = 0;
if (available - length < extlen) {
fprintf (stderr, "error: insufficient space available for '%s'.\n",
FEXT);
return 1;
}
strcat (filename, FEXT);
/* just output what would be done */
printf ("fp = fopen (\"e:\\%s\",\"a+\");\n", filename);
}
Пример использования / Вывод
В примере просто выводится то, чтоон откроется (а не будет фактически открывать файл), например,
$ ./bin/strcatext
Enter the filename: my_file_to_open
fp = fopen ("e:\my_file_to_open.txt","a+");
, а затем проверит, что ваш код примет имя файла из 25 символов плюс расширение из 4 символов, например,
$ ./bin/strcatext
Enter the filename: 1234567890123456789012345
fp = fopen ("e:\1234567890123456789012345.txt","a+");
И отклоняет 26-символьное имя файла, например,
$ ./bin/strcatext
Enter the filename: 12345678901234567890123456
error: insufficient space available for '.txt'.
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.