"Я понимаю, как открыть файл, ..."
Нет, не совсем, одно из фундаментальных правил кодирования - это вы "Не жестко кодируйте имена файлов и не используйтеMagic-номер ". Это означает, что вы не хотите:
secretMessage = fopen("C://Users/anyah/Fall2019/ECE_114/GreatGatsby.txt", "r");
Передача аргументов в вашу программу - вот почему у вас есть аргументы для main()
, например
int main (int argc, char **argv)
Просто укажите имя файла для чтения какаргумент вашей программы (или прочитанный из stdin
по умолчанию). Для этого вы можете сделать что-то похожее на:
#include <stdio.h>
...
int main (int argc, char **argv) {
...
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
На данный момент вы закончили открывать файл (или читаете из stdin
), и у вас есть проверено что файловый поток открыт для чтения.
Чтобы хранить несколько слов без динамического выделения памяти, вам нужно будет использовать двумерный массив, где каждая строка содержит слово, а столбцы достаточны для хранения любогослово плюс символ , заканчивающийся нулями , поэтому массив символов в этой строке можно рассматривать как строку. Самое длинное немедицинское слово в словаре Unabridged составляет 29 символов (поэтому подойдет общее количество столбцов, равное 30, но следующая степень двойки 32
в порядке)
Так как вы не используете магические числа в своем коде, #define
одну (или более) константу по мере необходимости. Вы можете использовать глобальный enum
, чтобы выполнить то же самое. Чтобы обеспечить хранение 128 слов из 31 символа или менее, вы можете сделать:
/* if you need a constant, #define one (or more) */
#define ROWS 128 /* max no. of words to read */
#define COLS 32 /* max no. of chars per-word */
...
char words[ROWS][COLS] = {""}; /* 2D array to hold words */
С открытым файлом и объявленным хранилищем для хранения ваших слов, теперь вы просто читаете каждый символ с fgetc
(или читаетестрока с fgets
) и собирать символы до тех пор, пока не будут найдены '_'
, '\n'
или EOF
. Чтобы защитить границы массива words
, убедитесь, что вы пытаетесь заполнить не более ROWS
слов. Для каждого слова вы защищаете границы столбцов, гарантируя, что вы читаете не более COL-1
символов (-1
, чтобы сэкономить место для символа , заканчивающегося нулем )
Соединяя это вместеи используя пару переменных счетчика, вы можете сделать:
while (row < ROWS) { /* while rows left in array */
int c, col = 0; /* character c, column counter */
/* loop over each char in word */
for (c = fgetc(fp); col < COLS - 1; col++, c = fgetc(fp)) {
if (c == EOF) /* if EOF jump out of nested loops */
goto done;
if (c == '_' || c == '\n') /* if char is '_' or '\n', get next */
break;
words[row][col] = c; /* assign char to current word */
}
words[row++][col] = 0; /* nul-terminate, advance word count */
}
done:; /* goto label to jump to */
( note: единственный прямой способ выпрыгнуть из вложенных циклов - использовать старый оператор goto
. Единственным ограничением является то, что вы не пытаетесь выпрыгнуть из функции, разбивая вложенные циклы - это нормально)
Полный пример может быть:
#include <stdio.h>
/* if you need a constant, #define one (or more) */
#define ROWS 128 /* max no. of words to read */
#define COLS 32 /* max no. of chars per-word */
int main (int argc, char **argv) {
char words[ROWS][COLS] = {""}; /* 2D array to hold words */
int row = 0, i; /* row (word) and loop counter */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (row < ROWS) { /* while rows left in array */
int c, col = 0; /* character c, column counter */
/* loop over each char in word */
for (c = fgetc(fp); col < COLS - 1; col++, c = fgetc(fp)) {
if (c == EOF) /* if EOF jump out of nested loops */
goto done;
if (c == '_' || c == '\n') /* if char is '_' or '\n', get next */
break;
words[row][col] = c; /* assign char to current word */
}
words[row++][col] = 0; /* nul-terminate, advance word count */
}
done:; /* goto label to jump to */
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (i = row-1; i >= 0; i--)
printf ((i != row - 1) > 0 ? " %s" : "%s", words[i]);
putchar ('\n');
}
Последний цикл просто выводит словав обратном порядке и троичный в операторе printf
просто гарантирует, что вы не печатаете пробел перед выводом первого слова.
Пример входного файла
$ cat dat/backwardsfleas.txt
cat_lucky_none_has_cat_my_fleas_has_dog_my
Пример использования / Вывод
$ ./bin/arrayrevwords dat/backwardsfleas.txt
my dog has fleas my cat has none lucky cat
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.