Sorting name of books by alphabetical order - c

I'm developing an application and one of the functions is the function sort_books_file which basically has to sort the name of the books in the file fp by alphabetical order and then prints them in the file fp2.
At the moment, the only thing the function does is printing the name of the books from file fp into file fp2.
I would like to know how it is possible to sort the name of the books by alphabetical order into the file fp2.
I'm a C beginner and I don't have a lot of experience in C programming...somebody helps?
#include <stdio.h>
FILE *fp;
FILE *fp2;
struct book{
int key;
char name[50];
int price;
};
sort_books_file(){
struct book b;
//r: open the file for reading (read-only)
if ((fp=fopen("books.dat","r"))==NULL){
printf("Error\n");
exit(1);
}
//w: open the file for writing (write-only).
//the file is created if it doesn't exist
if ((fp2=fopen("books_sorted.dat","w"))==NULL){
printf("Error: not possible to open the file. \n");
exit(1);
}
//while end of file has not been reached
while (!feof(fp)){
fread(&b,sizeof(b),1,fp);
if(feof(fp))
{
break;
}
fwrite(&b.name,sizeof(b.name),1,fp2);
}
fclose(fp);
fclose(fp2);
}

The easiest way is to use strcmp() on book.name to sort.
strcmp() works as follows :
syntax : int strcmp(const char *str1, const char *str2)
st1 and str2 are the strings to be compared
The function returns -1 if str1 is less than str2 and 0 if the strings are equal and 1 if str1 is greater than str2.
strcmp() uses lexicographic ordering, which means it sorts the words as it appears on the dictionary. Here's a question that discusses it.
Examples
strcmp("hello", "world")returns -1
strcmp("world", "hello") returns 1
stcmp("boo", "boo") returns 0
And here's a sorting function that does what you want (I haven't tested it) :
void sort_books_file(){
//Assume you have only maximum 10 books
struct book books[10];
strct book b;
//open files for reading and writing
//..
//..
int i = 0;
while (!feof(fp)){
fread(&b,sizeof(b),1,fp);
books[i] = b;
i++;
if(feof(fp))
{
break;
}
}
//number of books
int len = i;
//bubble sort;
int j = 0;
//Bubble sort. Google for "bubble sort"
for(i=0; i<len; i++)
{
for(j=0; j<len-1; j++)
{
//If the first book should come after the next book in the array
if(strcmp(books[j].name, books[j+1].name) > 0)
{
//swap the books
struct book temp;
temp = books[j];
books[j] = books[j+1];
books[j+1] = temp;
}
}
}
//now write each book in the array "books" into the file one by one
}

I hope this will help:
void sort(struct book* books, int n)
{
int j,i;
for(i=1;i<n;i++)
{
for(j=0;j<n-i;j++)
{
if(books[j].name < books[j+1].name)
{
struct book temp = books[j];
books[j] = books[j+1];
books[j+1] = temp;
}
}
}
}
Store Book info into an array of book structure. Then pass this array to sort function. This will do your job.
struct book LIST[n];
sort(LIST, n);

Related

A way to know if element in array of struct is empty/NULL in C

I would really appreciate help with this piece of code.
So I have defined a structure, and then an array of structures:
#define MAX_ITEMS 30
struct item{
char itemName[30];
int identification;
float sale;
};
struct item itemArray[MAX_ITEMS];
Then I have a function which takes the index of the array structure and is supposed to delete that element, and update the new array without the deleted element to the local .txt file
printf("item's index please: ");
char input[30];
gets(input);
for (int i=input; i<MAX_ITEMS;i++){
itemArray[i] = itemArray[i + 1];
}
FILE *fp
fp = fopen ("file.txt", "w");
int index = 0;
while(itemArray[index].itemName != ""){
fprintf(fp,"%s\n",itemArray[index].itemName);
fprintf(fp,"%d\n",itemArray[index].identification);
fprintf(fp,"%.2f\n",itemArray[index].sale);
index++;
}
fclose(fp);
So what I am expecting:
Instead, I get
Finishing after thousands of lines, like this:
I would appreciate any help!

Sorting structures from files

