Dynamically allocating array of struct from file in C - c

I have a program that I am trying to write that will open a file named list.txt, this file will contain a num, a ID, and a string name on each line. This program will read list.txt file and sort ID numbers and print sorted ID with number and name to index.txt file. I wrote a program code and it's working...
Here is my list.txt
(num, ID, name)
0 3 AB
1 2 BC
2 28 DC
3 1 EF
4 13 BB
10 30 CC
11 23 FF
14 16 GG
After compiled this program sorted ID with number and name, print to index.txt and it should be:
(ID, num, name)
1 3 EF
2 1 BC
3 0 AB
13 4 BB
16 14 GG
23 11 FF
28 2 DC
30 10 CC
Here is my program code:
#include <stdio.h>
#include <conio.h>
#include <process.h>
#include <stdlib.h>
#include <string.h>
#define NUM_NUMBERS 9
typedef struct student
{
int num;
int id;
char name[100];
}end;
void update();
void Sort(student array[], int n);
void load_menu();
void add(end *e);
void search(end e);
void view(end e);
FILE *fp;
FILE *f1;
int main(int argc, char** argv)
{
load_menu();
return 0;
}
void update()
{
end st[15];
int sayi[NUM_NUMBERS], number, i=0, j=0;
fp=fopen("list.txt", "r");
if( fp == NULL )
{
printf("File is not found at add();\n");
exit(0);
}
while(!feof(fp))
{
fscanf(fp,"%d%d%s",&st[i].num,&st[i].id,st[i].name);
i++;
}
Sort(st, NUM_NUMBERS);
f1=fopen("index.txt", "w");
for(int i=0; i<NUM_NUMBERS;i++)
{
fprintf(f1, "%d %d %s\n", st[i].id, st[i].num, st[i].name);
}
}
void Sort(end array[], int n)
{
int Min;
for(int i=0; i<n-1;i++)
{
Min=i;
for(int j=i+1;j<n;j++)
{
if(array[j].id<array[Min].id)
{
Min=j;
}
}
end temp=array[i];
array[i]=array[Min];
array[Min]=temp;
}
}
void load_menu(void)
{
end e;
int choice;
do
{
printf("1. Find a record given its ID value \n");
printf("2. Add a new record to the file \n");
printf("3. View Records\n");
printf("4. Exit\n\n");
printf("Please choose one: ");
scanf("%d",&choice);
switch(choice)
{
case 1:
search(e);
break;
case 2: add(&e);
update();
break;
case 3: view(e);
break;
case 4: printf("Done.");
return;
break;
default: printf("Invalid choice\n");
}
}while (choice != 5);
system("cls");
}
void add(end *e)
{
int i=0;
system("cls");
fp = fopen ( "list.txt", "a" );
if( fp == NULL )
{
printf("File is not found at add();\n");
exit(0);
}
printf("\n-----Add a new record-----\n");
printf("Enter number: ");
scanf("%d", &e->num);
printf("\nEnter ID : ");
scanf("%d",&e->id);
printf("\nEnter name: ");
scanf("%s",e->name);
fscanf(fp,"%d %d %s\n\n",&e->num, &e->id, e->name);
fprintf(fp,"%d %d %s\n\n",e->num ,e->id, e->name);
fclose(fp);
return;
}
void search(end e)
{
int i=0;
int sid;
system("cls");
fp = fopen ("list.txt", "r");
if(fp==NULL)
{
printf("File is not found at search();");
}
printf("\n-----Search ID-----\n");
printf("\nEnter ID : ");
scanf("%d",&sid);
printf("\nNumber ID Name");
while(!feof(fp))
{
fscanf(fp,"%d %d %s", &e.num, &e.id, &e.name);
if(sid==e.id)
{
printf("\n%d %d %s",e.num ,e.id, e.name);
}
}
printf("\n\n");
fclose(fp);
}
void view(end e)
{
int i=0;
system("cls");
printf("\n-----list.txt-----\n");
fp = fopen("list.txt", "r");
if(fp == NULL)
{
printf("File is not found at view();\n");
exit(0);
}
printf("\nNumber ID Name");
printf("\n");
while(fscanf (fp, "%d %d %s ",&e.num, &e.id, &e.name) != EOF )
printf("\n%d %d %s",e.num ,e.id, e.name);
printf("\n\n");
printf("-----index.txt-----\n");
f1 = fopen("index.txt", "r");
if(fp == NULL)
{
printf("File is not found.\n");
exit(0);
}
printf("\nNumber ID Name");
printf("\n");
while(fscanf (f1, "%d %d %s ",&e.id, &e.num, &e.name) != EOF )
printf("\n%d %d %s",e.id ,e.num, e.name);
printf("\n\n");
fclose(fp);
fclose(f1);
return;
}
But I used only array so I need to dynamically allocate at array of struct to store the info. Still don't know how to use dynamically allocate (malloc). Could you please show me how to use dynamically with code? Thanks for helps. (Sorry for bad english.)

