如何在指针数组中存储“迷宫”信息,其中数组的每个元素都指向一个char数组,该数组保存迷宫的一行[关闭]

y1aodyip  于 2023-05-22  发布在  其他
关注(0)|答案(2)|浏览(76)

已关闭,此问题需要更focused。目前不接受答复。
**想改善这个问题吗?**更新问题,使其仅通过editing this post关注一个问题。

昨天关门了。
Improve this question

#include <stdio.h>
#include <stdlib.h>
int main(){
    char **lab;
    char c;
    int x,y,i=0,j=0,columnnumber=0,rownumber=1,check=1;
    scanf("%d %d",&x,&y); 
    lab = (char**)malloc(sizeof(char*)*rownumber);
    lab[0] = (char*)malloc(sizeof(char)*1000);
    while(check){
        scanf("%c",&c);
        if(c=='\n'){
            check = 0;
        }
        else{
            lab[0][columnnumber] = c;
            columnnumber++;
        }
    }
    lab[0] = realloc(lab[0],(columnnumber+1)*sizeof(char));
    rownumber = 2;
    lab = (char**)realloc(lab,rownumber*sizeof(char*));
    lab[1] = (char*)malloc(sizeof(char)*(columnnumber+1));
    check = 1;
    while(check){
        scanf("%c",&c);
        if(c=='\n'){
            rownumber++;
            lab = realloc(lab,rownumber*sizeof(char*));
            lab[rownumber-1] = (char*)malloc(sizeof(char)*(columnnumber+1));
            j = 0;
        }
        else if(c == EOF){
            check = 0;
        }
        else{
            lab[rownumber-1][j] = c;
            j++;
        }
    }
}

迷宫(每行末尾有'\n',末尾有EOF):

XXXXXXXXXXXXXXXXXXXXX XXXX
X XXXX          X XX  XXXX
X      X XXXXXX   XX    XX
X XXXXXX   XXXXXXXXX XX XX
X XX   XXXX X     XX X  XX
X XX X  XXX XX XXXXX XX XX
X X  XX   X    X        XX
X X   XXX XXX XXXXXX XXXXX
X XX   XX     X   XX XX XX
X XX     XXXX X X XX XX XX
X XX XX  XX   XXX XX    XX
X XX  X XXX       XX  X XX
X XX    XXX XXXXXXXXX   XX
X XXXX   XX           XXXX
XXXXXXXXXXXXXXXXXXXXXXXXXX

我应该接受输入,我们称之为迷宫,并将迷宫信息存储在一个2D指针数组中,正如我在标题中所说的。我该怎么做?我是动态分配和C编程的新手。行计数和列计数可以变化,只要不超过100k个单元格即可。
每行末尾有'\n',末尾有EOF(迷宫在上面)。

aurhwmvo

aurhwmvo1#

如果迷宫的尺寸事先不知道,那么也不知道行指针的数组必须有多大。
在您的问题中,您指出单元格的最大数量为100,000。这意味着最大行数为100,000(一列)。因此,行指针数组的最大大小是100,000个指针。虽然您可以从一个较小的值开始并使数组增长,但从一开始就将数组设置为这个大小会更简单。
但是,100,000个指针的数组大小为400或800 KiB,具体取决于平台。虽然在大多数非嵌入式平台上获得这样的内存量不是问题,但在大多数平台上堆栈空间(由本地数组使用)是有限的。例如,在Windows上,默认的最大堆栈大小约为1 MiB。因此,最好在堆上分配内存(使用malloc),而不是在堆栈上分配内存(使用本地数组),如下所示:

#define MAX_ROWS 100000

