Home > Back-end >  Reading a text file to extract coordinates in c
Reading a text file to extract coordinates in c

Time:10-12

i am trying to read a text file and extract the cordinates of 'X' so that i can place then on a map the text file is

10 20
9 8 X
2 3 P
4 5 G
5 6 X
7 8 X 
12 13 X
14 15 X

           
fp = fopen(file_name, "r");
if (fp == NULL) {
    /* if the file opened is empty or has any issues, then show the error */
    perror("File Error");
}
else {
    if (ferror(fp)) {
        perror("unable to read from file");
    }
    else {
        /* get the dimensions from the file */
        fscanf(fp, "%d %d", &map_row, &map_col);
        map_row = map_row   2;
        map_col = map_col   2;
        while (fscanf(fp, "%d %d %c", &x, &y, &z) == 3) {
            if (z == 'X') {
                x = x   1;
                y = y   1;
                floor_row = x;
                floor_col = y;
            }
        }
    }
}

I tried multiple times but I am unable to extract the relevant data and place it in separate variables to plot I am quite new to c and am trying to learn things so any help is appreciated

thanks in advance

CodePudding user response:

From my top comments, I suggested an array of point structs.

Here is your code refactored to do that.

I changed the scanf to use %s instead of %c for the point name. It generalizes the point name and [probably] works better with the input line because [I think] the %c would not match up correctly.

It compiles but is untested:

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

struct point {
    int x;
    int y;
    char name[8];
};

struct point *points;
int count;
int map_row;
int map_col;

void
read_data(const char *file_name)
{
    FILE *fp = fopen(file_name, "r");
    if (fp == NULL) {
        /* if the file opened is empty or has any issues, then show the error */
        perror("File Error");
        return;
    }

    /* get the dimensions from the file */
    fscanf(fp, "%d %d", &map_row, &map_col);
    map_row = map_row   2;
    map_col = map_col   2;

    while (1) {
        // enlarge dynamic array
          count;
        points = realloc(points,sizeof(*points) * count);

        // point to place to store data
        struct point *cur = &points[count - 1];

        if (fscanf(fp, "%d %d %s", &cur->x, &cur->y, cur->name) != 3)
            break;
    }

    // trim to amount used
    --count;
    points = realloc(points,sizeof(*points) * count);

    fclose(fp);
}

CodePudding user response:

There are a number of way to approach this. Craig has some very good points on the convenience of using a struct to coordinate data of different types. This approach reads with fgets() and parses the data you need with sscanf(). The benefit eliminates the risk of a matching-failure leaving characters unread in your input stream that will corrupt the remainder of your read from the point of matching-failure forward. Reading with fgets() you consume a line of input at a time, and that read is independent of the parsing of values with sscanf().

Putting it altogether and allowing the filename to be provided by the first argument to the program (or reading from stdin by default if no argument is provided), you can do:

#include <stdio.h>

#define MAXC 1024   /* if you need a constand, #define one (or more) */

int main (int argc, char **argv) {
  
  char buf[MAXC];           /* buffer to hold each line */
  int map_row, map_col;     /* map row/col variables */
  /* use filename provided as 1st argument (stdin if none provided) */
  FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
  
  if (!fp) {  /* validate file open for reading */
    perror ("file open");
    return 1;
  }
  
  /* read/validate first line saving into map_row, map_col */
  if (!fgets (buf, MAXC, fp) || 
      sscanf (buf, "%d %d", &map_row, &map_col) != 2) {
    fputs ("error: EOF or invalid map row/col data.\n", stderr);
    return 1;
  }
  
  /* loop reading remaining lines, for used as line counter */
  for (size_t i = 2; fgets (buf, MAXC, fp); i  ) {
    char suffix;
    int x, y;
    
    /* validate parsing x, y, suffix from buf */
    if (sscanf (buf, "%d %d %c", &x, &y, &suffix) != 3) {
      fprintf (stderr, "error: invalid format line %zu.\n", i);
      continue;
    }
    
    if (suffix == 'X') {  /* check if line suffix is 'X' */
      printf ("-    -    %c\n", x, y, suffix);
    }
  }
  
  if (fp != stdin) {      /* close file if not stdin */
    fclose (fp);
  }
}

(note: this just illustrates the read and isolation of the values from lines with a suffix of 'X'. Data handling, and calculations are left to you)

Example Use/Output

With your data in dat/coordinates.txt you could do:

$ ./bin/readcoordinates dat/coordinates.txt
 9     8    X
 5     6    X
 7     8    X
12    13    X
14    15    X

As Craig indicates, if you need to store your matching data, then an array of struct provides a great solution.

  •  Tags:  
  • c
  • Related