В ответ на ваш вопрос и вопрос в комментарии определить размер строки и столбца довольно просто.Когда вы читаете строку массива из файла с fgets
, вы можете использовать strlen()
для определения количества символов (, но обратите внимание , он также содержит символ '\n'
- так что вы будетенужно вычесть одну - что вы можете сделать в сочетании с обрезкой '\n'
от конца)
После того, как вы прочитали первую строку и учли '\n'
, установите переменную, которая содержит числосимволы (столбцы) в вашем массиве.Поскольку вы знаете, что ваш массив является кубом, вы можете сравнить длину первой строки с длиной каждой прочитанной строки, чтобы проверить, что все строки имеют одинаковое количество столбцов.
Поскольку вы выполняете цикл и обрабатываетеПри вводе каждой строки вы просто сохраняете счетчик строк, который, когда вы закончите чтение, будет содержать количество строк в вашем массиве.
Существует два способа обработки хранилища для вашего массива.Вы можете либо объявить массив, достаточно большой, чтобы вместить самый большой ожидаемый лабиринт (сохраняя его достаточно маленьким для размещения в стеке 256x512
безопасен как для Linux, так и для Windoze), или вы можете динамически распределять хранилище для ваших столбцов и строк, используя realloc()
для выделения дополнительного хранилища по мере необходимости.(Там вы можете обрабатывать размеры лабиринта вплоть до предела памяти вашего компьютера - но это действительно добавляет сложности)
Ваша «путаница» с моим массивом должна быть, например, 11x21
понятна.Все это связано с тем, что символы на терминале примерно в два раза выше , чем в ширину .Таким образом, чтобы напечатать «куб» символов, вам нужно примерно вдвое больше столбцов, чем строк.Это не проблема вообще.Если вы правильно закодировали чтение столбцов и строк и у вас есть переменные, отслеживающие количество столбцов и строк - тогда разница становится не более чем числами, которые ваш код отслеживает в паре переменных.
Следующееэто короткий пример, чтобы обратиться к вашим камням преткновения при чтении неизвестного числа или строк и столбцов до фиксированного максимума.(вместо того, чтобы динамически распределять и перераспределять - что мы можем оставить на потом).Для этого мы #define
константа для максимального числа столбцов, а затем зная, что нам нужно 1/2 этого числа строк, #define
константа для этого количества строк, например
#include <stdio.h>
#include <string.h>
#define MAXC 512 /* declare consts for max NxN you can handle */
#define MAXR (MAXC + 1) / 2
Тогда достаточно просто объявить переменные для отслеживания текущих row
и col
и общего количества строк и столбцов (nrow, ncol
) вместе с объявлением массива a[MAXR][MAXC] = {""};
для хранения лабиринта.Затем вы можете либо открыть свой файл, если в качестве 1-го аргумента указано имя файла (либо прочитать из stdin
по умолчанию, если аргумент не указан).В любом случае вы можете проверить, есть ли у вас открытый поток для чтения, например,
size_t row = 0, col = 0, nrow = 0, ncol = 0;
char a[MAXR][MAXC+1] = {""}; /* delcare and initialize array */
/* 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;
}
Если ваш файловый поток открыт для чтения, теперь это просто вопрос чтения всех строк данных в файле.Поскольку вы ожидаете, что все строки будут иметь четное количество символов, так что ваш лабиринт на самом деле является кубом, вы можете сохранить количество символов в первой строке (после обрезки '\n'
) и использовать его для сравнения с количеством символовв каждой строке для подтверждения у вас есть куб.Когда вы читаете строки, вам также нужно защищать границы вашего массива, чтобы вы не пытались хранить больше строк в вашем массиве, чем у вас есть строк, которые нужно хранить, поэтому простая проверка row < MAXR
в сочетании с вашим fgets (a[row], MAXC, fp)
налагает, чтопредел, например,
while (row < MAXR && fgets (a[row], MAXC, fp)) {
size_t len = strlen (a[row]); /* get length of row */
if (len && a[row][len-1] == '\n') /* validate it fits in array */
a[row][--len] = 0; /* remove trailing '\n' char from end */
else if (len == MAXC) {
fprintf (stderr, "error: row exceeds %d chars.\n", MAXC);
return 1;
}
if (!row) /* if 1st row - set expected ncol for each row */
ncol = len;
if (ncol != len) { /* validate all other rows against 1st */
fprintf (stderr, "error: unequal columns (%lu) on row (%lu)\n",
len, row);
return 1;
}
/* your code goes here - example just outputs array */
for (col = 0; col < ncol; col++)
putchar (a[row][col]);
putchar ('\n');
row++; /* advance row counter when done processing row */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
nrow = row; /* save the total number of rows */
Теперь у вас есть все сохраненные строки и столбцы, и у вас есть установленные значения nrow
и ncol
, предоставляющие массив nrow x ncol
.Я оставлю вам логику пути, но я хотел бы привести пример замены ' '
на '*'
в вашем пути.Следующее делает это для каждого возможного символа пути, накладывая ограничение на то, что каждый '*'
имеет соседний пробел (вы можете отрегулировать по мере необходимости).Здесь мы просто зациклим 0 -> nrow-1
и вложим цикл из 0 -> ncol-1
, чтобы зациклить каждый символ в массиве.
Единственная морщина, на которую вы должны обратить внимание при проверке соседних ячеек подряд, это то, что вы должны убедиться, что вы не по левому краю лабиринта, когда вы проверяете столбец слева ине по правому краю лабиринта при проверке столбца справа (доступ к элементам за пределами вашего массива вызовет неопределенное поведение )
Вы обрабатываете проверки краев как простые добавленияк условному инсайдеру вашего оператора if (...)
, например
/* you can make multiple passes over the array to determine your path.
* below is just an example of replacing the spaces in the path with
* asterisks.
*/
puts ("\nreplacing path spaces with asterisks\n");
for (row = 0; row < nrow; row++) {
for (col = 0; col < ncol; col++) {
/* if adjacents and current ' ', replace with '*' */
if (col && col < ncol - 1 && /* col > 0 && col < ncol-1 */
/* next checks adjacent and current all ' ' */
a[row][col-1] == ' ' && a[row][col] == ' ' &&
a[row][col+1] == ' ')
a[row][col] = '*'; /* if conditions met, set element '*' */
putchar (a[row][col]);
}
putchar ('\n');
}
Собрав все части вместе в коротком примере, чтобы прочитать любой лабиринт шириной до 512
символов, вы можете сделать что-то вроде следующего:
#include <stdio.h>
#include <string.h>
#define MAXC 512 /* declare consts for max NxN you can handle */
#define MAXR (MAXC + 1) / 2
int main (int argc, char **argv) {
size_t row = 0, col = 0, nrow = 0, ncol = 0;
char a[MAXR][MAXC+1] = {""}; /* delcare and initialize array */
/* 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 < MAXR && fgets (a[row], MAXC, fp)) {
size_t len = strlen (a[row]); /* get length of row */
if (len && a[row][len-1] == '\n') /* validate it fits in array */
a[row][--len] = 0; /* remove trailing '\n' char from end */
else if (len == MAXC) {
fprintf (stderr, "error: row exceeds %d chars.\n", MAXC);
return 1;
}
if (!row) /* if 1st row - set expected ncol for each row */
ncol = len;
if (ncol != len) { /* validate all other rows against 1st */
fprintf (stderr, "error: unequal columns (%lu) on row (%lu)\n",
len, row);
return 1;
}
/* your code goes here - example just outputs array */
for (col = 0; col < ncol; col++)
putchar (a[row][col]);
putchar ('\n');
row++; /* advance row counter when done processing row */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
nrow = row; /* save the total number of rows */
/* you can make multiple passes over the array to determine your path.
* below is just an example of replacing the spaces in the path with
* asterisks.
*/
puts ("\nreplacing path spaces with asterisks\n");
for (row = 0; row < nrow; row++) {
for (col = 0; col < ncol; col++) {
/* if adjacents and current ' ', replace with '*' */
if (col && col < ncol - 1 && /* col > 0 && col < ncol-1 */
/* next checks adjacent and current all ' ' */
a[row][col-1] == ' ' && a[row][col] == ' ' &&
a[row][col+1] == ' ')
a[row][col] = '*'; /* if conditions met, set element '*' */
putchar (a[row][col]);
}
putchar ('\n');
}
return 0;
}
Пример использования / вывода
Как указано, код просто считывает и выводит оригинальный лабиринт, а затем делает второй проход по лабиринту, выводя его вместе с путемзаполнено '*'
$ ./bin/array2dread <dat/arrmaze.txt
+---+---+---+---+---+
| | |
+---+ + + + +
| | | | | |
+ + + + +---+
| | | | |
+ + + +---+ +
| | | |
+ +---+---+ + +
| | |
+---+---+---+---+---+
replacing path spaces with asterisks
+---+---+---+---+---+
| * * * | * * * * * |
+---+ * + * + * + * +
| * | * | * | * | * |
+ * + * + * + * +---+
| * | * | * | * * * |
+ * + * + * +---+ * +
| * * * | * | * * * |
+ * +---+---+ * + * +
| * * * * * * * | * |
+---+---+---+---+---+
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.