sample code:
#include <stdio.h>
#include <stdlib.h>
typedef struct student{
int num;
int id;
char name[100];
}end;
int cmp(void const *a, void const *b){
const end *x = a;
const end *y = b;
return x->id < y->id ? -1 : x->id > y->id;
}
int main(void){
end *st = NULL, tmp;
FILE *fp;
size_t i = 0, n = 0;
fp=fopen("list.txt", "r");
if( fp == NULL ) {
perror("fopen at XXX");
exit(EXIT_FAILURE);
}
while(3 == fscanf(fp,"%d %d %s", &tmp.num, &tmp.id, tmp.name)){
end *temp = realloc(st, ++n * sizeof(*st));//Secure multiple records when the number of records is large
if(temp == NULL){
perror("realloc at XXX");
free(st);
exit(EXIT_FAILURE);
}
st = temp;
st[i++] = tmp;
}
fclose(fp);
qsort(st, n, sizeof(*st), cmp);
fp=fopen("index.txt", "w");
for(i = 0; i < n; ++i){
fprintf(fp, "%d %d %s\n", st[i].id, st[i].num, st[i].name);
}
fclose(fp);
free(st);
}

malloc() returns a pointer to the memory you allocated. The argument is the size of the memory you want to allocate, so in your case its the size of of "end".
You need to declare a pointer to "end" first and then call malloc().
end * ptr = malloc(sizeof(end));
But thats just one Element. You should definitely check out a tutorial for lists in c.

Related

Scan (read) from BIN file

I need to solve a problem. I need to create two functions which scan user's input information and put in into structure array and then put all array to BIN file (with function fwrite()) and other function - read from BIN file with function fread(). You can see my code below. Problem is that I can write to file, but when I read I get filler array element and other element which are empty. How to get only filled struct array element?
#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
typedef struct
{
char Lesson[50];
char TeachersName[50];
char TeachersLastName[50];
int Credits;
int NumberOfStudents;
} School;
void ToFile (char *fileName);
void FromFile (char *FileName);
int main()
{
char *fileName[]={"student.bin"};
ToFile (*fileName);
FromFile (*fileName);
return 0;
}
void ToFile (char *fileName)
{
int n, chars;
FILE *fp;
fp = fopen(fileName, "wb");
School Info[20];
if(fp == NULL)
{
printf("Error opening file\n");
exit(1);
}
printf("Testing fwrite() function: \n\n");
printf("Enter the number of records you want to enter: ");
scanf("%d", &n);
for(int i = 0;i<n;i++)
{
printf("\nEnter details of employee %d \n", i + 1);
fflush(stdin);
printf("Lesson: ");
gets(Info[i].Lesson);
printf("Teachers name: ");
gets(Info[i].TeachersName);
printf("Teachers last name: ");
gets(Info[i].TeachersLastName);
printf("Credits: ");
scanf("%d", &Info[i].Credits);
printf("Number of studens: ");
scanf("%d", &Info[i].NumberOfStudents);
chars = fwrite(&Info[i], sizeof(Info), 1, fp);
printf("Number of items written to the file: %d\n", chars);
}
fclose(fp);
}
void FromFile (char *FileName)
{
School Info[20]= { { "", "","",0,0 } };;
FILE * fpp;
fpp = fopen(FileName, "rb");
fread(&Info, sizeof(Info), 1, fpp);
/*
for(int j=0; j<20; ++j) {
printf("\nLesson: %s", Info[j].Lesson);
printf("\nTeachers name: %s", Info[j].TeachersName);
printf("\nTeachers last name: %s", Info[j].TeachersLastName);
printf("\nCredits: %d", Info[j].Credits);
printf("\nNumber of students: %d", Info[j].NumberOfStudents);
printf("\n");
}*/
int j=0;
while (fread(&Info, sizeof(Info), 1, fpp))
{
printf("\nLesson: %s", Info[j].Lesson);
printf("\nTeachers name: %s", Info[j].TeachersName);
printf("\nTeachers last name: %s", Info[j].TeachersLastName);
printf("\nCredits: %d", Info[j].Credits);
printf("\nNumber of students: %d", Info[j].NumberOfStudents);
printf("\n");
j++;
}
fclose(fpp);
}

Invalid number comes when accessing member structures

