C struct quick sort for strings - c

I have problem with quick sort. It should sort books with author's names. Here is the code
#include <stdio.h>
#include <stdlib.h>
struct book {
char title[80];
char autor[80];
int pages;
};
int comparator (const void * a, const void *b)
{
struct book * ia=(struct book*)a;
struct book * ib=(struct book*)b;
return (strcmp(ia->autor,ib->autor));
}
int main(int argc, char ** argv)
{
int c = 2;
int i;
//Pointer to array of struct pointers, malloc for 2 structs
struct book **ptr = (struct book*)malloc(c*sizeof(struct book));
for(i=0;i<c;i++) {
//malloc for every struct
//also, if I'm doing it right?
ptr[i] = (struct book*)malloc(sizeof(struct book));
printf("Title: ");
scanf("%s",ptr[i]->title);
printf("Autor: ");
scanf("%s",ptr[i]->autor);
}
for(i=0;i<c;i++) {
printf("Before Quick sort Autor: %s, Title: %s \n",ptr[i]->autor,ptr[i]->title);
}
qsort(ptr,2, sizeof(struct book), comparator);
printf("QSORT DONe...\n\n");
for(i=0;i<c;i++) {
printf("TEST");
printf("After quick sort: Autor: %s, Title: %s \n",ptr[i]->autor,ptr[i]->title);
}
return 0;
}
So program compiles but it reaches only to printf("TEST"); (TEST prints on screen) and then it crashes.
Did I destroy my array with that quick sort? Or what could happen?
Also could you check my code if it's ok? Especially what mallocs (really) do in my code, because I'm not sure if I used them properly.
Thanks!

There were some small issues and confusions:
1) You were missing #include <string.h> for strcmp
2) You were allocating an array of pointers, which is probably not what you meant to do. An array in C is a pointer to the first element of the array, therefore if you allocate using (struct book*) malloc(n * sizeof(struct book)) you're already allocating a full array of n books.
You could also allocate an array of pointers to books, in which case you'd need to assign each pointer to a newly allocated book.
So you could do either of the following (and your code is mixing both):
struct book** ptr = (struct book**) malloc(c * sizeof(struct book*));
struct book* ptr = (struct book*) malloc(c * sizeof(struct book));
In the first case, you need to allocate new books (and therefore the malloc inside the loop would make sense)
In the second case, you just use the array directly, which is what I changed the following code to do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct book {
char title[80];
char autor[80];
int pages;
};
int comparator(const void * a, const void *b)
{
struct book * ia = (struct book*)a;
struct book * ib = (struct book*)b;
return (strcmp(ia->autor, ib->autor));
}
int main(int argc, char ** argv)
{
int c = 3;
int i;
//Pointer to array of struct pointers, malloc for 2 structs
struct book* ptr = (struct book*) malloc(c*sizeof(struct book));
if (ptr == NULL) {
printf("Could not allocate data\n");
return 1;
}
for (i = 0;i<c;i++) {
printf("Title: ");
scanf("%s", ptr[i].title);
printf("Autor: ");
scanf("%s", ptr[i].autor);
}
for (i = 0;i < c;i++) {
printf("Before Quick sort Autor: %s, Title : %s \n", ptr[i].autor, ptr[i].title);
}
qsort(ptr, c, sizeof(struct book), comparator);
printf("QSORT Done...\n\n");
for (i = 0;i<c;i++) {
printf("TEST");
printf("After quick sort: Autor: %s, Title: %s \n", ptr[i].autor, ptr[i].title);
}
free(ptr);
return 0;
}
3) Finally, it is a good practice to test the result of your malloc and to call free when you don't need it anymore.

It is shown for the point to be changed(for Pointer to array of struct pointers(but double pointer is not necessary)) following as
#include <string.h>
struct book * ia=*(struct book**)a;
struct book * ib=*(struct book**)b;
struct book **ptr = malloc(c*sizeof(struct book*));
qsort(ptr,2, sizeof(struct book*), comparator);
Perhaps version what you want
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct book {
char title[80];
char autor[80];
int pages;
};
int comparator (const void * a, const void *b)
{
struct book * ia=(struct book*)a;
struct book * ib=(struct book*)b;
return (strcmp(ia->autor,ib->autor));
}
int main(int argc, char ** argv)
{
int c = 2;
int i;
struct book *ptr = malloc(c*sizeof(struct book));
for(i=0;i<c;i++) {
printf("Title: ");
scanf("%s",ptr[i].title);
printf("Autor: ");
scanf("%s",ptr[i].autor);
}
for(i=0;i<c;i++) {
printf("Before Quick sort Autor: %s, Title: %s \n",ptr[i].autor,ptr[i].title);
}
qsort(ptr,2, sizeof(struct book), comparator);
printf("QSORT DONe...\n\n");
for(i=0;i<c;i++) {
printf("TEST");
printf("After quick sort: Autor: %s, Title: %s \n",ptr[i].autor,ptr[i].title);
}
return 0;
}

I'm going to give you an answer which will keep the definition of ptr, which is a pointer to a pointer to struct book, and also change a minimal amount of your code. This means we will allocate an array of pointers to struct book, and then for each pointer in that array we will allocate an actual object struct book.
The first malloc will allocate an array of cpointers to struct book:
struct book **ptr = (struct book**)malloc(c*sizeof(struct book*));
The for loop which allocates an object struct book using malloc is then correct.
The second correction is at the qsort() call. We are sorting pointers to struct book, not actual objects struct book.
qsort(ptr,4, sizeof(struct book*), comparator);
Then the comparison function needs a fix. Since we are sorting pointers, the comparison function will return a pointer to a pointer to struct book. So we need to dereference that pointer to our pointer to struct book:
int comparator (const void * a, const void *b)
{
struct book* ia=*(struct book**)a;
struct book* ib=*(struct book**)b;
return (strcmp(ia->autor,ib->autor));
}

Related

How can I read write this array of structure from/to a file? [duplicate]

