1

The program asks user to input some records (structures) if necessary and appends them to the existing file or creates a new file if there isn't any, then lists the contents of the file.

#include <stdio.h>
#include <string.h>
#define N 25

int main() {

  struct studrec {
    char name[20], surname[20], sex, date[12];
  } students[N];
  int i, count = 0;
  char another;

  FILE *fileptr;

  for (i = 0; i < 10; i++) {
    puts("Press y to continue without adding new records");
    another = getchar();
    if (another == 'y' || another == 'Y') break;
    while ((another = getchar()) != '\n' && another != EOF);
    puts("Input info");

    puts("Name: ");
    if (fgets(students[i].name, sizeof(students[i].name), stdin) == NULL) return 1;
    students[i].name[strlen(students[i].name)-1] = '\0';

    puts("Surname: ");
    if (fgets(students[i].surname, sizeof(students[i].surname), stdin) == NULL) return 1;
    students[i].surname[strlen(students[i].surname)-1] = '\0';

    puts("Sex (m/f): ");
    students[i].sex = getchar();
    while ((another = getchar()) != '\n' && another != EOF);

    puts("Date (dd.mm.yyyy): ");
    if (fgets(students[i].date, sizeof(students[i].date), stdin) == NULL) return 1;
    students[i].date[strlen(students[i].date)-1] = '\0';
    while ((another = getchar()) != '\n' && another != EOF);
   }
   count = i;

   fileptr = fopen("students.txt", "a+");
   for (i = 0; i < count; i++) fwrite(&students, sizeof(students), 1, fileptr);

   rewind(fileptr);
   for (i = 0; (another = fgetc(fileptr)) != EOF && i < N; i++) {
     fseek(fileptr, -1, SEEK_CUR);
     fread(&students, sizeof(students), 1, fileptr);
   }
   fclose(fileptr);

   count = i;
   for (i = 0; i < count; i++) printf("%20s%20s%4c%15s\n", students[i].name, students[i].surname, students[i].sex, students[i].date);

   return 0;
}

Everything works normally when writing to a new file. Output:

...input procedure...
Press y to continue without adding new records
y
                Liam               James   m     12.03.1987
               Abbey             Trueman   f     23.07.1943
                Hugo               Brown   m     13.05.1947

But then if I run it again and try to append another record to the existing file the program fails:

...input procedure...
Press y to continue without adding new records
y
               Nadia          Rachmonoff   f     12.07.1934
                                    O|u                  
                  �u                       �              u
                                           �           E�u

It seems that the new record is put in students[0] and all the other elements are erased. What am I doing wrong? Maybe there's something wrong with the &students pointer. I tried with &students[i] but it returned "segmentation fault" after the first iteration. As I understand the &students address is "automatically" incremented to the next element after every fread/fwrite. If it wasn't so the program would not work correctly on the first run.

1
  • Why do you write students to the file count times? Commented Dec 3, 2011 at 21:11

3 Answers 3

3

You have a few issues with how you deal with the arrays. First of all, this line:

for (i = 0; i < count; i++) fwrite(&students, sizeof(students), 1, fileptr);

What you're doing here running a loop, with one pass for each record entered, and writing the whole array of 25 items to the file on each pass. So if 3 records were entered, you write 75, most of which are garbage or redundant. What you probably want here is more like this:

for (i = 0; i < count; i++)
  fwrite(&students[i], sizeof(students[i]), 1, fileptr);

...where the size is the size of one element of the array (a single record) and the address is the address of the record you're currently writing rather than the address of the whole array.

You have a similar problem when reading the data later, among others:

rewind(fileptr);
for (i = 0; (another = fgetc(fileptr)) != EOF && i < N; i++) {
  fseek(fileptr, -1, SEEK_CUR);
  fread(&students, sizeof(students), 1, fileptr);
}

First, the fread(&students, sizeof(students), 1, fileptr); should be changed much like the fwrite() before, to fread(&students[i], sizeof(students[i]), 1, fileptr);. The reasons are the same: You're reading one record at a time in a loop, so you need to read into that item not just to the beginning of the array each time, and the amount of data you read should be the size of that record rather than the size of the whole array.

Second, though fixing the above should get it working, you could easily change the loop so that you don't need to read the single char in the loop expression to check for EOF. You should really check for that by checking the return from the fread() in the loop instead. Something like:

rewind(fileptr);
for (i = 0; i < N; i++) {
  if (fread(&students[i], sizeof(students[i]), 1, fileptr) != 1)
    break;
}

Or better yet, just read N items with no loop, and use the return value to tell you how many were read:

rewind(fileptr);
i = fread(students, sizeof(students[0]), N, fileptr);
Sign up to request clarification or add additional context in comments.

6 Comments

+1 Just curious. What is the motivation to write so lengthy answer?
@RomanB. Just for added clarity. The sorts of mistakes the poster made would probably only be made by someone who has difficulty understanding the details, so a terse answer may be inadequate. I'd rather explain too much than not enough; extra details can be ignored, but missing details just make the answer unhelpful.
@RomanB. - Why not write a lengthy, detailed answer? I don't understand this sentiment at all. Dmitri logged on to Stack Overflow to ask and answer questions. Providing terse answers seems even more pointless than providing detailed answers!
KevinVermeer Well, it was merely a discussion between him and me. But if you've mixed in I can ask you the same. I do not understand what is the stimulus of highly professional developers to write such answers and even to read this code. But you're not the one. So you're not right person to ask.
@KevinVermeer Sorry, I've missed @ in my previous comment.
|
0

The following writes the entire 25-element array count times:

for (i = 0; i < count; i++) fwrite(&students, sizeof(students), 1, fileptr);

There are two ways to fix this:

  1. Compute the correct size occupied by the count elements, and write them out with a single fwrite call.
  2. Write the entries out one a time, using a loop.

The same goes for the loop that tries to read the elements back: each iteration reads the entire 25-element array.

1 Comment

@RomanB.: It was easy after running the code and looking at the output file.
0

Your writing code is incorrect, try

   fwrite(students, sizeof*students, i, fileptr);

   rewind(fileptr);
   for (i = 0; i < N && fread(&students[i], sizeof*students, 1, fileptr); i++);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.