I don't understand what I'm doing wrong here. I have a program that successfully reads in data from a file. Once it does this the data that was read in SHOULD be able to be searched/shown/or deleted, but it does not do this. I know the file is being successfully read because when I add a printf() to the function reading the file, it prints out the correct data. Help would be wonderful. Here is the stripped down version of the code.
typedef struct friends_contact{
char *First_Name;
char *Last_Name;
char *home;
char *cell;
}fr;
int main()
{
fr friends[5];
char buffer[BUFFSIZE];
int counter=0;
int i=0;
menu(friends, &counter,i,buffer);
getch();
return 0;
}
//Menu function
void menu(fr*friends,int* counter, int i,char buffer[])
{
int user_entry=0;
int user_entry1=0;
int user_entry2=0;
char user_entry3[50]={'\0'};
FILE *read;
printf("Welcome! Would you like to import a file? (1)Yes or (2) No");
scanf("%d",&user_entry1);
if(user_entry1==1)
{
printf("Please enter a file name");
scanf("%s",user_entry3);
read=fopen(user_entry3,"r");
}else;
do{
int result;
printf("\nPhone Book Application\n");
printf("1) Add friend\n2) Delete friend\n3) Show a friend\n4) Show phonebook\n5)Exit\n");
scanf("%d", &user_entry);
if(user_entry==1)
{
add_contact(friends,counter,i,buffer);
}
if(user_entry==2)
{
delete_contact(friends ,counter,i);
}
if(user_entry==3)
{
result=show_contact(friends ,counter,i);
if(result==0){
printf("\nName not Found\n");
}else{
result;
}
}
if(user_entry==4)
{
print_contact(friends, counter,i,user_entry3);
if(user_entry1==1)
{
file2(friends ,counter,i,buffer,read);
}else;
}
}while(user_entry!=5);
}
The delete function
//This is used to delete a name out of the book
char delete_contact(fr*friends ,int* counter, int i)
{
char name_search[50]={'\0'};
char Delete[5]={'\0'};
printf("Search by last name\n");
scanf("%s",name_search);//Name entry
for(i=0;i<*counter;i++)
{
if(strcmp(name_search,friends[i].Last_Name)==0)//Copys over the name entered
{
strcpy(friends[i].Last_Name,Delete);
}
}
//Freeing up memory.
free(friends[i].First_Name);
free(friends[i].Last_Name);
free(friends[i].home);
free(friends[i].cell);
printf("\nName(s) has been deleted\n");
}
the print function:
//This function prints out all the contact information
void print_contact(fr*friends ,int* counter, int i,char user_entry3[50])
{
for( i = 0; i < *counter; i++)
if (strlen(friends[i].First_Name) && strlen(friends[i].Last_Name)&& strlen(friends[i].home)&& strlen(friends[i].cell ))
{
getFirst(friends, i);
getLast(friends, i);
getHome(friends, i);
getCell(friends, i);
}
}
//Displays the contact in which you are searching for.
int show_contact(fr*friends ,int* counter, int i)
{
char name_search2[50]={'\0'};
int flag=0;
printf("Please enter a last name\n");
scanf("%s",name_search2);
for(i=0;i<*counter;i++)
{
//If the name is found, it reaturns the contact info.Now works for duplicate last names.
if(strcmp(name_search2,friends[i].Last_Name)==0)
{
(strlen(friends[i].First_Name) && strlen(friends[i].Last_Name)&& strlen(friends[i].home)&& strlen(friends[i].cell ));
getFirst(friends, i);
getLast(friends, i);
getHome(friends, i);
getCell(friends, i);
flag++;
}
}
return flag;
}
The Read in function:
void file2(fr*friends ,int* counter, int i,char buffer[],FILE*read)
{
fseek(read, 0, SEEK_SET);
while (fscanf(read,"%s", buffer) != EOF)
{
friends[*counter].Last_Name=malloc(BUFFSIZE*strlen(buffer));
strcpy(friends[*counter].Last_Name, buffer);
printf("%s\n",friends[*counter].Last_Name);
}
}
Try changing your read function to something like this where you pass in the size of your friends array so you don't read in too many lines and end up crashing your program. This is assuming you are reading in line by line from a text file.
This will loop while our counter is less than the number of elements in our friends array to ensure we don't go out of bounds while accessing each of the structures, OR if we reached the end of file, then it will stop.
To allocate memory for Last_Name we take the length of the string that got stored in buffer and add 1 to make room for the null terminating byte.
void file2(fr *friends, const size_t num_friends, FILE *read)
{
size_t counter = 0;
char buffer[128];
while (counter < num_friends && fscanf(read, "%s", buffer) != EOF) {
friends[counter].Last_Name = malloc(strlen(buffer) + 1);
strcpy(friends[counter].Last_Name, buffer);
counter++;
}
}
Then call this like file2(friends, 5, read); The middle argument is the size of your array.
fscanf can also overflow your buffer if you supply it with too much data. It has no bounds checking which can lead to crashing your program. I'd look into using fgets instead for next time.
Related
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", ¤t->stock);
printf("Enter Purchase Price: \n");
scanf("%f", ¤t->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!
#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;
}
I must modify my program to accept input from
a file called anagrams.txt.This file should have two strings per line, separated by the # character. My program should read
each pair of strings and report back if each pair of strings is an anagram. For example consider the following content of anagrams.txt:
hello#elloh
man#nam
Astro#Oastrrasd
Your program should print out the following:
hello#elloh - Anagrams!
man#nam - Anagrams!
Astro#Oastrrasd- Not anagrams!
I should compile in g++
Here is the code to read from text:
int main()
{
char input[30];
if(access( "anagrams.txt", F_OK ) != -1) {
FILE *ptr_file;
char buf[1000];
ptr_file =fopen("anagrams.txt","r"); if (!ptr_file)
return 1;
while (fgets(buf,1000, ptr_file)!=NULL)
printf("%s",buf);
fclose(ptr_file);
printf("\n");
}
else{ //if file does not exist
printf("\nFile not found!\n");
}
return 0;
}
Code to find if the text are anagrams:
#include <stdio.h>
int find_anagram(char [], char []);
int main()
{
char array1[100], array2[100];
int flag;
printf("Enter the string\n");
gets(array1);
printf("Enter another string\n");
gets(array2);
flag = find_anagram(array1, array2);
if (flag == 1)
printf(" %s and %s are anagrams.\n", array1, array2);
else
printf("%s and %s are not anagrams.\n", array1, array2);
return 0;
}
int find_anagram(char array1[], char array2[])
{
int num1[26] = {0}, num2[26] = {0}, i = 0;
while (array1[i] != '\0')
{
num1[array1[i] - 'a']++;
i++;
}
i = 0;
while (array2[i] != '\0')
{
num2[array2[i] -'a']++;
i++;
}
for (i = 0; i < 26; i++)
{
if (num1[i] != num2[i])
return 0;
}
return 1;
}
You can try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXLINE 1000
#define MAXLETTER 256
int is_anagram(char *word1, char *word2);
void check_lines(FILE *filename);
int cmpfunc(const void *a, const void *b);
void convert_to_lowercase(char *word);
int
main(int argc, char const *argv[]) {
FILE *filename;
if ((filename = fopen("anagram.txt", "r")) == NULL) {
fprintf(stderr, "Error opening file\n");
exit(EXIT_FAILURE);
}
check_lines(filename);
fclose(filename);
return 0;
}
void
check_lines(FILE *filename) {
char line[MAXLINE];
char *word1, *word2, *copy1, *copy2;
while (fgets(line, MAXLINE, filename) != NULL) {
word1 = strtok(line, "#");
word2 = strtok(NULL, "\n");
copy1 = strdup(word1);
copy2 = strdup(word2);
convert_to_lowercase(copy1);
convert_to_lowercase(copy2);
if (is_anagram(copy1, copy2)) {
printf("%s#%s - Anagrams!\n", word1, word2);
} else {
printf("%s#%s - Not Anagrams!\n", word1, word2);
}
}
}
void
convert_to_lowercase(char *word) {
int i;
for (i = 0; word[i] != '\0'; i++) {
word[i] = tolower(word[i]);
}
}
int
is_anagram(char *word1, char *word2) {
qsort(word1, strlen(word1), sizeof(*word1), cmpfunc);
qsort(word2, strlen(word2), sizeof(*word2), cmpfunc);
if (strcmp(word1, word2) == 0) {
return 1;
}
return 0;
}
int
cmpfunc(const void *a, const void *b) {
if ((*(char*)a) < (*(char*)b)) {
return -1;
}
if ((*(char*)a) > (*(char*)b)) {
return +1;
}
return 0;
}
Since this looks like a University question, I won't provide a full solution, only a hint.
All you have to do is replace the stdin input part of the anagram-finding file with the code you wrote to read from a file: it's as simple as changing
printf("Enter the string\n");
gets(array1);
printf("Enter another string\n");
gets(array2);
to
// before program:
#define SIZE 1000
// inside main
if (access("anagrams.txt", F_OK) == -1){
printf("\nFile not found!\n");
return 1; // Abort the program early if we can't find the file
}
FILE *ptr_file;
char buf[1000];
ptr_file = fopen("anagrams.txt","r");
if (!ptr_file)
return 1;
char array1[SIZE], array2[SIZE];
while (fgets(buf, 1000, ptr_file)!=NULL){
// do all your anagram stuff here!
// there is currently one line of the input file stored in buf
// Hint: You need to split buf into array_1 and array_2 using '#' to separate it.
}
fclose(ptr_file);
printf("\n");
Additional comments:
Don't ever ever ever use gets. gets doesn't check that the string it writes to can hold the data, which will cause your program to crash if it gets input bigger than the array size. Use fgets(buf, BUF_SIZE, stdin) instead.
Beautiful code is good code. People are more likely to help if they can read your code easily. (fix your brackets)
Just for interest, a more efficient algorithm for checking anagrams is to use qsort to sort both arrays, then a simple string matcher to compare them. This will have cost O(mnlog(m+n)), as opposed to O(m^2 n^2), awith the current algorithm
You need to split every line you read by fgets (as you did) in to two strings, and pass them to your find_anagram function. You can do that using strtok:
int main()
{
int flag;
char buf[1000];
FILE *ptr_file;
//Check file existence
//Open the file for reading
while (fgets (buf, 1000, ptr_file) != NULL)
{
char *array1 = strtok(buf, "#");
char *array2 = strtok(NULL, "\n");
flag = find_anagram (array1, array2);
//Check flag value to print your message
}
return 0;
}
//put your find_anagram function
Don't forget to #include <string.h> to use strtok().
Okay so basically the title says it all. I am working on a project where I get a segmentation fault right after I enter the name of the file I want to open. I created a smaller program that did just that, but when I implement it in my project it does not seem to work. I might be overlooking something. Would be awesome if someone could point it out.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
//function prototypes
void printmenu();
void getcipher(char **arr, int *count, FILE **infile);
int main()
{
int flag = 1; //exit flag for menu loop
int choices; //user input for menu
int count = 0;
char arr[7000][25]; //store words in this array
FILE *infile = NULL; //input cipher file
while(flag)
{
printmenu();
scanf("%d", &choices);
getchar();
while(choices < 1 || choices > 4)
{
printf("\nInvalid input. Try again...");
scanf("%d", &choices);
getchar();
}//end while
switch(choices)
{
case 1:
getcipher((char **)arr, &count, &infile);
break;
case 2:
printf("2");
break;
case 3:
printf("3");
break;
case 4:
flag = 0;
break;
}//end switch
}//end while
return 0;
}
void printmenu()
{
printf("\n%s", "Menu Choices");
printf("\n%-40s%-20s", "Use Cipher text file as cipher key", "Enter 1");
printf("\n%-40s%-20s", "Create cipher using a text file","Enter 2");
printf("\n%-40s%-20s", "Decode existing cipher", "Enter 3");
printf("\n%-40s%-20s\n\n", "Exit Program","Enter 4");
}
void getcipher(char **arr, int *count, FILE **infile)
{
int flag; //flag for getting cipher text file
char buffer[1000]; //buffer for reading in lines
char *token;
int letters = 0; //index for letters
int low; //index for converting to lowercase
//Gets cipher text file
printf("\nEnter the name of the cipher text file: ");
scanf("%s", buffer);
printf("\n%s\n", buffer);
*infile = fopen(buffer, "r");
if(!(*infile))
{
printf("Unable to open file. Exiting...");
exit(1);
}//end while
//inputs words from cipher text file to array
while(fgets(buffer, 1000, *infile))
{
token = strtok(buffer, " ");
strcat(arr[*count], token);
count++;
while((token = strtok(NULL, " ")) != NULL)
{
strcat(arr[*count], token);
count++;
}//end while
}//end while
printf("\n%d" , *count);
int i = 0;
//print array
while(i < *count)
{
printf("\n%s ", arr[i]);
i++;
}//end while
}
This is my second smaller program that opened a file within a function. I basically copied this into my project.
#include<stdio.h>
#include<string.h>
void openfile(FILE **file);
int main()
{
FILE *file = NULL;
openfile(&file);
return 0;
}
void openfile(FILE **file)
{
char buffer[100];
printf("Enter the name of file: ");
scanf("%s", buffer);
*file = fopen(buffer, "r");
if(*file)
printf("\nSuccess!!");
}
The problem is that you're casting arr, which is char [7000][25], to char ** when passing it to getcipher. These two declarations are incompatible. The first is a flat 2-dimensional array, while the second is an array of pointers, each of which points to its own secondary array. In general, if you are casting one pointer type to another like this, you are probably introducing a bug.
To fix it, you can change your char **arr declaration in getcipher to char arr[7000][25], or char arr[][25], or char (*arr)[25]. If you don't want to hard-wire the size, you can pass it as a parameter as long as it precedes the array parameter.
Second problem: You have argument int *count in getcipher. In this case it is a pointer to a single int. But you increment it with count++ in a couple places. This will increment the pointer, not the integer it points to. Change it to (*count)++;
I was creating on a very basic program in C which takes a word from user as input and searches for how many times it appears in a text file and gives output.
The code is:
#include<stdio.h>
#include<string.h>
int main()
{
char user[20];
char word[20];
int i,pos=0,sum=0;
char c;
c='a';
printf("Enter the word you want to look for\n");
gets(user);
FILE *p;
p=fopen("D:\\trees.txt","r+");
do
{
pos=0;
fscanf(p,"%s",word);
if(c!=EOF)
{
if(strlen(word)==strlen(user))
{
for(i=0;i<strlen(user);i++)
{
if(word[i]==user[i]||word[i]==user[i]+32||word[i]==user[i]-32)
{
}
else
{
pos=1;
break;
}
}
}
else
{
pos=1;
}
if(pos=0)
{
sum++;
}
}
}
while(c!=EOF)
;printf("\nNumber of times %s appears is %d",user,sum);
fclose(p);
}
Now the program takes the input fine, but doesn't give any output.
Looks like this:
What have I done wrong?
Looking at the comments, your code should be something like:
#include<stdio.h>
#include<string.h>
#include <ctype.h>
int main()
{
char user[20];
char word[20];
int n, pos=0, sum=0;
unsigned int i, l;
FILE *p;
do {
printf("Enter the word you want to look for\n");
} while (gets(user)==0);
user[strlen(user)-1]= '\0'; // remove trailing \n
if ((p=fopen("D:\\trees.txt","r+"))==0) {printf("Error opening file\n"); exit(0);}
do
{
pos=0;
n= fscanf(p,"%s",word);
if (n==1)
{
if(strlen(word)==(l=strlen(user)))
{
for(i=0; i<l; i++)
{
if(!(word[i]==user[i]||word[i]==tolower(user[i])||word[i]==toupper(user[i])))
{
pos=1;
break;
}
}
}
else pos=1;
if(pos==0) sum++;
}
}
while(n==1);
printf("\nNumber of times %s appears is %d",user,sum);
fclose(p);
return(1);
}
(with some optimizations and additions)