簡體   English   中英

在數組中讀取迷宮文件的數組,立方體大小不均,多余字符

[英]Reading in an array for maze file in C with an uneven size of cube and extra characters

我試圖弄清楚如何正確地從C中的.txt文檔中讀取和存儲迷宮。此迷宮的最大大小為40x40“立方體”。 閱讀完之后,我將需要解決此問題,方法是在路徑的左上角到右下角之間加一個*。 我習慣於使用2D數組,但是這個問題一直困擾着我,因為我不了解如何跟蹤行和列是否不完全均勻,或者如何准確地在中間打印*我解決了每個“多維數據集”的問題。 我已經讀過其他由1和0組成的迷宮示例,或者什至是牆壁上的所有#迷宮示例,這使它很容易讀入並跟蹤,但不能像這樣輸入。 解決第一個迷宮,並用雙倍空格隔開后,我將需要閱讀同一文本文件上的其他迷宮。 以下是其中一個迷宮的示例:

+---+---+---+---+---+  
|       |           |  
+---+   +   +   +   +  
|   |   |   |   |   |  
+   +   +   +   +---+  
|   |   |   |       |  
+   +   +   +---+   +  
|       |   |       |  
+   +---+---+   +   +  
|               |   |  
+---+---+---+---+---+ 

這是到目前為止我進行錯誤檢查和讀取字符的一些代碼。 在其中,我試圖初始化一個120x120的數組,讀取當前char,然后將這些字符轉換為-1或0以對應於牆或空白空間。

/* Read in a grid as parameter of max 120x120 to account for '+' and'-' */
int readLine(int grid2D[120][120])
{
    int row = 0;
    int col = 0;

    int isNewLine = TRUE;

    /* Loop through while getchar does not equal EOF */
    while ((c = getchar()) != EOF)
    {

        /* Check for foreign characters, return FALSE if found */
        if ((c != '+') || (c != '-') || (c != '|') || (c != ' '))
        {
            /* If c = \n , avoid tripping error, and do nothing */
            if(c == '\n'){}
            else
              errorFree = FALSE;
        }

        /* If character is a '+' '-' or '|', it is a wall, set to -1 to 
        use int's for wall tracking */
        else if (row%2 == 0)
        {
           if(c == '|')
           {
              grid2D[row][col] = -1;
              col++;
           }
        }
        else if((c == '+') || (c == '-'))
        {
           grid2D[row][col] = -1;
           col++;
        }
        else
        {
            if(c == '\n')
            {
               col = 0;
               row++;
            }
        }

    isNewLine = TRUE;

    return isNewLine;
}

任何指導將不勝感激,我不確定我所采用的方法是否正確。 我相信我目前正在正確地進行錯誤檢查,但是我正在努力了解應該如何跟蹤每個“多維數據集”,因為每個“多維數據集”的字符都不均勻,它們的大小更是如此,為5x1多維數據集(a +---+表示一側, |表示另一側)

為了回答您的問題和評論中的問題,確定行和列的大小非常簡單。 當您使用fgets從文件中讀取數組的一行時,可以使用strlen()確定字符數( 但請注意 ,它也包含'\\n'字符-因此您需要減去一個-您可以可以與從末尾修剪'\\n'結合使用)

讀完第一行並說明'\\n' ,請設置一個變量,該變量保存數組中的字符(列)數。 由於您知道數組是一個多維數據集,因此可以將第一行的長度與每隔一行讀取的長度進行比較,以驗證所有行的列數均相同。

在循環和處理每一行的輸入時,您只需保留一個行計數器,當您完成讀取操作后,該計數器將保存數組中的行數。

有兩種方法可以處理陣列的存儲。 您可以聲明一個足夠大的數組以容納最大的預期迷宮(同時保持足夠小的大小以適合堆棧,在Linux和Windoze上都是256x512都是安全的),也可以使用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

然后,只需聲明變量即可跟蹤當前rowcol以及rowcol的總數( nrow, ncol ),以及聲明數組a[MAXR][MAXC] = {""}; 拿着迷宮。 然后,如果給定文件名作為第一個參數,則可以打開文件(如果沒有給定參數,則默認情況下從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 < MAXRfgets (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 */

您現在所有的行和列存儲和你有你的nrowncol值設置讓您在nrow x ncol陣列。 我將留給您的路徑邏輯,但是我確實想提供一個示例,說明如何在您的路徑中將' '替換為'*' 對於每個可能的路徑字符,以下操作只是強制每個'*'具有相鄰空格(您可以根據需要進行調整)。 在這里,我們只循環0 -> nrow-1然后嵌套一個從0 -> ncol-1 0 -> nrow-1的循環以遍歷數組中的每個字符。

連續檢查相鄰單元格時唯一需要注意的皺紋是,當您檢查列的左側而不是迷宮的右邊緣時,必須確保自己不在迷宮的左邊緣當檢查右邊的列時(訪問超出數組范圍的元素將調用Undefined Behavior

您可以將邊緣檢查作為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

+---+---+---+---+---+
| * * * | * * * * * |
+---+ * + * + * + * +
| * | * | * | * | * |
+ * + * + * + * +---+
| * | * | * | * * * |
+ * + * + * +---+ * +
| * * * | * | * * * |
+ * +---+---+ * + * +
| * * * * * * * | * |
+---+---+---+---+---+

仔細檢查一下,如果您還有其他問題,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM