# C: Printing specific elements of a structure

Tags:
1. Aug 19, 2015

### gruba

1. The problem statement, all variables and given/known data
I have the following code which manipulates with basics of structures.
There are function like reading and sorting data from structures.

Now, I don't know how to write a function that reads name and surname of an author of a book,
Prototype of a function is
Code (Text):
void print(BOOK *pb,int n,char *p_surname,char *p_name)
2. Relevant equations
-Structures
-Pointers

3. The attempt at a solution
Code (Text):

#include <stdio.h>
#include<stdlib.h>

typedef struct
{
char surname[20];
char name [20];
}AUTHOR;

typedef struct
{
char title[20];
int year;
int number_of_authors;
AUTHOR *author;
}BOOK;

{
printf("surname:");
scanf("%s",pa->surname);
printf("name:");
scanf("%s",pa->name);

}

{
printf("title:");
scanf("%s",pb->title);
printf("publish year:");
scanf("%d",&pb->year);
printf("number of authors:");
scanf("%d",&pb->number_of_authors);
pb->author=calloc(pb->number_of_authors,sizeof(*pb->author));
int i;
for(i=0;i<pb->number_of_authors;i++)
{
printf("%d. authors:\n",i+1);
}
}

int compare_authors(AUTHOR *a,AUTHOR *b)
{
int i;
for(i=0;a->surname[i] && a->surname[i] == b->surname[i];i++);
return a->surname[i]-b->surname[i];
}

void sort_authors(AUTHOR *array,int n)
{
int i,j;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(compare_authors(array+i,array+j)>0)
{
AUTHOR temp=array[i];
array[i]=array[j];
array[j]=temp;
}
}

int compare_books(BOOK *a,BOOK *b)
{
int i;
for(i=0;a->title[i] && a->title[i] == b->title[i];i++);
return a->title[i]-b->title[i];
}

void sort_books(BOOK *array,int n)
{
int i,j;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
{
if(compare_books(array+i,array+j)>0)
{
BOOK temp=array[i];
array[i]=array[j];
array[j]=temp;
}
else
if((compare_books(array+i,array+j) == 0) )
{
BOOK temp=array[i];
array[i]=array[j];
array[j]=temp;
}

}
}

int main()
{
int i,n;
BOOK *array;
char psurname[101],pname[101];
do
{
printf("n=");
scanf("%d",&n);
}
while(n<1);
array=(BOOK *)malloc(n*sizeof(BOOK));
printf("enter books:\n");
for(i=0;i<n;i++)
{
printf("%d. book:\n",i+1);
}
sort_books(array,n);
free(array);
return 0;
}

I don't know how to write a function for printing data about books that are from input author:
Code (Text):

void print(BOOK *pb,int n,char *psurname,char *pname)
{
int i,j;
scanf("%s",psurname);
scanf("%s",pname);
for(i=0;i<n;i++)
{
for(j=0;j<pb->number_of_authors;j++)
{
if((compare_authors(pb->author[j].surname,psurname)== 0) &&
(compare_authors(pb->author[j].name,pname)==0))
printf("%s %d %d %s %s",pb->title,pb->year,pb->number_of_authors,
pb->author[j].surname,pb->author[j].name);
}
}
}

Could someone help with this function?
Thanks for replies.

2. Aug 19, 2015

### SteamKing

Staff Emeritus
You'll have to make an attempt at writing your own function. Those are the rules for the HW forums at PF, even for programmers.

It's not clear what is the problem here. Are you trying to list the works by an author having a certain name?

It seems that if you have a particular name to search for, you should search through your database, and every time a hit is made on the author's name, you extract and print the corresponding book title.

3. Aug 19, 2015

### Zondrina

I notice there are several errors in the functions you have wrote.

--------------------

First, the read_book function is not written properly:

Code (Text):

{
printf("title:");
scanf("%s",pb->title);
printf("publish year:");
scanf("%d",&pb->year);
printf("number of authors:");
scanf("%d",&pb->number_of_authors);

pb->author=calloc(pb->number_of_authors,sizeof(*pb->author));
int i;
for(i=0;i<pb->number_of_authors;i++)
{
printf("%d. authors:\n",i+1);
}
}

1. Why do you compute so many unnecessary pointers when reading in the year and number of authors?

