0

so what I have is the following array:

10
1 250 350 50
2 525 200 80
3 425 700 60
4 675 475 65
5 850 850 40
6 925 200 90
7 1050 575 80
8 1250 800 70
9 1375 400 60
10 1500 650 40

Each lines' value means something different, per instance

1   250  350    50
id  lat  long  value

I want to assign each of those line values to a structure so I can play with them, but after googling and coming up with the graph theory (which is kind of similar to what I am trying to do) nothing worked... I may say that this array is being pulled from a text file, whether that is or not relevant.

struct population{
    int id;
    int latitude;
    int longitude;
    int value;
};

I can't come up with any solution, can anyone help me out or at least provide some tutorials or articles to help me clear my mind?

Here is my code:

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

#define RSIZE 20
#define CSIZE 11

struct population{
    int id;
    int latitude;
    int longitude;
    int value;
};


int main(void) 
{
    char line[CSIZE][RSIZE];
    char fname[20];
    FILE *fptr = NULL; 
    int i = 0;
    int tot = 0;
    printf("\n\n Read the file and store the lines into an array :\n");
    printf("------------------------------------------------------\n"); 
    printf(" Input the filename to be opened : ");
    scanf("%s",fname);  

    fptr = fopen("cord.txt", "r");
    while(fgets(line[i], RSIZE, fptr)) 
    {
        line[i][strlen(line[i]) - 1] = '\0';
        i++;
    }
    tot = i;
    printf("\n The contents of the file %s  are : \n",fname);    
    for(i = 0; i < tot; ++i)
    {
        printf(" %s\n", line[i]);
    }
    printf("\n");
    return 0;
}
E_net4
  • 27,810
  • 13
  • 101
  • 139
Tomas Mota
  • 672
  • 5
  • 27
  • 1
    "*I can't come up with any solution*". What did you try? Show a specific example of something you tried and explain what specific issue you had with it. For example, one simple example is to use `sscanf` to parse each `line` into individual struct fields. Did you try that? If not then what parsing technique did you try? – kaylum Dec 31 '21 at 20:29
  • Thank you for your answer, I meant that I don't know enough about programming to come up with a solution to this problem. But based on your answer, I googled it and found this stackoverflow answer. https://stackoverflow.com/questions/3878327/easiest-way-to-read-this-line-of-text-into-a-struct Do you think it makes sense to what I am trying to do? – Tomas Mota Dec 31 '21 at 20:32
  • 1
    Yes, looks like a reasonable approach to try. – kaylum Dec 31 '21 at 20:34
  • `line[i][strlen(line[i]) - 1] = '\0';` allows for a hacker exploit. If the first byte _read_ is a _null character_, `line[i][strlen(line[i]) - 1]` leads to UB as that is `line[i][SIZE_MAX]`. – chux - Reinstate Monica Dec 31 '21 at 23:39

1 Answers1

2

A good way to read, validate and save a line of file text into a struct is to use a helper function with fgets() and sscanf() @kaylum. Use " %n" to detect successful parsing completion.

#define INT_TEXT_SIZE 12 // INT_MIN
#define POPULAITON_LINE_SIZE ((INT_TEXT_SIZE + 1 /* separator */)*4 + 1)

// Return: 
// 1 on success
// 0 on failure
// EOF on end-of-file/input error
int population_read(struct population *p, fptr) {
  // Be generous in buffer size, suggest 2x max expected
  char buf[POPULAITON_LINE_SIZE * 2];
  if (fgets(buf, sizeof buf, fptr) == NULL) {
    return EOF;
  }

  int n = 0;
  // Use %n to store offset 
  sscanf(buf, "%d%d%d%d %n", &p->id, 
      &p->latitude, &p->longitude, &p->value, &n);

  if (n == 0 || buf[n] || n >= sizeof buf - 1) {
    // Parsing failed, junk at the end or very long
    return 0;
  }

  // Maybe some range/value tests per member
  if (p->latitude < LATITUDE_MIN || p->latitude > LATITUDE_MAX) {
    return 0;
  }
  ... // likewise for other members.

  return 1;
}

Usage example:

struct population pop[CSIZE];

int count;
for (count = 0; count < CSIZE; count++) {
  int result = population_read(&pop[count], fptr));
  if (result == 0) {
    report_error_with_TBD_code();
    return -1;
  }
  if (result != 1) {
    break;
  }
}

for (int c = 0; c < count; c++) {
  // Use pop[c];
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256