I have an array of structs I would like to write to a binary file. I have a write.c program and a read.c program. The write.c program seems to be working properly but when I run the read.c program I get a segmentation fault. I'm new to C so It would be great if someone could look over my code for any obvious errors. I promise it's not too long :)
write.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
struct Person* people;
int people_count;
printf("How many people would you like to create: ");
scanf("%i", &people_count);
people = malloc(sizeof(struct Person) * people_count);
int n;
for (n = 0; n < people_count; n++)
{
printf("Person %i's First Name: ", n);
scanf("%s", people[n].f_name);
printf("Person %i's Last Name: ", n);
scanf("%s", people[n].l_name);
printf("Person %i's Age: ", n);
scanf("%i", &people[n].age);
}
FILE* data;
if ( (data = fopen("data.bin", "wb")) == NULL )
{
printf("Error opening file\n");
return 1;
}
fwrite(people, sizeof(struct Person) * people_count, 1, data);
fclose(data);
return 0;
}
read.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
FILE* data;
if ((data = fopen("data.bin", "rb")) == NULL)
{
printf("Error opening file\n");
return 1;
}
struct Person* people;
fread(people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
printf("%s\n", people[0].f_name);
fclose(data);
return 0;
}
Thanks for the help!
struct Person* people;
This allocates just a pointer to struct, but you don't have any allocated space for actual struct contents. Either use malloc similarly to your write program, or try something like:
struct Person people;
fread(&people, sizeof(people), 1, data);
You need to allocate memory for the person first. Change: struct Person* people; into struct Person* people = malloc(sizeof(struct Person));. And don't forget to free your memory at the end: free(people);.
You either need to malloc memory into the pointer variable people before you do the fread, or (easier) just read directly into a local variable:
struct Person people;
fread(&people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
You need to allocate space for the data you are reading in:
people = malloc(sizeof(*people)*numPeople);

How to access fields of an Struct array in a function definition

Im new to programming and im having a hard time learning DMA and trying to work with structs and pointer at the same time.
im working on a program that takes in information about books and stores the author and title in an array of structs to be displayed it requires DMA to store the strings in the struct.
my hardest part to understand and trying to fix is when i try to access fields of an Struct array in a function definition
for example:
void getInfo(struct BookInfo *pbook, char author[], char title[])
{
//creating memory for strings
pbook.author = (struct BookInfo*) malloc((strlen(author) +1) * sizeof(char));
pbook.title = (struct BookInfo*) malloc((strlen(title) +1) * sizeof(char));
//copying info into the heap
strcopy(pbook.author, author);
strcopy(pbook.title, title);
}
I would really appreciate your help in any way, thanks in advance
This is my full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define size 5 //size is the total number of elements in the array
//declaration of struct
struct BookInfo {
char* author;
char* title;
};
//prototypes
void getInfo(struct BookInfo *pbook, char author[], char title[]);
void printInfi(struct BookInfo book[]);
int main() {
struct BookInfo myBook[size]; //declare an array.
char author[40] = { '0' }; //temp strings to store input from user
char title[50] = { '0' };
//get input from user
printf("Enter author name: ");
fgets(author, 40, stdin);
printf("Enter book title name: ");
fgets(title, 50, stdin);
// call function to store info (dma) individually in array, loop 5 times do fill struct array
for(int i =0; i < size; i++)
{
void getInfo(struct BookInfo myBook, author, title);
}
// call function to print all info from array, call one time
void printInfi(struct BookInfo myBook);
// Free space from dma
for(int i=0; i < size; i++)
{
free(myBook[i].author);
free(myBook[i].title);
}
return 0;
}
void getInfo(struct BookInfo *pbook, char author[], char title[])
{
//creating memory for strings
pbook.author = (struct BookInfo*) malloc((strlen(author) +1) * sizeof(char));
pbook.title = (struct BookInfo*) malloc((strlen(title) +1) * sizeof(char));
//copying info into the heap
strcopy(pbook.author, author);
strcopy(pbook.title, title);
}
void printInfo(struct BookInfo book[])
{
for(int i = 0; i < size; i++)
{
printf("Title: %s, Author: %s\n", book[i].author, book[i].title);
}
}
If you have a structure pointer example: struct structName *pToAStruct;, to access the value of a field use -> operator like this : var = pToAStruct->field. With var and field having the same type, int for example.
If you have a directly the structure variable, then use . operator. Example: struct structName AStruct; var = AStruct.field;
Beware in these examples I assumed you have allocated memory / initialized the structure when its needs to be.

initialise constructor values of structure using pointer in c [duplicate]

This question already has answers here:
How do malloc() and free() work?
(13 answers)
Closed 3 years ago.
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char name[50];
int year_of_birth;
char sex[7];
char father[50];
char mother[50];
char significant_other[50];
char children[50];
};
struct Person* person_constructor(char *name, int year_of_birth, char *sex);
int main(){
struct Person* p1 = person_constructor("Abbas", 1970, "male");
}
struct Person* person_constructor(char *name, int year_of_birth, char *sex) {
struct Person *p;
printf("%s",*name);
printf("%s",*sex);
printf("%d",&year_of_birth);
// how to initalise these here and return name, age and sex everytime , can you tell me in print function
}
i want to do :
Person* person_constructor(char *name, int year_of_birth, char *sex);
A person with the given arguments and return it.
Also allocate memory.
In example code bellow you can find one of possible solutions to your question.
In C language is not possible to return more then one variable, but you can return pointer to constructed structure object and access structure members using notation stuct_ptr->struct_member.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char name[50];
int year_of_birth;
char sex[7];
char father[50];
char mother[50];
char significant_other[50];
char children[50];
};
struct Person* person_constructor(char *name, int year_of_birth, char *sex);
int main(){
struct Person* p1 = person_constructor("Abbas", 1970, "male");
/* it is not possible to return more variables in C */
/* you can use pointer to access members from constructed structure: */
printf("print from main:\n %s %d %s \n", p1->name, p1->year_of_birth, p1->sex);
if( p1 != NULL) free(p1); /* do not forget do deallocate something taht is allocated */
return 0;
}
struct Person* person_constructor(char *name, int year_of_birth, char *sex) {
struct Person *p = calloc(1, sizeof(struct Person));
if( p == NULL ) return p; /* memory alocation failed! */
strcpy(p->name, name);
p->year_of_birth = year_of_birth;
strcpy(p->sex, sex);
printf("print from constructor:\n");
printf("%s ",p->name);
printf("%s ",p->sex);
printf("%d \n",p->year_of_birth);
return p;
}

C array gets corrupted after being modified by a function