I recently got an assignment to sort members in a struct by last name and if they are the same to sort by first name. What i have so far only reads their name and age from the file but I am not properly grapsing how I would be able to sort it. So far I gathered the data from the file but im at a loss from there. I followed a code I saw but i didnt get a proper grasping of the process so i reverted back to step one.
struct Members{
int id;
char fname[50];
char lname[50];
int age;
}bio;
int main(){
int i=0;
FILE *fptr;
file = fopen("Members Bio.txt", "r");
while ( fscanf(file, "%d%s%s%d", &bio[i].id,bio[i].fname,bio[i].lname,&bio[i].age) != EOF)
{
printf("%d %s %s %d %d\n", bio[i].id,bio[i].fname, bio[i].lname, bio[i].age);
i++;
}
fclose(fptr);
}
Can anyone help me out on this one?
Code goes something like this for your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Members{
int id;
char fname[50];
char lname[50];
int age;
};
typedef int (*compare_func)(void*, void*);
int struct_cmp(void* s1, void* s2)
{
int l_result = strcmp(((struct Members*) s1)->lname, \
((struct Members*) s2)->lname);
if (l_result < 0)
return 1;
else if (l_result > 0)
return 0;
else
return (strcmp(((struct Members*) s1)->fname, \
((struct Members*) s2)->fname) < 0 ? 1 : 0);
}
void sort(void* arr,long ele_size,long start,long end,compare_func compare)
{
// Generic Recursive Quick Sort Algorithm
if (start < end)
{
/* Partitioning index */
void* x = arr+end*ele_size;
long i = (start - 1);
void* tmp=malloc(ele_size);
for (long j = start; j <= end - 1; j++)
{
if ((*compare)(arr+j*ele_size,x))
{
i++;
// Swap is done by copying memory areas
memcpy(tmp,arr+i*ele_size,ele_size);
memcpy(arr+i*ele_size,arr+j*ele_size,ele_size);
memcpy(arr+j*ele_size,tmp,ele_size);
}
}
memcpy(tmp,arr+(i+1)*ele_size,ele_size);
memcpy(arr+(i+1)*ele_size,arr+end*ele_size,ele_size);
memcpy(arr+end*ele_size,tmp,ele_size);
i= (i + 1);
sort(arr,ele_size,start, i - 1,compare);
sort(arr,ele_size,i + 1, end,compare);
}
}
int main()
{
FILE* fp;
int bio_max = 3;
struct Members bio[bio_max]; // Define bio to be large enough.
/* Open FILE and setup bio matrix */
/* For testing */
bio[0].id = 0;
strcpy(bio[0].fname, "");
strcpy(bio[0].lname, "Apple");
bio[0].age = 0;
bio[1].id = 1;
strcpy(bio[1].fname, "");
strcpy(bio[1].lname, "Cat");
bio[1].age = 1;
bio[2].id = 2;
strcpy(bio[2].fname, "");
strcpy(bio[2].lname, "Bat");
bio[2].age = 2;
/* Sort the structure */
sort(bio, sizeof(struct Members), 0, bio_max - 1, struct_cmp);
/* Print the sorted structure */
for (int i = 0; i < bio_max; i++) {
printf("%d %s %s %d\n", bio[i].id, bio[i].fname, \
bio[i].lname, bio[i].age);
}
}
Output
0 Apple 0
2 Bat 2
1 Cat 1
If the strings are not sorting in the way you want, you can redefine the struct_cmp function. Code is self explanatory, the base logic in the code is pass an array and swap elements using memcpy functions. You cant use simple assignment operator if you want to be generic, so that is why the element size is explicitly passed.
Edit
The code was not handling the condition, if lname are same. I missed it thanks for #4386427 for pointing this out.
I think you should define bio to be an array. And google sort algorithms please. Also recommend you google how to use libc function qsort.

C - Printing word/freq BST in order of freq instead of word

I've created a program that collects words and their frequencies from a text file. At the moment I've managed to save the words and their frequencies in a binary search tree. The problem is that the program prints out the words and their frequencies in alphabetic (key) order. I need to print out the top-100 words according to their frequency. I would like to use the binary search tree, even if it isn't the most effective way of doing this task.
If I understand correctly, the maximum heap structure could be used here, but I need more specific steps to go on by. I am very new to data structures.
My structures look like this:
typedef char data_type[MAXLEN];
typedef struct bstnd {
data_type data;
int freq;
struct bstnd* parent;
struct bstnd* left;
struct bstnd* right;
} bstnode, *pbstnode;
typedef struct bt {
pbstnode root;
} bst;
My main function looks like this:
int main( int argc, char* argv[] ){
bst tree;
tree.root=0;
FILE * fp;
int i=0, c=0;
char buffer[MAXLEN];
fp = fopen(argv[1], "r");
if (fp==0) {
printf("Usage: %s [file]\n", argv[0]);
return 0;
}
while (!feof(fp)) {
c = fgetc(fp);
if (isalpha(c) || c == '\'' || c == '’' || c == '‘') {
buffer[i]=tolower(c);
i++;
}
else {
buffer[i]='\0';
if (isalpha(buffer[0])) {
bst_insert( &tree, buffer );
}
buffer[0]='\0';
i=0;
}
}
print_tree_inorder(tree);
return 0;
}