I am new to c language. I add the structure members(int dd) to file(file.txt) and now am trying to read that file to access structure members(Day.dd). But when I add 5 to a variable through scanf() function and compile that file and run, I did not get (Day = 5). I got Day = 1325715504
My code is:
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
struct DailyCost
{
int dd;
} Day;
FILE *fp;
void add_dailycost();
void display();
void mainmenue();
int main()
{
int j;
fp = fopen("/home/mohit/projects/c/gedit_Dailyost/TextFiles/fileb.txt", "w+");
rewind(fp);
mainmenue();
return 0;
}
void mainmenue()
{
struct DailyCost day1;
int j;
printf("Enter 1 to add dailycost and enter 2 display dailycost.");
scanf("%d", &j);
switch (j)
{
case 1:
add_dailycost(day1);
break;
case 2:
display(day1);
break;
}
}
void add_dailycost(struct DailyCost Day)
{
if (fp != NULL)
{
fseek(fp, 0L, SEEK_END);
}
int j;
printf("Enter Day = ");
scanf("%d", &Day.dd);
fwrite(&Day, sizeof(struct DailyCost), 1, fp);
printf("If menmenue press 1 and exit press 0 = ");
scanf("%d", &j);
if (j == 1)
{
mainmenue();
}
else
{
printf("\nThank you");
fclose(fp);
exit(0);
}
}
void display(struct DailyCost Day)
{
fread(&Day, sizeof(struct DailyCost), 1, fp);
rewind(fp);
printf("Day = %d\n", Day.dd);
fclose(fp);
}
Please suggest what I had done wrong to code a program. And how to fix this problem, by taking my code.
As suggested by Klaus Gütter use call by reference, to make changes to original object.
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
struct DailyCost
{
int dd;
} Day;
FILE *fp;
void add_dailycost();
void display();
void mainmenue();
int main()
{
int j;
fp = fopen("/home/mohit/projects/c/gedit_Dailyost/TextFiles/fileb.txt", "w+");
rewind(fp);
mainmenue();
return 0;
}
void mainmenue()
{
struct DailyCost day1;
int j;
printf("Enter 1 to add dailycost and enter 2 display dailycost.");
scanf("%d", &j);
switch (j)
{
case 1:
add_dailycost(&day1);
break;
case 2:
display(&day1);
break;
}
}
void add_dailycost(struct DailyCost* Day) /*if you pass simply
struct DailyCost , all the contents of original objects will be copied
into a new memory area, to be used in this function and will be
destroyed when this function exits. */
/* if you pass just the address of your object,you are working on
the same memory area as you passed from,in this case from mainmenue. */
{
if (fp != NULL)
{
fseek(fp, 0L, SEEK_END);
}
int j;
printf("Enter Day = ");
scanf("%d", &Day->dd);
fwrite(Day, sizeof(struct DailyCost), 1, fp);
printf("If menmenue press 1 and exit press 0 = ");
scanf("%d", &j);
if (j == 1)
{
mainmenue();
}
else
{
printf("\nThank you");
fclose(fp);
exit(0);
}
}
void display(struct DailyCost* Day) /* passing the object instead
of reference would also work here. But just for the display
purpose, you need not to unnecessarily create a new memory. */
{
fread(Day, sizeof(struct DailyCost), 1, fp);
rewind(fp);
printf("Day = %d\n", Day->dd);
fclose(fp);
}
Read about call by value and call by reference, and passing struct as argument in the internet, if you are not clear yet.

