简体   繁体   中英

C program. Taking top number from input file, creating 2d array, then reading grid from file

Sorry if this question has been askked I've been looking on this site for a couple hours and haven't seen anything yet.

So I'm reading an input file that looks like this. The top line being an 8x8 2d array, then the remaining lines the grid I have to sort through. Basically I'm replacing each * with a letter +1, so a,b,c...etc but that's not my question.

8   <---- The size of the array 8X8
**......       
**..*..*
..**.**.
..**..*.
.*..*..*
..**.**.
..**.**.
.*..*..*

my question is, how can I read just the top line of the input file to find the size of the array then store that as the row and columns of my array, then read the remainder of the file (the grid) and store the characters into the rows and columns of the array?

This is what I have so far.

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define N 9

void blobchecker(char[][N]);

main()
{
    FILE *fp;
    fp = fopen("blobfile.txt", "r");
    if ((fp = fopen("blobfile.txt", "r")) == NULL) 
        printf("File not read \n");

    int c;
    char myarray[N][N];
    int i, j;

    fscanf(fp, "%d", &c);
    fclose(fp);
    fp = fopen("blobfile.txt", "r");
    for (i = 0; i < N; i++)
        for (j = 0; j < N; j++)
            fscanf(fp, "%c", &myarray[i][j]);

    for (i = 0; i < N; i++)
        for (j = 0; j < N; j++)
            printf("%c", myarray[i][j]);

    printf("\n Now checking for blobs \n");

    // blobchecker(myarray);

    fclose(fp);
}

Try this:

int c;
char** myarray;
int i;
fscanf(fp, "%d", &c);
myarray = malloc(c*sizeof(char*));
for (i=0; i<c; i++)
    myarray[i] = malloc(c);

And don't forget to free the allocated memory at a later point in the execution of your program:

for (i=0; i<c; i++)
    free(myarray[i]);
free(myarray);

Here is a solution without using heap allocated memory. Note: This solution works only with the C99 standard and onward versions.

int main()
{
    FILE *fp;
    fp = fopen("blobfile.txt", "r");
    if ((fp = fopen("blobfile.txt", "r")) == NULL) {
        printf("File not read \n");
        return 1; // end the program when the file can't be opened
    }

    int c;
    int i, j;

    fscanf(fp, "%d", &c);

    char myarray[c][c]; // variable length array using the read size

    for (i = 0; i < c; i++) // use c as upper limit
        for (j = 0; j < c; j++)
            fscanf(fp, " %c", &myarray[i][j]);

    for (i = 0; i < c; i++)
    {
        for (j = 0; j < c; j++)
            printf("%c", myarray[i][j]);
        printf("\n");
    }
    printf("\n Now checking for blobs \n");

    //blobchecker(myarray);

    fclose(fp);

}

Your problem was opening and reopening the file once you've read the array size. By opening the file again you reset the 'cursor' ( stream position indicator ) to the beginning of the file. So the first charactar you've read was the size of your array.

This has been pretty much answered, but couple of additional notes: It might be easier to use fscanf(fp,"%s", myarray[i][]) . The fscanf will take care of the newline chararter, and this way you can assign a whole string to a desired array in 2d matrix. Makes reading and handling way easier and you can still refer to a specific member of an array using both of his indexes. Make sure to allocate the memory correctly and take care: fscanf which takes care of the \\n will add it to your string! But overall it's a simpler solution. Also, as it has been said, avoid closing and reopening the file. If you do this, you're losing an offset pointer so you're basically reading a file all over again from the top, which is neither necessary or needed.

Dynamically allocate memory using malloc and free it after its use.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
/* `#define N 9` Not needed */

void blobchecker(char**); /* Note the change here */

int main(void) /* Always use a standard signature of main */
{

    /* Indent your code properly always */

    FILE *fp;
    fp = fopen("blobfile.txt", "r");
    if ((fp = fopen("blobfile.txt", "r")) == NULL) 
    {
        /* `printf("File not read \n");` Better to print in stderr */
        fputs("Failed to open file 'blobfile.txt'", stderr);
        return EXIT_FAILURE; /* Exit the program (main) */
    }


    int c;
    /* char myarray[N][N]; */
    char **myarray; /* Note the change here */
    int i, j;

    fscanf(fp, "%d", &c);

    /*
    `fclose(fp);`
    `fp = fopen("blobfile.txt", "r");` Don't close and reopen
    */

    myarray = malloc(c * sizeof *myarray); /* Allocate `c` rows */
    if(NULL == myarray) /* If `malloc` failed */
    {
        fputs("Failed to malloc 'myarray'", stderr);
        return EXIT_FAILURE; /* Exit the program (main) */
    }
    for (i = 0; i < c; i++)
    {
        myarray[i] = malloc(c); /* For each row, allocate `c` columns */
        if(NULL == myarray[i]) /* If `malloc` failed */
        {
            for(j = i - 1; j >= 0; j--) /* `free` all previously allocated memory */
                free(myarray[j]);
            free(myarray);
            fputs("Failed to malloc 'myarray[i]'", stderr);
            return EXIT_FAILURE; /* Exit the program (main) */
        }
    }

    for (i = 0; i < c; i++)
        for (j = 0; j < c; j++)
            fscanf(fp, " %c", &myarray[i][j]); /* Space before `%c` gets rid of whitespaces */

    for (i = 0; i < c; i++)
        for (j = 0; j < c; j++)
            printf("%c", myarray[i][j]);

    printf("\n Now checking for blobs \n");

    //blobchecker(myarray);

    fclose(fp);

    /* `free` whatever you've allocated after its use: */

    for (i = 0; i < c; i++)
        free(myarray[i]);
    free(myarray);

    return EXIT_SUCCESS; /* Exit main */

}

WARNING: Untested code


Note that in the above code,each call to malloc may allocate memory non-contiguously and this would result in heap fragmentation and reduced efficiency of the program. @Lundin's comments mention more about this.

If the dimension is only known in run-time, you can use a VLA:

int c;
fscanf(fp, "%d", &c);

char myarray[c][c];

for (i = 0; i < c; i++)
    for (j = 0; j < c; j++)
        fscanf(fp, "%c", &myarray[i][j]);

If the amount of memory to read is wast, it might be better to allocate the 2D array dynamically, to ensure that the memory ends up on the heap:

char (*myarray)[c] = malloc( sizeof(char[c][c]) );
...
free(myarray);

There should never be any need of obscure char** -based look-up tables in your case. All they will do is to segment your array all over the heap and make your program slower.


EDIT

If you need to be backwards-compatible with the 27 years old, obsolete C89 standard, you could write portable code like this:

#ifndef __STDC_VERSION__
  #define OLD_JUNK
#elif __STDC_VERSION__ < 199901L
  #define OLD_JUNK
#endif

#ifdef OLD_JUNK
  #define get_item(arr, x, y) (arr [(x) * (y)] )
#else
  #define get_item(arr, x, y) (arr[x][y])
#endif

int c;
fscanf(fp, "%d", &c);

#ifdef OLD_JUNK
  char* myarray = malloc(c * c);
#else
  char (*myarray)[c] = malloc ( sizeof(char[c][c]) );
#endif

int i, j;
for (i = 0; i < c; i++)
    for (j = 0; j < c; j++)
        fscanf(fp, "%c", &get_item(myarray,i,j) );

free(myarray);

I would however strongly recommend to upgrade to a compiler which is not using 1980s technology. Then you would not have to write ugly solutions like this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM