C: Printing specific elements of a structure

In summary, the conversation discusses the basics of structures and pointers, and then moves on to the problem of writing a function that prints data about books by a specific author. The code provided includes functions for reading and sorting data from structures, but the function for printing books by a specific author is not provided. Suggestions for improving the existing code are also given.
  • #1
gruba
206
1

Homework Statement


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,
and then prints data about books that are from read author.
Prototype of a function is
Code:
void print(BOOK *pb,int n,char *p_surname,char *p_name)

Homework Equations


-Structures
-Pointers

The Attempt at a Solution


Code:
#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;

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

}

void read_book(BOOK *pb)
{
  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);
  read_author(pb->author+i);
  }
}

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);
  read_book(array+i);
  }
  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:
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.
 
Physics news on Phys.org
  • #2
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
I notice there are several errors in the functions you have wrote.

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

First, the read_book function is not written properly:

Code:
void read_book(BOOK *pb)
{
  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);
  read_author(pb->author+i);
  }
}

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:
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:
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:
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:
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

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

Now, I don't know how to write a function that reads name and surname of an author of a book,
and then prints data about books that are from read author.

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:
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 into the name and surname of the author of the book. Instead the prototype should be:

Code:
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:
  • #4
Zondrina said:
I notice there are several errors in the functions you have wrote.

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

First, the read_book function is not written properly:

Code:
void read_book(BOOK *pb)
{
  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);
  read_author(pb->author+i);
  }
}

1. Why do you compute so many unnecessary pointers when reading in the year and number of authors?
Because scanf() requires the address of an input buffer for all of the variables it is used to read.
Zondrina said:
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.
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 said:
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:
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.
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.
Zondrina said:
--------------------

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

Code:
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:
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.
Again, that's not how to compare strings.
Zondrina said:
--------------------

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

Code:
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

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

Now, I don't know how to write a function that reads name and surname of an author of a book,
and then prints data about books that are from read author.

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:
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 into the name and surname of the author of the book. Instead the prototype should be:

Code:
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.
 
  • #5
Because scanf() requires the address of an input buffer for all of the variables it is used to read.

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.

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.

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.

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.

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.

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.

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.
 

Related to C: Printing specific elements of a structure

1. How do I print a specific element of a structure in C?

To print a specific element of a structure in C, you can use the dot operator (.) to access the individual element. For example, if you have a structure named "person" with elements for name and age, you can print the person's name by using printf("%s", person.name);

2. Can I print multiple elements of a structure at once in C?

Yes, you can print multiple elements of a structure at once in C by using the dot operator (.) to access each element and including them in the printf() statement. For example, printf("Name: %s, Age: %d", person.name, person.age);

3. How do I print a structure within a structure in C?

To print a structure within a structure in C, you can use the dot operator (.) to access the inner structure's elements. For example, if you have a structure called "address" with elements for street, city, and state, and a structure called "person" with elements for name and address, you can print the person's city by using printf("%s", person.address.city);

4. How can I print a specific element of a nested structure in C?

To print a specific element of a nested structure in C, you can use multiple dot operators (.) to access the desired element. For example, if you have a nested structure called "student" within a structure called "class" and you want to print the student's grade, you can use printf("%d", class.student.grade);

5. Can I print a structure's elements in a specific order in C?

Yes, you can print a structure's elements in a specific order in C by using the dot operator (.) to access each element and including them in the printf() statement in the desired order. For example, if you have a structure called "car" with elements for make, model, and year, but you want to print the year first, you can use printf("Year: %d, Make: %s, Model: %s", car.year, car.make, car.model);

Similar threads

  • Engineering and Comp Sci Homework Help
Replies
3
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
17
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
4
Views
959
  • Engineering and Comp Sci Homework Help
Replies
3
Views
913
  • Engineering and Comp Sci Homework Help
Replies
9
Views
3K
  • Engineering and Comp Sci Homework Help
Replies
9
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
5
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
12
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
1
Views
3K
Back
Top