I'm trying to write a C program that gathers all structures passing a specific condition into an array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Book {
char title[20];
unsigned int published;
char authors[50];
unsigned int pages;
};
unsigned int get_books_from(unsigned int year, int length, struct Book data[], struct Book results[]);
int main(int argc, char* argv[]) {
struct Book data[5];
// Init book pool inside data
struct Book books[0];
unsigned int books_count = get_books_from(1973, 5, data, books);
return 0;
}
unsigned int get_books_from(unsigned int year, int length, struct Book data[], struct Book results[]) {
results = (struct Book*) malloc(sizeof(struct Book));
unsigned int results_count = 0;
int i;
for (i = 0; i < length; i++) {
if (data[i].published == year) {
*(results + results_count) = data[i];
results = (struct Book*) realloc(results, (++results_count + 1) * sizeof(struct Book));
}
}
return results_count;
}
The logic seems to be working fine, however when trying to access the books array contents outside of the get_books_from function (where it's called results), all the data becomes corrupted. Some of the original data is still there but not in the right places, it looks as if the data got shifted. I checked the pointers to both books and results and it appears that those variables do not point to the same place in memory after the function finishes. What could be the problem?
Your get_books_from changes the value of results here:
results = (struct Book*) realloc(results, (++results_count + 1) * sizeof(struct Book));
But it provides no way for the caller to get the new value of results.
Worse, you call get_books_from with data, which was allocated on the stack in main. You can't realloc it. As the documentation for realloc says, the pointer you are attempting to reallocate must been returned by a previous call to malloc, calloc, or realloc. Fortunately, you ignore that value. But that renders the struct Book data[5]; in main incomprehensible. Why allocate space on the stack?
In addition to the other answer:
You probably want something like this (untested, non error checking code, declarations and #includes ommited for brevity):
unsigned int get_books_from(unsigned int year, int length, struct Book data[], struct Book **results);
int main(int argc, char* argv[]) {
struct Book data[5];
// Init book pool inside data
struct Book *books;
unsigned int books_count = get_books_from(1973, 5, data, &books);
return 0;
}
unsigned int get_books_from(unsigned int year, int length, struct Book data[], struct Book **results) {
*results = (struct Book*) malloc(sizeof(struct Book));
unsigned int results_count = 0;
int i;
for (i = 0; i < length; i++) {
if (data[i].published == year) {
*(*results + results_count) = data[i];
*results = (struct Book*) realloc(*results, (++results_count + 1) * sizeof(struct Book));
}
}
return results_count;
}

Writing an array of structs to a binary file in C

I have an array of structs I would like to write to a binary file. I have a write.c program and a read.c program. The write.c program seems to be working properly but when I run the read.c program I get a segmentation fault. I'm new to C so It would be great if someone could look over my code for any obvious errors. I promise it's not too long :)
write.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
struct Person* people;
int people_count;
printf("How many people would you like to create: ");
scanf("%i", &people_count);
people = malloc(sizeof(struct Person) * people_count);
int n;
for (n = 0; n < people_count; n++)
{
printf("Person %i's First Name: ", n);
scanf("%s", people[n].f_name);
printf("Person %i's Last Name: ", n);
scanf("%s", people[n].l_name);
printf("Person %i's Age: ", n);
scanf("%i", &people[n].age);
}
FILE* data;
if ( (data = fopen("data.bin", "wb")) == NULL )
{
printf("Error opening file\n");
return 1;
}
fwrite(people, sizeof(struct Person) * people_count, 1, data);
fclose(data);
return 0;
}
read.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
FILE* data;
if ((data = fopen("data.bin", "rb")) == NULL)
{
printf("Error opening file\n");
return 1;
}
struct Person* people;
fread(people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
printf("%s\n", people[0].f_name);
fclose(data);
return 0;
}
Thanks for the help!
struct Person* people;
This allocates just a pointer to struct, but you don't have any allocated space for actual struct contents. Either use malloc similarly to your write program, or try something like:
struct Person people;
fread(&people, sizeof(people), 1, data);
You need to allocate memory for the person first. Change: struct Person* people; into struct Person* people = malloc(sizeof(struct Person));. And don't forget to free your memory at the end: free(people);.
You either need to malloc memory into the pointer variable people before you do the fread, or (easier) just read directly into a local variable:
struct Person people;
fread(&people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
You need to allocate space for the data you are reading in:
people = malloc(sizeof(*people)*numPeople);

Resources