int main( void )
{
    char **rows = malloc( MAX_ROWS * sizeof *rows );
    if ( rows == NULL )
    {
        fprintf( stderr, "Memory allocation error!\n" );
        exit( EXIT_FAILURE );
    }

    [...]

我们在阅读第一行时也有类似的问题,因为我们不知道该行的列数。由于您声明单元格的最大数量为100,000,这意味着最大列数为100,000(如果迷宫只有一行)。因此,为了阅读第一行,我们需要一个char类型的100,000个元素的数组。由于上述原因,这个数组也应该在堆上而不是在堆栈上分配,所以我们应该再次使用malloc。一旦我们通过阅读第一行确定了列数,我们就可以使用realloc将数组缩小到所需的大小。此外,对于所有进一步的行,我们知道列数不会改变,所以从现在开始,我们总是知道数组中每行所需的元素数。这意味着我们不再需要为一行分配100,000个元素,然后在以后收缩它;我们现在可以从一开始就分配所需数量的元素。
下面是一个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

bool get_line_from_stream( char buffer[], int buffer_size, FILE *fp );

#define MAX_ROWS 100000
#define MAX_COLS 100000

int main( void )
{
    int num_rows, num_cols;

    //allocate memory for array of row pointers
    char **rows = malloc( MAX_ROWS * sizeof *rows );
    if ( rows == NULL )
    {
        fprintf( stderr, "Memory allocation error!\n" );
        exit( EXIT_FAILURE );
    }

    //allocate memory for first row
    rows[0] = malloc( MAX_COLS + 1 );
    if ( rows[0] == NULL )
    {
        fprintf( stderr, "Memory allocation error!\n" );
        exit( EXIT_FAILURE );
    }

    //read first row
    if ( !get_line_from_stream( rows[0], MAX_COLS + 1, stdin ) )
    {
        fprintf( stderr, "Error reading first row!\n" );
        exit( EXIT_FAILURE );
    }

    //determine number of columns by inspecting the first row
    num_cols = strlen( rows[0] );

    //shrink first row to required size
    rows[0] = realloc( rows[0], num_cols + 1 );
    if ( rows[0] == NULL )
    {
        fprintf( stderr, "Memory allocation error!\n" );
        exit( EXIT_FAILURE );
    }

    //process one row per loop iteration
    for ( num_rows = 1; ; num_rows++ )
    {
        char *new_row;

        //allocate memory for new row
        new_row = malloc( num_cols + 1 );
        if ( new_row == NULL )
        {
            fprintf( stderr, "Memory allocation error!\n" );
            exit( EXIT_FAILURE );
        }

        //read next row
        if ( !get_line_from_stream( new_row, num_cols + 1, stdin ) )
        {
            //we are unable to read any further rows, so
            //we break out of the loop
            free( new_row );
            break;
        }

        //verify that we have room for another row
        if ( num_rows == MAX_ROWS )
        {
            fprintf( stderr, "Too many rows in input file!\n" );
            exit( EXIT_FAILURE );
        }

        //add new row to array
        rows[num_rows] = new_row;
    }

    //print back the data
    printf( "The following data was stored:\n" );
    for ( int i = 0; i < num_rows; i++ )
    {
        printf( "%s\n", rows[i] );
    }

    //cleanup
    for ( int i = 0; i < num_rows; i++ )
    {
        free( rows[i] );
    }
    free( rows );
}

//This function will read exactly one line of input and remove the
//newline character, if it exists. On success, it will return true.
//If this function is unable to read any further lines due to
//end-of-file, it will return false. If it fails for any other reason,
//it will not return, but will print an error message and call "exit"
//instead.
bool get_line_from_stream( char buffer[], int buffer_size, FILE *fp )
{
    char *p;

    //attempt to read one line from the stream
    if ( fgets( buffer, buffer_size, fp ) == NULL )
    {
        if ( !feof(fp) )
        {
            fprintf( stderr, "Input error!\n" );
            exit( EXIT_FAILURE );
        }

        return false;
    }

    //make sure that line was not too long for input buffer
    p = strchr( buffer, '\n' );
    if ( p == NULL )
    {
        //a missing newline character is ok if the next
        //character is a newline character or if we have
        //reached end-of-file
        if ( getc(fp) != '\n' && !feof(fp) )
        {
            fprintf( stderr, "Line is too long for memory buffer!\n" );
            exit( EXIT_FAILURE );
        }
    }
    else
    {
        //remove newline character by overwriting it with a null
        //character
        *p = '\0';
    }

    return true;
}

使用问题中指定的输入,此程序具有以下输出:

The following data was stored:
XXXXXXXXXXXXXXXXXXXXX XXXX
X XXXX          X XX  XXXX
X      X XXXXXX   XX    XX
X XXXXXX   XXXXXXXXX XX XX
X XX   XXXX X     XX X  XX
X XX X  XXX XX XXXXX XX XX
X X  XX   X    X        XX
X X   XXX XXX XXXXXX XXXXX
X XX   XX     X   XX XX XX
X XX     XXXX X X XX XX XX
X XX XX  XX   XXX XX    XX
X XX  X XXX       XX  X XX
X XX    XXX XXXXXXXXX   XX
X XXXX   XX           XXXX
XXXXXXXXXXXXXXXXXXXXXXXXXX
iugsix8n

iugsix8n2#

或者,由于您已经在进行重新分配,因此不妨将此操作简化为将未知长度的文件读取到一个动态字节数组中(使用fread)。如果您不担心将其解析为行,这会非常简单(并且更快)。

#include <stddef.h>

struct array { char *data; size_t capacity, size; };

#include <stdlib.h>
#include <errno.h>
#include <stdint.h>

static int array_reserve(struct array *const a, const size_t n) {
    if(n == 0) return 1;
    size_t capacity = a->capacity ? a->capacity : 1;
    while(capacity < n) {
        if(capacity & (SIZE_MAX & ~(SIZE_MAX >> 1))) return errno = ERANGE, 0;
        capacity <<= 1;
    }
    if(capacity <= a->capacity) return 1;
    char *const data = realloc(a->data, capacity);
    if(!data) { if(!errno) errno = ERANGE; return 0; }
    a->data = data, a->capacity = capacity;
    return 1;
}
static char *array_buffer(struct array *const a, const size_t n) {
    if(a->size > SIZE_MAX - n) { errno = ERANGE; return 0; }
    return array_reserve(a, a->size + n) && a->data ? a->data + a->size : 0;
}
static char *array_append(struct array *const a, const size_t n) {
    char *buffer;
    if(!(buffer = array_buffer(a, n))) return 0;
    return a->size += n, buffer;
}

#include <stdio.h>
#include <assert.h>
#include <string.h>

static int get_file(struct array *const a, FILE *const fp) {
    const size_t granularity = 1024;
    size_t nread;
    char *cursor;
    assert(a && fp);
    size_t start = a->size;
    do if(!(cursor = array_buffer(a, granularity))
        || !array_append(a, nread = fread(cursor, 1, granularity, fp)))
        return 0;
    while(nread == granularity);
    if(ferror(fp) || !(cursor = array_buffer(a, 1))) return 0;
    *cursor = '\0';
    /* Binary files with embedded '\0' are not allowed; check just this read. */
    if(strchr(a->data + start, '\0') != cursor) { errno = EILSEQ; return 0; }
    return 1;
}

int main(void) {
    const char *fail = 0;
    struct array a = {0};
    if(!get_file(&a, stdin)) { fail = "input"; goto catch; }
    printf("The following was read:\n"
        "%s", a.data);
    goto finally;
catch:
    perror(fail);
finally:
    free(a.data);
    return fail ? EXIT_FAILURE : EXIT_SUCCESS;
}

然后,当输入全部完成时,可以验证附加约束,诸如最大线或线是相同长度。这线性化和简化了双指针,并在一个内存块内工作。

相关问题