I have a program that writes struct
to a binary file and then reads it, but the entered data does not match with output data, after reading it, there are wrong characters.
This is what I expected after entering data:
|First Name | Last Name | Location | ID |
--------------------------------------------------------------
John Doe London 1
This is what I got:
|First Name | Last Name | Location | ID |
--------------------------------------------------------------
└$↔ | îQ@ | á¡ K∙⌂ | 1385584
How can this be fixed, so that the output is formatted in readable characters? I tried changing the struct element sizes but after increasing after 16 and reducing below 15, i got additional read errors.
The program looks like this:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#pragma GCC diagnostic ignored "-Wwrite-strings"
struct user{
char firstname[16], lastname[16], location[16];
unsigned int id;};
struct user * data_entry(){
struct user *data = (struct user*) malloc(sizeof(struct user));
printf("Enter first name:");
scanf("%s", data->firstname);
printf("Enter last name:");
scanf("%s", data->lastname);
printf("Enter location:");
scanf("%s", data->location);
printf("Enter ID:");
scanf("%d", &data->id);
return data;}
int data_read(int bytes, int fd, const char *file){
struct user *data = NULL;
struct user *tmp;
int idx = 0;
int count = 0;
data = (struct user *)malloc(sizeof(struct user));
while (bytes > 0) {
bytes = read(fd, data + count, sizeof(struct user));
if (bytes == -1){
printf("File read error: %i (%s)\n", errno, strerror(errno));
close(fd);
free(data);
return errno;}
if (!bytes){
break;}
if (bytes < sizeof(struct user)){
printf("Error: read %i bytes out of %llu\n", bytes, sizeof(struct user));
close(fd);
free(data);
return errno;}
count++;
tmp = (struct user *)realloc(data, sizeof(struct user) * (count + 1));
if (!tmp){
close(fd);
free(data);
return errno;}
data = tmp;
}
printf("|First Name |"
" Last Name |"
" Location |"
" ID |\n");
printf("--------------------------------------------------------------\n");
while (count--){
printf("%-20s| %-20s| %-10s| %-7d\n",
(data + idx)->firstname,
(data + idx)->lastname,
(data + idx)->location,
&(data + idx)->id);
idx++;}
printf("\n[!] %i records from %s have been read\n", idx, file);
printf("-------------------------------------------\n");
return 0;
}
int main (){
int bytes = 1;
int fd;
int num;
struct user *sp;
const char *file = "data.bin";
struct user *tmp;
fd = open(file, O_CREAT | O_APPEND | O_RDWR, 0000777);
if (fd == -1){
printf("File open error: %i (%s)\n", errno, strerror(errno));
return fd;}
data_read(bytes, fd, file);
sp = (struct user *)malloc(sizeof(struct user));
if (!sp){
printf("Memory allocation has failed\n");
return -1;
}
sp = data_entry();
bytes = write(fd, &sp, sizeof(struct user));
if (bytes == -1) {
printf("File write error: %i (%s)\n", errno, strerror(errno));
close(fd);
return bytes;}
printf("User data saved to %u (%i bytes)\n", file, bytes);
free(sp);
close(fd);
return 0;
}
I have fixed your code. The biggest error was when writing data to the file where you passed &sp
while sp
is already a pointer.
open
, read
, write
and close
(Remove underscore if your compiler doesn't like that).Thee is still plenty of room for improvement.
#include <stdio.h>
#include <fcntl.h>
#include <io.h> // MSVC2019 want that
//#include <unistd.h> // MSVC2019 doesn't know it
#include <string.h>
#include <errno.h>
#include <stdlib.h>
struct user {
char firstname[16], lastname[16], location[16];
unsigned int id;
};
struct user* data_entry() {
struct user* data = malloc(sizeof(struct user));
if (data != NULL) {
printf("Enter first name:");
scanf("%s", data->firstname);
printf("Enter last name:");
scanf("%s", data->lastname);
printf("Enter location:");
scanf("%s", data->location);
printf("Enter ID:");
scanf("%d", &data->id);
}
return data;
}
int data_read(int fd, const char* fileName) {
int bytes;
struct user* data = NULL;
struct user* tmp;
int idx = 0;
int count = 0;
data = (struct user*)malloc(sizeof(struct user));
if (data == NULL) {
printf("Memory allocation error\n");
return errno;
}
while (1) {
bytes = _read(fd, data + count, sizeof(struct user));
if (bytes == 0) // End of file
break;
if (bytes == -1) {
printf("File read error: %i (%s)\n", errno, strerror(errno));
free(data);
return errno;
}
if (bytes != sizeof(struct user)) {
printf("Error: read %i bytes out of %d\n", bytes, sizeof(struct user));
free(data);
return errno;
}
count++;
tmp = (struct user*)realloc(data, sizeof(struct user) * (count + 1));
if (!tmp) {
free(data);
return errno;
}
data = tmp;
}
printf("|First Name |"
" Last Name |"
" Location |"
" ID |\n");
printf("--------------------------------------------------------------\n");
while (count--) {
printf("%-20s| %-20s| %-10s| %-7u\n",
(data + idx)->firstname,
(data + idx)->lastname,
(data + idx)->location,
(data + idx)->id);
idx++;
}
printf("\n[!] %i records from %s have been read\n", idx, fileName);
printf("-------------------------------------------\n");
free(data);
return 0;
}
int main() {
int bytes;
int fd;
struct user* sp;
const char* file = "data.bin";
fd = _open(file, O_CREAT | O_APPEND | O_RDWR, 0000777);
if (fd == -1) {
printf("File open error: %i (%s)\n", errno, strerror(errno));
return 1;
}
data_read(fd, file);
sp = data_entry();
if (sp == NULL) {
printf("data_entry failed\n");
_close(fd);
return 1;
}
bytes = _write(fd, sp, sizeof(struct user));
if (bytes != sizeof(struct user)) {
if (bytes == -1)
printf("File write error: %i (%s)\n", errno, strerror(errno));
else
printf("Not all bytes written to file\n");
_close(fd);
return 1;
}
printf("User data saved to %s (%i bytes)\n", file, bytes);
free(sp);
_close(fd);
return 0;
}