Reading a text file with data into a linked list

I am working on a project where I have to read the .txt file where I have data of four elements for each component, ex:
5 2 7 0.99 (which are the components id, inside node, outside node and reliability)
7 3 5 0.95
...
I want to read and write data into a linked list, over which I will later on be able to search for values and sign them to a new linked list. It's about a method of minimal paths in mechanical engineering used for calculating reliability of systems.
To test the code I just want to print out all the components that were put into the linked list. I get the right value for number of lines, but for components I just get out one random not all of them. Any kind of help will be much appreciated :)
Here is the code:
#include <stdlib.h>
#include <stdio.h>
struct Components_element {
int id;
int in_node;
int out_node;
float reliability;
struct Components_element *next_c;
};
struct Components_element *head_c = NULL;
int count_lines(char *filename)
{
int counter = 0;
char c;
FILE *ptr_sistem;
ptr_sistem = fopen(filename, "r");
if(ptr_sistem == NULL)
return 0;
while((c = fgetc(ptr_sistem)) != EOF)
if(c == '\n')
counter++;
fclose(ptr_sistem);
if(c != '\n')
counter++;
return counter;
}
struct Components_element *add_comp(struct Components_element *head_c, int id, int in_node, int out_node, float reliability)
{
struct Components_element *new;
struct Components_element *tail_c;
new = (struct Components_element*) malloc(sizeof(struct Components_element));
new->id = id;
new->in_node = in_node;
new->out_node = out_node;
new->reliability = reliability;
if(head_c == NULL)
return(new);
tail_c = head_c;
while(tail_c->next_c != NULL)
tail_c = tail_c->next_c;
tail_c->next_c = new;
return(head_c);
}
void write_out(struct Components_element *p)
{
while(p != NULL) {
printf("%d %d %d %f", p->id, p->in_node, p->out_node, p->reliability);
p = p->next_c;
}
printf("\n");
}
struct Components_element *empty(struct Components_element *p)
{
struct Components_element *tail_c;
while(p != NULL) {
tail_c = p;
p = p->next_c;
free(tail_c);
}
return(p);
}
main()
{
int i, id, in_node, out_node;
int n_lines;
float reliability;
struct Components_element *components;
FILE *ptr_file;
ptr_file = fopen("system.txt", "r");
if(ptr_file == NULL) {
printf("Cannot open file.\n");
return 0;
} else {
n_lines = count_lines("system.txt");
for(i = 0; i < n_lines; i++) {
fscanf(ptr_file, "%d %d %d %f", &id, &in_node, &out_node, &reliability);
components = add_comp(head_c, id, in_node, out_node, reliability);
++i;
}
}
printf("Number of lines: %d.\n", n_lines);
write_out(components);
empty(components);
fclose(ptr_file);
}
Writing the code is only a small fraction of what programming is about. The really hard part, is getting it to work as required.
To do this, we use various tools to aid with testing the code to make sure it works the way the programmer intended.
The most useful tool is the debugger. Learn how to use one and you can find your problem in a couple of minutes.
Sometimes, however, debuggers aren't always available and this is where things can get quite tricky and requires logging information (printf / fwrite / etc) and a lot of deductive reasoning.
But here, running the code through a debugger will show you your problem. I'll leave it as an exercise for you as you'd learn a lot more that way rather than having the answer spoon fed to you.

String array searching in C