2. When setting up the author(s), why not use a simple malloc call to allocate the appropriate amount of authors, i.e malloc(sizeof(AUTHOR)*pb->number_of_authors). It is simpler than a calloc call, and avoids typecasting altogether. The only problem is the way the elements are initialized, so you have to be careful. Then you can use your loop and read_author function to assign a name and surname to each author.

--------------------

Second, the function you wrote that compares two authors is wrong:

Code (Text):

int compare_authors(AUTHOR *a,AUTHOR *b)
{
int i;
for(i=0;a->surname[i] && a->surname[i] == b->surname[i];i++);
return a->surname[i]-b->surname[i];
}

1. Should you not compare the name and the surname? Try returning 1 if the name and surname are equal for both authors, and 0 otherwise. You could also import <stdbool.h> and return a _Bool instead.

2. While it may be inefficient, the 'easiest' way think about this is to compare each name and surname char by char using a loop. If the loop executes fully, then return true. If one of the chars don't match, return false.

--------------------

Third, I think some improvements can be made to the bubble sort you used for the sort_authors function:

Code (Text):

void sort_authors(AUTHOR *array,int n)
{
int i,j;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(compare_authors(array+i,array+j)>0)
{
AUTHOR temp=array[i];
array[i]=array[j];
array[j]=temp;
}
}

1. See this link for details: https://en.wikipedia.org/wiki/Bubble_sort#Optimizing_bubble_sort

--------------------

Fourth, your compare_books function has the same problem as the compare_authors function:

Code (Text):

int compare_books(BOOK *a,BOOK *b)
{
int i;
for(i=0;a->title[i] && a->title[i] == b->title[i];i++);
return a->title[i]-b->title[i];
}

1. See the advice I gave you for compare_authors because the solution is similar.

--------------------

Fifth, you are using bubble sort for sort_books again and improvements can be made:

Code (Text):

void sort_books(BOOK *array,int n)
{
int i,j;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
{
if(compare_books(array+i,array+j)>0)
{
BOOK temp=array[i];
array[i]=array[j];
array[j]=temp;
}
else
if((compare_books(array+i,array+j) == 0) )
{
BOOK temp=array[i];
array[i]=array[j];
array[j]=temp;
}

}
}

1. Once again, see this link for details: https://en.wikipedia.org/wiki/Bubble_sort#Optimizing_bubble_sort

--------------------

So you want to read in the name and a surname of an author. Then you want to loop through an array of books. If the name and surname entered match the name and surname of the author of the book, then you want to print information about the book.

Is that correct?

If so, then I don't see the reason to use this prototype:

Code (Text):
void print(BOOK *pb, int n, char *psurname, char *pname)
Why do you need the char pointers? If you are reading in the name and surname inside the function, then all you have to do is compare the name and surname you read in to the name and surname of the author of the book. Instead the prototype should be:

Code (Text):
void print(BOOK *pb, int n)
Where the parameter $n$ is the size of the book array. You have to loop over all the books, and make sure to check all of the authors for each book.

Whew, that's quite a bit of coding to do, but feel free to ask questions if you get stuck.

Last edited: Aug 19, 2015
4. Aug 19, 2015

### Staff: Mentor

Because scanf() requires the address of an input buffer for all of the variables it is used to read.
No. The returned value from both calloc() and malloc() is a void pointer, so C code should cast the returned value to the appropriate type. Also, the main difference between these two functions is that calloc() returns a block of memory that is initialized to zero.
Zondrina apparently didn't notice, but whatever strings you're comparing, you can't use == to compare them. In C, a string (i.e., a char * type) evaluates to the location in memory of the first character, so the comparisons above are comparing addresses, not the contents of two strings.

Although it is fairly easy to write a loop and compare the two strings character by character, it's probably safer to use the standard library function strcmp() or one of its variants.
Again, that's not how to compare strings.

5. Aug 19, 2015

### Zondrina

I've been coding in java too often. I forgot scanf() requires a pointer to be computed. I wonder if they will ever write a version where you don't have to pass an address.

I forgot the return types of those as well, gosh its been a while since I've done C. I do remember the main difference was the way the memory is initialized though.

I know you can't use '==' to compare strings since it compares by reference. For example, in java we use equals() in class String to compare two String objects. The OP is the person unaware I believe.

I assumed the OP has no knowledge of standard library functions considering the code I've seen so far. So I provided the OP with a relatively simple thought process instead.