How would I go about saving and reading an integer then a struct array in the same .dat file? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
Basicly, I have a counter that I need to save and read as an integer as the first thing in a data file while in the same data file save a struct array. I don't want to post my entire code as its a bit too long but below are the functions that I have written so far.
void write(InventoryItemType *writefile[], int count)
{
int i;
FILE *ptr;
ptr=fopen("inventory.dat","wb");
if(ptr==NULL)
{
printf("Unable to Open File\n");
system("pause");
return;
}
putw(count, ptr);
for(i=0;i < count; i++)
{
fwrite(&writefile[i], sizeof writefile, 1, ptr);
}
fclose(ptr);
}
InventoryItemType *read(InventoryItemType *readfile[])
{
int i, count;
FILE *ptr;
ptr=fopen("inventory.dat","wb");
if(!ptr)
{
printf("Unable to Open File\n");
system("pause");
return;
}
count=getcount();
for(i=0;i < count; i++)
{
fread(&readfile[i], sizeof readfile, 1, ptr);
}
fclose(ptr);
return *readfile;
}
int getcount(void)
{
int i;
FILE *ptr;
ptr=fopen("inventory.dat","wb");
if(ptr<=0)
{
i=0;
return i;
}
i=getw(ptr);
fclose(ptr);
return i;
}
I call the functions in the main block like so:
At the top of code for file reading:
int i=0, item_count=getcount();
char selection, code[4];
InventoryItemType *inventoryItems[MAX_INVENTORY_SIZE];
*inventoryItems=read(inventoryItems);
And at the exit statements like so:
write(inventoryItems, item_count);
break;
I am relatively new to this concept so any help would be appreciated.
memmory allocation edit:
InventoryItemType *addItem(void)
{
InventoryItemType *current = (InventoryItemType*) malloc (sizeof *current);
system("cls");
if(current == NULL)
return NULL;
....
system("cls");
return current;
}
EDIT #2: I tried my best to implement your suggestions. Currently, I get a value of -1 for count. Here is the updated code:
Calling Functions for Reading:
int i=0, item_count=getcount();
char selection, code[4];
InventoryItemType *inventoryItems[MAX_INVENTORY_SIZE];
reader(inventoryItems);
Calling Function for writing:
case 'A' :
writer(inventoryItems, item_count);
break;
Reading Functions:
void reader(InventoryItemType *readfile[])
{
int i, count;
FILE *ptr;
ptr=fopen("inventory.dat","rb");
if(!ptr)
{
printf("Unable to Open File\n");
system("pause");
return;
}
count=getcount();
for(i=0;i < count; i++)
{
fread(&readfile[i], sizeof (InventoryItemType), 1, ptr);
}
fclose(ptr);
return;
}
int getcount(void)
{
int i;
FILE *ptr;
ptr=fopen("inventory.dat","rb");
if(ptr==NULL)
{
i=0;
return i;
}
i=getw(ptr);
return i;
}
Writing Functions:
void writer(InventoryItemType *writefile[], int count)
{
int i;
FILE *ptr;
ptr=fopen("inventory.dat","wb");
if(ptr==NULL)
{
printf("Unable to Open File\n");
system("pause");
return;
}
putw(count, ptr);
for(i=0;i < count; i++)
{
fwrite(&writefile[i], sizeof (InventoryItemType), 1, ptr);
}
}
EDIT #3: Entire code just.. frustration setting in Q_Q
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INVENTORY_SIZE 100
typedef struct {
char item_Number[4];
char item_Name[20];
float item_Profit;
float latest_Price;
float selling_Price;
unsigned int stock;
unsigned int total_Sold;
}InventoryItemType;
void MainMenu();
void displayInventory(InventoryItemType *[], int);
void displaySales(InventoryItemType *[], int);
InventoryItemType *addItem(void);
InventoryItemType *deleteItem(InventoryItemType *[], int);
InventoryItemType *newShipment(InventoryItemType *[], int);
InventoryItemType *updateSales(InventoryItemType *[], int);
InventoryItemType *bubbleSort(InventoryItemType *[], int, char);
void swap(InventoryItemType *[], InventoryItemType *[]);
void writer(const char *,InventoryItemType *[], size_t );
void reader(const char *,InventoryItemType *[], size_t );
int main()
{
int i=0, item_count=0;
char selection, code[4];
const char file[]={"inventory.dat"};
InventoryItemType *inventoryItems[MAX_INVENTORY_SIZE];
reader(file,inventoryItems,item_count);
while(1)
{
MainMenu();
scanf(" %c", &selection);
switch(selection)
{
case 'A' :
displayInventory(inventoryItems, item_count);
system("pause");
system("cls");
continue;
case 'B' :
displaySales(inventoryItems, item_count);
system("pause");
system("cls");
continue;
case 'C' :
if(item_count == MAX_INVENTORY_SIZE - 1)
{
printf("Array is full\n");
system("pause");
continue;
}
inventoryItems[item_count] = addItem();
item_count++;
continue;
case 'D' :
*inventoryItems=deleteItem(inventoryItems, item_count);
item_count--;
continue;
case 'E' :
*inventoryItems=newShipment(inventoryItems, item_count);
continue;
case 'F' :
*inventoryItems=updateSales(inventoryItems, item_count);
continue;
case 'G' :
while(1)
{
system("cls");
printf("A. Sort by Name\n");
printf("B. Sort by Item Number\n");
scanf(" %c", &selection);
switch(selection)
{
case 'A' :
*inventoryItems=bubbleSort(inventoryItems, item_count, selection);
break;
case 'B' :
*inventoryItems=bubbleSort(inventoryItems, item_count, selection);
break;
default:
{
printf("Invalid Input!\n");
system("pause");
continue;
}
}
break;
}
continue;
case 'H' :
while(1)
{
printf("Would you like to save your changed?\n");
printf("A. Yes\n");
printf("B. No\n");
scanf(" %C", &selection);
switch(selection)
{
case 'A' :
writer(file,inventoryItems,item_count);
break;
case 'B' :
break;
default:
{
printf("Invalid Input!\n");
system("pause");
continue;
}
}
break;
}
continue;
default :
printf("Invalid Entry\n" );
system("pause");
}
}
}
void MainMenu()
{
system("cls");
printf("A. Display Inventory\n");
printf("B. Display Sales\n");
printf("C. Add Item\n");
printf("D. Remove Item\n");
printf("E. Enter Shipment\n");
printf("F. Update Sales\n");
printf("G. Sort\n");
printf("H. Exit\n");
printf("Make a selection\n");
}
void displayInventory(InventoryItemType *display[], int key)
{
system("cls");
{
int i;
for(i=0; i<key; i++)
{
printf("Item No.:%s\n", display[i]->item_Number);
printf("Item Name:%s\n", display[i]->item_Name);
printf("Item Stock:%d\n",display[i]->stock);
printf("Item Purchased Price:%.2f\n", display[i]->latest_Price);
printf("Total Value of Items:%.2f\n", (display[i]->stock)*(display[i]->latest_Price));
printf("\n");
}
}
}
void displaySales(InventoryItemType *display[], int key)
{
int i;
float total_profit=0;
system("cls");
for(i=0; i<key; i++)
{
printf("Item No.:%s\n", display[i]->item_Number);
printf("Item Name:%s\n", display[i]->item_Name);
printf("Number of Item Sold:%d\n", display[i]->total_Sold);
printf("Item Selling Price:%.2f\n", display[i]->selling_Price);
printf("Total Profit from Item:%.2f\n", (display[i]->selling_Price-display[i]->latest_Price)*display[i]->total_Sold);
total_profit=total_profit+((display[i]->selling_Price-display[i]->latest_Price)*display[i]->total_Sold);
if(i==key-1)
printf("\nTotal Over-all Profit:%.2f", total_profit);
printf("\n\n");
}
}
InventoryItemType *addItem(void)
{
InventoryItemType *current = (InventoryItemType*) malloc (sizeof *current);
system("cls");
if(current == NULL)
return NULL;
printf("\nEnter details of item \n\n");
printf("Enter Item no: \n");
scanf("%s", current->item_Number);
printf("Enter Item Name: \n");
scanf("%s", current->item_Name);
printf("Enter Stock: \n");
scanf("%d", &current->stock);
printf("Enter Purchase Price: \n");
scanf("%f", &current->latest_Price);
current->selling_Price=(current->latest_Price)*1.5;
current->total_Sold=0;
system("cls");
return current;
}
InventoryItemType *deleteItem (InventoryItemType *deleted[], int item_count)
{
char code[4];
int i;
system("cls");
displayInventory(deleted,item_count);
printf("Enter Item Number to be Deleted\n");
scanf("%3s", code);
for(i=0;i<item_count;i++)
{
if(strcmp(code,deleted[i]->item_Number)==0)
break;
}
free(deleted[i]);
for(;i<item_count; i++)
deleted[i]=deleted[i+1];
return *deleted;
}
InventoryItemType *newShipment (InventoryItemType *shipment[], int item_count)
{
char code[4];
int i, add;
float newprice;
while(1)
{
system("cls");
displayInventory(shipment, item_count);
printf("\nEnter Item Number to Update Stock\n");
scanf("%3s", code);
for(i=0;i<item_count;i++)
{
if(strcmp(code,shipment[i]->item_Number)==0)
{
printf("Enter the Quantity of Item being added\n");
scanf("%d", &add);
printf("Enter the Purchase Price of the Item\n");
scanf("%f", &newprice);
shipment[i]->stock=shipment[i]->stock+add;
shipment[i]->latest_Price=newprice;
shipment[i]->selling_Price=shipment[i]->latest_Price*1.5;
displayInventory(shipment, item_count);
return *shipment;
}
}
printf("Invalid Item Number, Please Try Again\n");
system("Pause");
continue;
}
}
InventoryItemType *updateSales (InventoryItemType *sale[], int item_count)
{
char code[4], choice;
int i, sold;
while(1)
{
system("cls");
displayInventory(sale, item_count);
printf("\nEnter Item Number to Update Stock and Profits\n");
scanf("%3s", code);
for(i=0;i<item_count;i++)
{
if(strcmp(code,sale[i]->item_Number)==0)
{
printf("Enter the Quantity of Item Sold\n");
scanf("%d", &sold);
if(sale[i]->stock>sold)
{
sale[i]->stock=sale[i]->stock-sold;
sale[i]->item_Profit=sale[i]->selling_Price*sold;
displayInventory(sale, item_count);
system("pause");
return *sale;
}
else
{
printf("Invalid Input!\nThere can not be more sold than in stock!\nWould you like to try again?\n");
printf("A. Yes\n");
printf("B. No\n");
scanf(" %c", &choice);
switch(choice)
{
case 'A' :
system("cls");
displayInventory(sale, item_count);
continue;
case 'B' :
return *sale;
}
}
}
else
{
printf("Invalid Item Number, Please Try Again\n");
system("Pause");
}
}
}
}
void swap(InventoryItemType *a[], InventoryItemType *b[])
{
InventoryItemType *temp=*a;
*a=*b;
*b=temp;
}
InventoryItemType *bubbleSort(InventoryItemType *sorting[], int item_count, char swaptype)
{
int i, sorted;
system("cls");
if(swaptype=='A')
{
do{
sorted=1;
for (i = 0; i < item_count - 1; i++)
{
if (strcmp(sorting[i]->item_Name,sorting[i + 1]->item_Name)==1)
{
swap(&sorting[i],&sorting[i + 1]);
sorted = 0;
}
}
}while(!sorted);
}
else
{
do{
sorted=1;
for (i = 0; i < item_count - 1; i++)
{
if (strcmp(sorting[i]->item_Number,sorting[i + 1]->item_Number)==1)
{
swap(&sorting[i],&sorting[i + 1]);
sorted = 0;
}
}
}while(!sorted);
}
printf("Your Inventory is Sorted!\n\n");
system("pause");
return *sorting;
}
void writer(const char *fname,const InventoryItemType *saveinventory , size_t count)
{
FILE *ptr = fopen(fname, "wb");
if(ptr == NULL)
{
fclose(ptr);
printf("Unable to Open File\n");
system("pause");
return;
}
if (fwrite(&count, sizeof(count), 1, ptr)!= 1)
{
fclose(ptr);
printf("Write count failed\n");
system("pause");
return;
}
if (fwrite(saveinventory, sizeof (*saveinventory), count, ptr)!= count)
{
fclose(ptr);
printf("Write inventory failed\n");
system("pause");
}
}
void reader(const char *fname,InventoryItemType **inventory_ptr, size_t *count_ptr)
{
InventoryItemType *inventory;
size_t count;
FILE *ptr = fopen(fname, "rb");
if(ptr == NULL) {
printf("Unable to Open File\n");
system("pause");
return;
}
if (fread(&count, sizeof count, 1, ptr)!= 1) {
fclose(ptr);
printf("Read count failed\n");
system("pause");
return;
}
inventory = (InventoryItemType *)malloc(sizeof *inventory * count);
if (inventory == NULL && count > 0) {
fclose(ptr);
printf("Allocation failed\n");
system("pause");
return;
}
if (fread(inventory, sizeof *inventory, count, ptr)!= count) {
fclose(ptr);
free(inventory);
printf("Read inventory failed\n");
system("pause");
return;
}
fclose(ptr);
*inventory_ptr = inventory;
*count_ptr = count;
return;
}
How would I go about saving and reading an integer then a struct array in the same .dat file?
I suggest an architecture change. Rather than
// void write(InventoryItemType *writefile[], int count)
// InventoryItemType *read(InventoryItemType *readfile[])
Consider
// return 0 on success
int iwrite(const char *fname, const InventoryItemType *inventory, size_t count)
int iread(const char *fname, InventoryItemType **inventory, size_t *count)
I found OP's approach too tangled.
To write, open the file, write the count and data. Recall the inventory is still allocated and eventually needs to be freed.
int iwrite(const char *fname, const InventoryItemType *inventory, size_t count) {
FILE *ptr = fopen(fname, "wb");
if(ptr == NULL) {
// printf("Unable to Open File\n");
return 1;
}
if (fwrite(&count, sizeof count, 1, ptr)!= 1) {
fclose(ptr);
// printf("Write count failed\n");
return 2;
}
if (fwrite(inventory, sizeof *inventory, count, ptr)!= count) {
fclose(ptr);
// printf("Write inventory failed\n");
return 3;
}
fclose(ptr);
return 0;
}
To write, open the file, read the count, allocate memory for the inventory and then read the inventory.
int iread(const char *fname, InventoryItemType **inventory_ptr, size_t *count_ptr) {
FILE *ptr = fopen(fname, "rb"); // read mode
if(ptr == NULL) {
// printf("Unable to Open File\n");
return 1;
}
size_t count;
if (fread(&count, sizeof count, 1, ptr)!= 1) {
fclose(ptr);
// printf("Read count failed\n");
return 2;
}
InventoryItemType *inventory = malloc(sizeof *inventory * count);
if (inventory == NULL && count > 0) {
fclose(ptr);
// printf("allocation failed\n");
return 3;
}
if (fread(inventory, sizeof *inventory, count, ptr)!= count) {
fclose(ptr);
free(inventory);
// printf("Read inventory failed\n");
return 3;
}
fclose(ptr);
*inventory_ptr = inventory;
*count_ptr = count;
return 0;
}
Thee are a number of problems in your code:
InventoryItemType *inventoryItems[MAX_INVENTORY_SIZE];
*inventoryItems=read(inventoryItems);
You declare an array of pointers to items and then you read the items. But in the code for reading the items, I do not see you allocate memory for the items. Then, when the function returns, you assign the returned result to *inventoryItems, that is you dereference the array and so have its first element. This seems like nonsense and you compiler should have complained. Do not return any thing from the function, except success/failure.
And note that read is the name of a function from the standard library. Use another name. Also for write.
When yu open the file, you specify "wb" but that means you open the file for writing. That should be "rb" (read binary).
In the read function, you read sizeof readfile bytes. But readfile is a pointer to an array of pointers. So sizeof readfile will be the size of a pointer. You should use sizeof *readfile[i] or sizeof(InventoryItemType).
But before you read anything into readfile[i], you should allocate memory for it! And note that readfile[i] is already a pointer, so you don't need the & operator in fread and fwrite.
As an example of what it should be, I provide the read function:
int myread(InventoryItemType *readfile)
{
int i, count;
FILE *ptr;
ptr=fopen("inventory.dat","rb"); // "rb" = Read Binary
if(!ptr)
{
printf("Unable to Open File\n");
system("pause");
return 0;
}
count=getcount();
for(i=0;i < count; i++)
{
readfile[i]= malloc(sizeof(InventoryItemType));
fread(readfile[i], sizeof(InventoryItemType), 1, ptr);
}
fclose(ptr);
return 1;
}
..and turn warnings of your compiler on!

