0
votes

I have a function that is trying to read each line of a file, then use sscanf to pass values into an array of structs, creating a new struct for each line of the file that is not a comment line containing char '#'. This is my code:

typedef struct { 
    int row, col, C, D;
    char program[80];
} agentDetails;

My structs are defined in a header file, #included in the main file.

char currentLine[80];
char** agents;
int n=0;

agents = malloc(sizeof(char*)*4); 

while (fgets(currentLine, sizeof currentLine, file) != NULL) {
    if(!strchr(currentLine, '#')) {
        agentDetails agents[n];    /*create new struct in array agents*/
        sscanf(currentLine, "%d %d %c %s %s", &agents[n].row, &agents[n].col, &agents[n].C, agents[n].program, agents[n].D); 
        n++; 
    }
}

this works, however when it reaches end of file it does not exit the loop, it sits there waiting for input. I have tried stepping through with gdb, after the last line it steps to the while(fgets...) line, and then waits for input.

I know this code works if I try to sscanf values into variables initialised within the function, it only seems to fault when I use an array of structs. What is happening here?


I have changed the code so it works, see below:

int n = 0; 
int i = 0;

while (fgets(currentLine, sizeof currentLine, file) != NULL) {
    if(!strchr(currentLine, '#')) {
        n++;
    }
}

rewind(file);
agentDetails agents[n];

while (fgets(currentLine, sizeof currentLine, file) != NULL) {
    if(!strchr(currentLine, '#')) {
        sscanf("same as above"); 
        i++; 
    }
}

I dont use malloc, however. Is this a problem? Will this cause issues?

5
how currentLine is declared ? - phoxis
char currentLine[80]; - user2790954
Shouldn't there be a comma between &agents[n].C agents[n].program in sscanf ? - phoxis
Ah yes, you're right. That was just an error I made typing the code out then. - user2790954
I do not see any issue in the code snippet, other than the fact that why agents[n] is declared and agents[n] is accessed which is out of array bounds. However, please provide minimal compilable code to check any other issue not visible in the provided code snippet. - user1969104

5 Answers

0
votes

Your code looks a bit strange

while (fgets(currentLine, sizeof currentLine, file) != NULL) 
{
  if(!strchr(currentLine, '#')) 
  {
    agentDetails agents[n];    /*create new struct in array agents*/
    sscanf(currentLine, "%d %d %c %s %s", &agents[n].row, &agents[n].col, &agents[n].C, agents[n].program, agents[n].D); 
    n++; 
  }
}

for every loop you create an array of agentDetails of size n, then n is incremented and a new array is created. You use also use n in your arguments to sscanf potentially reaching beyond the array. I would think something like this would be more in line what you want:

int i = 0; // assuming n is defined somewhere else
agentDetails agents[n];    /*create new struct in array agents*/
while (fgets(currentLine, sizeof currentLine, file) != NULL && i < n) 
{
  if(!strchr(currentLine, '#')) 
  {
    sscanf(currentLine, "%d %d %c %s %s", &agents[i].row, &agents[i].col, &agents[i].C, agents[i].program, agents[i].D); 
    i++; 
  }
}

it is also a good practice to check return values e.g. what sscanf returns to see if the number of expected arguments is same as what sscanf found.

0
votes

Take a closer look at this:

agentDetails agents[n];    /*create new struct in array agents*/
sscanf(currentLine, "%d %d %c %s %s", &agents[n].row, &agents[n].col, &agents[n].C, agents[n].program, agents[n].D); 
n++;

You are creating an array inside the while loop (error 1) of size n (assuming n has a non-zero value). Then you are sscanfing into the array at index n, which is always passed the limit of the array (error 2). At the end of the loop, you throw the array away because its scope finishes (error 3).

Your code instead should read something like this:

agentDetails agents[n];    /* make sure to get the correct `n` from somewhere, for example the file itself */
                           /* better yet, use `malloc`, since `n` could be really large */
i = 0;
while (fgets(currentLine, sizeof currentLine, file) != NULL) {
    if(!strchr(currentLine, '#')) {
        sscanf(currentLine, "%d %d %c %s %s", &agents[i].row, &agents[i].col, &agents[i].C, agents[i].program, agents[i].D); 
        i++; 
    }
}
0
votes

This is wrong on several counts.

  1. You declare and allocate char** agents, then shadow it with agentDetails agents[n]
  2. You are reading past the end of the agents array. The valid indices are 0 through (n-1).
  3. Your format specifications are wrong.

GCC issues these warnings:

 warning: format ‘%c’ expects argument of type ‘char *’, 
 but argument 5 has type ‘int *’ [-Wformat]

 warning: format ‘%s’ expects argument of type ‘char *’, 
 but argument 7 has type ‘int’ [-Wformat]
0
votes

As far as I can tell from code you provided... In this line:

agentDetails agents[n];    /*create new struct in array agents*/

you create n-sized array of structures agentDetails.
In sscanf you try to write some details into structure agents[n], which is not in the array, since array size is from 0-(n-1). If I'm wrong, provide more detail about your code.

You try do declare an array of unknown size but it doesn't work that way.
You can iterate over the file once, counting how many agents are in file, then allocate with malloc as much memory as you need. Or you can malloc and realloc in every iteration(which is propably bad idea).

1st. Remove array declaration from loop.
2nd. Do some reading on how malloc works.
3rd. You will be able to fix you code yourself after those steps easily.

0
votes

Just have show the part of you code. Which is working good.

#include<stdio.h>
int main()
{
    FILE *file;
    int agent1, agent2;
    char c, s1[10],s2[10],currentline[100];
    char currentLine [100];
    file = fopen ("test.txt" , "r");
    while (fgets(currentline, 100, file) != NULL) {
            printf("currentline = %s\n", currentline);
            fflush(stdout);
                sscanf(currentLine, "%d %d %c %s %s", &agent1, &agent1, &c, s1, s2); 
    }
    fclose(file);
    return 0;
}

file test.txt

32 10 a megharaj india

output

currentline = 32 10 a megharaj india