I'm trying to figure out how to search a list of names that are inputted into a string array. If the name entered is part of the original array, then the search function should return the position of the string in the array; if the string is not found, it should return -1. If -1 is returned then I want to be able to print out "not found", which doesn't seem like it would be too hard to figure out, but if the name is found, I want to be able to print out the position at which the name is found.
Here is my code, obviously I'm new to this, so I might have butchered how this is supposed to be done. The rest of my code seems to work fine, but it's this function that has me at a loss.
#include<stdio.h>
#include<conio.h>
#include<string.h>
#define MAX_NAMELENGTH 10
#define MAX_NAMES 5
void initialize(char names[MAX_NAMES][MAX_NAMELENGTH]);
int search(char names[MAX_NAMES][MAX_NAMELENGTH],int i,Number_entrys);
int main()
{
char names[MAX_NAMES][MAX_NAMELENGTH];
int i;
initialize(names);
search(names,i,Number_entrys);
search_result= search(names,i,Number_entrys);
if (search_result==-1){
printf("Found no names.\n");
}
if(search_result==0){
printf("Name found");
} getch();
return 0;
}
void initialize(char names[MAX_NAMES][MAX_NAMELENGTH])
{
int i, Number_entrys;
printf("How many names would you like to enter to the list?\n");
scanf("%d",&Number_entrys);
if(Number_entrys>MAX_NAMES){
printf("Please choose a smaller entry\n");
}else{
for (i=0; i<Number_entrys;i++){
scanf("%s",names[i]);
}
}
for(i=0;i<Number_entrys;i++){
printf("%s\n",names[i]);
}
}
int search(char names[MAX_NAMES][MAX_NAMELENGTH],int i)
{
int j, idx;
char name[MAX_NAMELENGTH];
printf("Now enter a name in which you would like to search the list for:");
scanf("%s", name);
for(x = 0; x < Number_entrys; x++) {
if ( strcmp( new_name, names[x] ) == 0 ){
/* match, x is the index */
return x;
}else{
return -1;
}
}
}
There are several problems here.
The purpose of search is to ask the user to enter a single name to be searched for. So why is
char new_name[MAX_NAMES][MAX_NAMELENGTH];
You need only a single array
char new_name[MAX_NAMELENGTH];
Then you have a loop you just go round once, so you don't need a loop
scanf("%s",new_name);
would be enough. This feels like you have copied the code you used to fill your array of names, but haven't really understood its essence.
Another problem is that you have no control on how long a name the user might enter. What would happen if the user typed a very long name? You'd over-fill the array and your program will probably crash and burn. Read this article to learn about how to control this.
To be really pedantic you should also check the return code from scanf, you are expecting to read one item so the return value should be 1, anything else would be an error.
Then you are trying to use strstr(), to look through an array of char arrays. The strstr documentation says that its purpose is to search for a substring within a string rather than search through an array of strings.
So instead just search the array by hand
/* what is i? the number of items used in the array? */
for(x = 0; x < i; x++) {
if ( strcmp( new_name, names[x] ) == 0 ){
/* match, x is the index */
return x;
}
}
/* here with no match */
return -1;
In your main
int search_result;
search_result = search( /* etc */ );
if ( search_result == -1 ) {
/* print "not found" here */
} else {
/* print something else */
}
You means like this:
int search(char names[MAX_NAMES][MAX_NAMELENGTH], int i)
{
int j, idx;
char name[MAX_NAMELENGTH];
printf("Now enter a name in which you would like to search the list for:");
scanf("%s", name);
idx = -1;
for(j = 0; j < i; j++){
if(strstr(names[i], name) != NULL){
idx = j;break;
}
}
return idx;
}
(8) ...
Maybe we'll turn it all around
'Cause it's not too late
It's never too late!! (8)
:) !
Sorry about the song ^_^... oh Well, I was having fun with this question for a couples of minutes, I hope this code help you out a little more, with regards:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* return array of indexs */
int*
search(const char *list, size_t slen, const char **arr_names, size_t arrlen)
{
int *arr_idx;
int j,i,idx;
i=idx=0;
arr_idx = malloc(sizeof(int)*arrlen+1);
if(!arr_idx)
exit(EXIT_FAILURE);
for(i=0; i<slen; i++) {
for(j=0; j<arrlen ; j++) {
if(!strncmp(&list[i], &arr_names[j][0], strlen(arr_names[j]))) {
arr_idx[idx] = j;
idx++;
}
}
}
arr_idx[idx] = -1; /* -1 terminated array */
if(!idx) {
free(arr_idx);
return NULL; /* found no names */
}
return arr_idx;
}
/* I'm a sick [something], nul terminated strings :P */
const char *string = "My favorite artists: ATB, Nujabes and Bonobo also Aphex Twins is nice, along with Trapt and Breaking Benjamin.\0";
const char *names[] = {"ATB\0", "Scifer\0", "Aphex\0", "Bonobo\0", "Nujabes\0", "Tipper\0"};
#define N_NAMES 6
int
main(void)
{
int i;
int *array;
array = search(string, strlen(&string[0]), names, N_NAMES);
if(!array) {
puts("Found no names.\n");
return EXIT_SUCCESS;
}
printf("Names found: ");
for(i=0; array[i]!=-1; i++)
printf("%s,", names[array[i]]);
printf("\b \n");
free(array); /* important */
/* system("pause"); */ /* NOTE: decomment this if you're on windows */
return EXIT_SUCCESS;
}
ran some tests:
~$ ./program
output
Names found: ATB,Nujabes,Bonobo,Aphex

Resources