how should I use qsort for pointers to sort by first character of it in c

/* problem of qsorting
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INPUT "doc.txt"
#define OUTPUT "output.txt"
#define MAX_SIZE 500
typedef struct student // here I declare stuctures
{
char name[20];
int index;
int code;
int grade;
char surname[20];
} student;
int cmpfunc (const void * a, const void * b) // initial part of qsort
{
return ( *(char*)a - *(int*)b );
}
int main()
{
int i=0, m=0;
int number=0;
FILE *fo;
FILE *fi;
char file[]={INPUT};
char file1[]={OUTPUT};
fo = fopen(file, "r"); // open the file
fi = fopen(file1, "w"); // open the file
student *studentPtr;
studentPtr = (student*) malloc(MAX_SIZE*sizeof(student));
// here I use mallocation
if(fo == NULL || studentPtr == NULL || fi == NULL)
{
perror("Error");
exit(1);
}
while (!feof(fo)) // reading of file
{
fscanf(fo,"%d %s %s %d %d",
&studentPtr[i].index,
studentPtr[i].name,
studentPtr[i].surname,
&studentPtr[i].code,
&studentPtr[i].grade);
i++;
}
i=m;
printf("please insert a number upto 7:\n");
// because there are only 7 raws in the file
scanf("%d",&number);
m=number;
if (number > 7)
{
printf("try again");
}
else
{
for(i=0;i<m;i++)
{
qsort(studentPtr[i].surname, 1, sizeof(char), cmpfunc); // ?
printf("%d %s %s %d %d\n", // printing out
studentPtr[i].index,
studentPtr[i].name,
studentPtr[i].surname,
studentPtr[i].code,
studentPtr[i].grade);
fprintf(fi,"%d %s %s %d %d\n", // writing in the file
studentPtr[i].index,
studentPtr[i].name,
studentPtr[i].surname,
studentPtr[i].code,
studentPtr[i].grade);
}
}
free(studentPtr);
fclose(fo);
fclose(fi);
return 0;
}
I am just beginner and sorry for obvious mistakes.
I cannot do qsorting properly.
i will attach txt file as a comment of this post.
could you guys tell me how to change first part of qsort not to get silly things, after that i will try to do that by myself

C doesn't load info from file (fread, fwrite)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SLENG 50 //just a random value
typedef struct Song
{
char *name;
char *nameSong;
char *timeSong;
int date;
} Song;
void saveToFile(Song *x, int *songCount) //Saves info to the binary file
{
FILE *f = fopen("array.txt", "w");
if (f == NULL)
{
printf("Error\n");
}
fwrite(songCount, sizeof(int), 1, f);
fwrite(x, sizeof(struct Song), (*songCount), f);
fclose(f);
}
void readSong(Song *x, int *songCount) //Reads info fromt he file and writes it
{
FILE *fr = fopen("array.txt", "r");
if (fr == NULL)
{
printf("Error\n");
}
printf("Songs:\n");
fread(songCount, sizeof(int), 1, fr);
fread(x, sizeof(struct Song), (*songCount), fr);
for(int i=0; i < (*songCount); i++)
{
printf("%d. %s %s %s %d\n", (i+1), x[i].name, x[i].nameSong, x[i].timeSong, x[i].date);
}
fclose(fr);
}
void insertSong(Song *x, int Count) //Inserts new song into the array.
{
printf("\nInsert name of the band:\n");
x[Count].name=malloc(SLENG * sizeof(char));
scanf("%s", x[Count].name);
printf("Insert name of the song:\n");
x[Count].nameSong=malloc(SLENG * sizeof(char));
scanf("%s", x[Count].nameSong);
printf("Insert length of the song:\n");
x[Count].timeSong=malloc(SLENG * sizeof(char));
scanf("%s", x[Count].timeSong);
printf("Insert then song was created:\n");
scanf("%d", &(x[Count].date));
printf("\n");
}
main()
{
int songCount, menuOption;
Song *x=malloc(SLENG*sizeof(char)+SLENG*sizeof(char)+SLENG*sizeof(char)+sizeof(int));
printf("1. insert song\n 2. load from file\n ");
scanf("%d", &menuOption);
switch(menuOption)
{
case(1) :
printf("Insert how many songs do you want to input?\n");
scanf("%d", &songCount);
for(int i=0; i<songCount; i++)
{
insertSong(x, i);
}
saveToFile(x, &songCount);
break;
case(2) :
readSong(x, &songCount);
break;
}
}
I have an assingment to write a programm which would input some data into file and could read that data from that file, the problem is probably with fwrite or fread, couse it seems to crash everytime I try to load the and write the data from file. Any ideas why is it not working properly? And can I even do it like this as it is dynamic struct array. Thanks in advance.
In order to save the structure to a file, it must only contain scalar values, not pointers into memory objects. Modify your structure to use arrays instead of pointers:
typedef struct Song {
char name[SLENG];
char nameSong[SLENG];
char timeSong[SLENG];
int date;
} Song;
And modify the code accordingly, but note that:
saving and reading the structures to and from a file requires opening it in binary mode "wb" and "rb".
it is very misleading to name a binary file array.txt.
you do not need to pass the address of the count when writing to the file, but you need to pass the address of the array pointer when reading as you do not know yet how much memory to allocate.
Here is the modified code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SLENG 50 // this value is used in the file format
typedef struct Song {
char name[SLENG];
char nameSong[SLENG];
char timeSong[SLENG];
int date;
} Song;
int saveToFile(Song *x, int songCount) { //Saves info to the binary file
FILE *f = fopen("array.bin", "wb");
if (f == NULL) {
printf("Error\n");
return -1;
}
fwrite(songCount, sizeof(int), 1, f);
int written = fwrite(x, sizeof(struct Song), songCount, f);
fclose(f);
return written;
}
int readSong(Song **x, int *songCount) { //Reads info from the file and writes it
int count = 0;
FILE *fr = fopen("array.bin", "rb");
if (fr == NULL) {
printf("Error\n");
return -1;
}
printf("Songs:\n");
fread(&count, sizeof(int), 1, fr);
*x = calloc(count, sizeof(Song));
if (*x == NULL) {
printf("Cannot allocate %d bytes of memory\n", count);
fclose(fr);
return -1;
}
int found = fread(*x, sizeof(struct Song), count, fr);
for (int i = 0; i < found; i++) {
printf("%d. %s %s %s %d\n", i + 1,
(*x)[i].name, (*x)[i].nameSong, (*x)[i].timeSong, (*x)[i].date);
}
fclose(fr);
return *songCount = found;
}
void insertSong(Song *x, int Count) { //Inserts new song into the array.
printf("\nInsert name of the band:\n");
scanf("%49s", x[Count].name);
printf("Insert name of the song:\n");
scanf("%49s", x[Count].nameSong);
printf("Insert length of the song:\n");
scanf("%49s", x[Count].timeSong);
printf("Insert then song was created:\n");
scanf("%d", &(x[Count].date));
printf("\n");
}
int main(void) {
int songCount, menuOption;
Song *x = NULL;
printf("1. insert song\n 2. load from file\n ");
scanf("%d", &menuOption);
switch (menuOption) {
case 1:
printf("Insert how many songs do you want to input?\n");
if (scanf("%d", &songCount) == 1) {
x = calloc(songCount, sizeof(Song));
for (int i = 0; i < songCount; i++) {
insertSong(x, i);
}
saveToFile(x, songCount);
}
break;
case 2:
readSong(&x, &songCount);
break;
}
free(x);
x = NULL;
return 0;
}

Resources