0

I have this kind of struct:

  typedef struct {
  char a[MAX];
  char b[MAX];
  int c;
  } mys;

and this functions:

mys* search_m(FILE *fp, int m)
  {
    mys* s;
    s=(mys *)malloc(sizeof(mys));
    if(s){
      for(int i=0;i<m;i++)
        fread(s,sizeof(mys),1,fp);
    }else{
      printf("Error during allocation\n");
    }
    return s;
  }


  void search_s(FILE *fp, char *c)
  {
    mys s;
    int count=0;

    while(fread(&s,sizeof(mys),1,fp)==1){

        if(strcmp(s.b,c)==0){
          show_s(s,count);

        }
        count++;
    }    
     return;
  }

that's a part of my program. During the input fase (when I write data on my file) I don't have any problem ( using fread) but I have some problem reading it.

The my function search_s execute and find the value every time that I call it, but the search_m function seems that can't read anby data in my file and since it's practically the same things that I did on search_s I don't know where is my mistake.

In my main when I call seach_m I do this:

s=*search_ID(f_ptr,m);
show_s(s,m);

I don't think that the problem is in the main since the fread in the search_m function doesn't load any data (it stops on the first try).

Where is my mistake? I thought that it was all right PS before calling this function I open the file and I check for errors and after I close the file.

EDIT: I'm opening the file with this:

f_ptr=fopen(argv[1],"rb");

(It doesn't work (also) if I only use "r") argv[1] is the name of my file

PS m is the number of the element in the file that I want to read. (I read every time one block untile I don't get the m-esimo element)

My file contains only struct of that type.

Ofey
  • 167
  • 7
  • how are you opening your file ? and are you using the same handle? we need calling context here. – Jean-François Fabre Mar 12 '18 at 19:57
  • What is the `search_m()` function supposed to do? Read and return many or just one? – 001 Mar 12 '18 at 20:07
  • @JohnnyMopp it's suppose to find a struct in the file with the b parameter equal to the string of char passed c and print it – Ofey Mar 12 '18 at 20:09
  • @Ofey Sounds like that's the `search_s()` function. Question: are you reading the file elsewhere? Do you need to `rewind` the file before searching again. – 001 Mar 12 '18 at 20:12
  • If you want your code to work portably and independent of byte order, padding and so on, consider using a serialization library, for example my own one ( https://github.com/Erlkoenig90/uSer ). If the format is not fixed, several others are suitable too. – Erlkoenig Mar 12 '18 at 20:12
  • @JohnnyMopp the two function do practically the same thing but one works and the other don't. I'm not ready the file elsewhere, before colling any of this function I open the file and after returning I close it. In short I open and close the file each time. – Ofey Mar 12 '18 at 20:14
  • I now see that in your post. Another question: the function is `search_m()` but in your example you have: `search_ID(f_ptr,m);`. Is that just a typo? – 001 Mar 12 '18 at 20:20
  • In `count_students()` you read the file to the end. Then you call `search_ID()` without resetting the file. Checking the return value from `fread()` might have helped you. – 001 Mar 12 '18 at 20:28
  • @JohnnyMopp yeah but I close the file and I start reading it every time. Doesn't it start from the beginning every time? – Ofey Mar 12 '18 at 20:29
  • No. You don't do it between `count_students()` and `search_ID()`. After `count_students()` add `rewind(f_ptr);` to set the file pointer back to the beginning of the file. – 001 Mar 12 '18 at 20:33
  • you are right @JohnnyMopp. Thank you! You solved my problem – Ofey Mar 12 '18 at 20:35

2 Answers2

0

The following line does not allocate enough memory.

s=(mys *)malloc(sizeof(mys));

You are allocating memory for just object. As a result, you are accessing more memory than you allocated, which causes undefined behavior.

You need to allocate memory for m objects.

s = malloc(sizeof(mys)*m);

See Do I cast the result of malloc? to understand why you should not cast the return value of malloc.

Also, make sure that you read into the appropriate slot of the allocated memory.

mys* search_m(FILE *fp, int m)
{
  mys* s = malloc(sizeof(mys)*m);
  if(s){
    for(int i=0;i<m;i++)
      fread(s+i, sizeof(mys), 1, fp);  // Use s+i
  }else{
    printf("Error during allocation\n");
  }
  return s;
}

You can compress that to just one call to fread.

mys* search_m(FILE *fp, int m)
{
  mys* s = malloc(sizeof(mys)*m);
  if(s){
    fread(s, sizeof(mys), m, fp);
  }else{
    printf("Error during allocation\n");
  }
  return s;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

This is how you would read and write a struct to a file. You should then be able to open your file with fopen and call read_data and write_data for each of your data structures. Once read_data returns 0, it has reached EOF. This can be error prone though, as this depends on the size of the struct. If its size change between versions of your application, it might not be able to deserialize the struct correctly.

struct st_data 
{
    char str[25];
    int i;
    int j;
};

typedef struct st_data data_t;

size_t write_data(data_t *data, FILE *stream)
{
    return fwrite(data, sizeof(*data), 1, stream);
}

size_t read_data(data_t *data, FILE *stream)
{
    return fread(data, sizeof(*data), 1, stream);
}

void search(char *str, FILE *stream)
{
    data_t data;
    size_t n_read = read_data(&data, stream);

    while (n_read > 0)
    {
        if (strcmp(data.str, str) == 0)
        {
            // handle data
        }

        n_read = read_data(&data, stream);
    }
}

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        fprintf(stderr, "ERROR: requires a single argument");
        exit(-1);
    }

    FILE *stream = fopen("data.txt", "rb+");

    search(argv[1], stream);

    fclose(stream);

    exit(0);   
}
Jazzwave06
  • 1,883
  • 1
  • 11
  • 19