Using bsearch in C failed to find a string 'Eva Lam' in an array of structure. This array is sorted in descending order of string members. I checked many times, still don't know where the bug is? BTW, I am using DEV C++ 5.9.4. Please help, many thanks.
#include <stdio.h>
#include <stdlib.h> // for bsearch
#include <string.h>
#define SIZE 4
#define NAME_SIZE 20
struct student {
int id;
char name[NAME_SIZE];
};
// Function prototypes
int comp_name(const void* a, const void* b);
void print_struct_array(struct student studs[], int size, int serial);
int main(){
int i, option=0;
struct student *stud, *target;
// studs array already sort in descending order of name
struct student studs[SIZE] = {{14123456, "Mary Chan"}
, {11001234, "Eva Lam"}
, {10123456, "David Wong"}
, {12345678, "Chris So"}
};
printf("*** Before Searching ***\n");
print_struct_array(studs, SIZE, 1);
target = (struct student*) malloc(sizeof(struct student));
if (target == NULL) {
fprintf(stderr, "Out of memory!\n");
return -1;
}
printf("Input student name to search: ");
scanf("%[^\n]", target->name);
fflush(stdin);
printf("name=%s\n", target->name);
stud = (struct student *)bsearch(target->name, studs, SIZE,
sizeof(struct student), comp_name);
if (!stud)
printf("name %s not found!\n", target->name);
else
printf("[id, name] found is [%d, %s]\n", stud->id, stud->name);
return 0;
}
int comp_name(const void* a, const void* b) {
printf("comp_name: a->name=%s, b->name=%s\n",
(*(struct student *)a).name, (*(struct student *)b).name);
return strcmp((*(struct student *)b).name,
(*(struct student *)a).name);
}
void print_struct_array(struct student studs[], int size, int serial) {
int i;
printf("Student array #%d is {\n", serial);
for (i=0; i<SIZE; i++) {
if (i==0)
printf(" ");
else if (i<=SIZE-1)
printf(", ");
printf("[%d, %s]\n", studs[i].id, studs[i].name);
}
printf("}\n");
}
But the output of the program when searching 'Eva Lam' is:
*** Before Searching ***
Student array #1 is {
[14123456, Mary Chan]
, [11001234, Eva Lam]
, [10123456, David Wong]
, [12345678, Chris So]
}
Input student name to search: Eva Lam
name=Eva Lam
comp_name: a->name=Lam, b->name=Eva Lam
comp_name: a->name=Lam, b->name=Mary Chan
name Eva Lam not found!
--------------------------------
Process exited after 8.216 seconds with return value 0
Read the documentation for bsearch more carefully.
The compar routine is expected to have two arguments which point to the key object and to an array member, in that order.
This means that the first argument to your compare function will always be exactly what you gave as a first argument to bsearch. So either call it as: bsearch(target, studs, ...) or better yet, rewrite your compare function to:
int
comp_name(const void *av, const void *bv) {
const char *a = av;
const struct student *b = bv;
printf("comp_name: a->name=%s, b->name=%s\n", a, b->name);
return strcmp(b->name, a);
}
Also, please don't cast void * pointers in C, especially from malloc, but also the return value from bsearch in your code.
Related
I'm having a problem to allocate a structure dynamically.
I'm making a program that works as a contact book, but I'm getting the
following error: Segmentation fault (core dumped).
The structure declaration, following the functions to add a contact
and print all contacts:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct contact{
int number;
char name[80];
}contact;
void addContact(contact **contacts, int position){
int aux=position;
printf("Enter the name: ");
setbuf(stdin, 0);
fgets(contacts[position]->name,80,stdin);
printf("Enter the telephone number: ");
scanf("%d",&contacts[position]->number);
return;
}
void printAllContacts(contact **contacts, int size){
for(int i;i<size;i++){
printf("Contact %d:\n",i);
printf("Name: %s\n",contacts[i]->name);
printf("Telephone number: %d \n",contacts[i]->number);
}
}
// Main function:
int main(){
int size;
printf("Enter the list size: ");
scanf("%d",&size);
contact *contacts= (contact*)malloc(sizeof(contact)*size);
int counter=0;
int x;
do{
printf("------------MENU-----------\n");
printf("1-Add contact\n");
printf("2-Print contacts list\n");
printf("0-Exit\n");
printf("----------------------------\n");
printf("Enter an option: ");
scanf("%d",&x);
switch (x){
case 1:
addContact(&contacts,counter);
counter++;
break;
case 2:
printAllContacts(&contacts,counter);
break;
case 0:
break;
}
}while(x!=0);
return 0;
}
Can anyone help?
The basic problem is that you're allocating an array of struct contact objects, but your addContact and printAllContacts expect an array of pointers to struct contact. You need to choose one or the other.
The easiest fix is probably to change the functions -- change the argument type to contact * instead of contact **, remove the & at the call site in main, and change the -> to . in the functions where needed.
Pass in a pointer (contacts *) instead of pointer to pointer (contacts **) to addContact() & printAllContacts(). Updated caller, and partially updated called code which already assumed it was operating on an array.
Initialize i in printAllContacts().
Removed the unnecessary cast of malloc() return value.
Removed the name of the struct as you use only use the typedef.
Introduced a NAME_LEN macro instead of the magic 80 value.
Minor reformatting for readability & consistency.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAME_LEN 80
typedef struct {
int number;
char name[NAME_LEN];
} contact;
void addContact(contact *contacts, int position) {
printf("Enter the name: ");
setbuf(stdin, 0);
fgets(contacts[position].name, NAME_LEN, stdin);
printf("Enter the telephone number: ");
scanf("%d", &contacts[position].number);
return;
}
void printAllContacts(contact *contacts, int size) {
for(int i=0; i<size;i++) {
printf("Contact %d:\n", i);
printf("Name: %s\n", contacts[i].name);
printf("Telephone number: %d\n", contacts[i].number);
}
}
int main() {
int size;
printf("Enter the list size: ");
scanf("%d", &size);
contact *contacts = malloc(sizeof(contact)*size);
int counter=0;
int x;
do {
printf("------------MENU-----------\n");
printf("1-Add contact\n");
printf("2-Print contacts list\n");
printf("0-Exit\n");
printf("----------------------------\n");
printf("Enter an option: ");
scanf("%d", &x);
switch (x) {
case 1:
addContact(contacts, counter++);
break;
case 2:
printAllContacts(contacts, counter);
break;
case 0:
break;
}
} while(x!=0);
return 0;
}
I would add additional structure holding all the contacts and also keeping the number of contacts stored. You do not need to know the size of the list - it will grow with any added contact.
When you test the idea I would advise you to not use user input functions, only fixed data. It makes debugging and testing faster and easier. Especially function which adds data should not communicate with the external world. Caller is the correct place to do it
Also use function return values to return result or status codes. You tend to use void everywhere - it is not a good idea.
typedef struct contact{
unsigned number;
char name[80];
}contact;
typedef struct
{
size_t size;
contact contacts[];
}constactList;
constactList *addContact(constactList *list, const char *name, const unsigned number)
{
size_t newsize = list ? list -> size + 1 : 1;
list = realloc(list, sizeof(*list) + sizeof(list -> contacts[0]) * newsize);
if(list)
{
strncpy(list -> contacts[list -> size].name, name, sizeof(list -> contacts[0].name));
list -> contacts[list -> size].name[sizeof(list -> contacts[0].name) - 1] = 0;
list -> contacts[list -> size].number = number;
list -> size = newsize;
}
return list;
}
void printContacts(const constactList *list)
{
if(list)
{
for(size_t i = 0; i < list -> size; i++) printf("[%3zu] %s, %u\n", i, list -> contacts[i].name, list -> contacts[i].number);
}
}
int main(void)
{
constactList *list = NULL;
list = addContact(list, "James Bond", 7);
if(!list) {/* error handling*/}
list = addContact(list, "Mata Hari", 99);
if(!list) {/* error handling*/}
list = addContact(list, "Wladymir Putin", 666);
if(!list) {/* error handling*/}
printContacts(list);
free(list);
}
Fields of Student: name, lastName, studentId, mid1Grade, mid2Grade, finalGrade, average
Fields of Course: courseName, courseCode, myStudentArray (array of Student structures),currentStudentCount
Functions:
void createNewStudent(struct Course *myCourse);
void setGradeOfStudent(struct Course *myCourse);
void findAndDisplayAverage(struct Course *myCourse);
struct Student * findStudentByID(int id, struct Course *myCourse);
void displayAverageOfAllStudents(struct Course *myCourse);
void displayAverageOfStudentsInInterval(struct Course *myCourse
ok so I have written the first function but there is an error which I dont understand. First of all the first function and what it does:
createNewStudent: Prompt the user to enter name, last name and id of the new student.Values entered by the user are assigned to the fields of the student residing in themyStudentArray of course variable pointed by myCourse. currentStudentCount will be updated so that it designates the slot allocated for the student inserted next.
and my implementation:
#include <string.h>
#include <stdio.h>
struct Student {
char name[50];
char lastname[50];
int id;
int mid1;
int mid2;
int final;
double average;
};
struct Course {
char courseName[50];
char courseCode[50];
struct Student myStudentArray[5];
int currentstudentcount;
};
void createNewStudent(struct Course * myCourse);
void setGradeOfStudent(struct Course * myCourse);
void findAndDisplayAverage(struct Course * myCourse);
struct Student * findStudentByID(int id, struct Course * myCourse);
void displayAverageOfAllStudents(struct Course * myCourse);
void displayAverageOfStudentsInInterval(struct Course * myCourse);
int main() {
struct Student * stud;
int input = 0;
scanf("%d", & input);
if (input == 1) {
createNewStudent(struct Course * myCourse);
}
}
return 0;
}
void createNewStudent(struct Course * myCourse) {
struct Student s1;
printf("Enter name: ");
scanf("%[^\n]%*c", s1.name);
printf("Enter Surname: ");
scanf("%[^\n]%*c", s1.lastname);
printf("Enter id: ");
scanf("%d", & s1.id);
}
When you call the function with the if(input == 1) it gives
error: expected expression before ‘struct’
but I dont understand this beacuse *myCourse is just a pointer to the Course struct isn't it ????
If I can understand this ı will be able to the the next functions I think
Is the function correct ?? I dont know why this doesnt work
Ok I tried to use the struct Student myStudentArray[5]; to get name, lastname,id like so (structs are the same)
void createNewStudent(struct Course *myCourse);
void setGradeOfStudent(struct Course *myCourse);
int main(){
struct Course *myCourse;
int input=0;
scanf("%d",&input);
if(input == 1){
createNewStudent(myCourse);
}
return 0;
}
void createNewStudent(struct Course *myCourse){
myCourse->currentstudentcount=0;
printf("Enter name: ");
scanf("%[^\n]%*c"
,myCourse->myStudentArray[myCourse->currentstudentcount].name);
printf("Enter Surname: ");
scanf ("%[^\n]%*c",
myCourse->myStudentArray[myCourse->currentstudentcount].name);
myCourse->currentstudentcount++;
}
I Keep getting
may be used uninitialized in this may be used uninitialized in this function [-Wmaybe-uninitialized]
and
Segmentation errors
void createNewStudent(struct Course * myCourse)
If you want to create new student, you should use the student struct as the parameter of this function instead of using struct Course.
void createNewStudent(struct Student *s1)
Then, this function becomes as:
void createNewStudent(struct Student *s1) {
printf("Enter name: ");
scanf("%49s", s1->name);
printf("Enter Surname: ");
scanf("%49s", s1->lastname);
printf("Enter id: ");
scanf("%d", & s1->id);
}
If you want to test, in main function, you can declare the value stud or the pointer to struct Student.
For example:
int main() {
struct Student stud;
int input = 0;
scanf("%d", & input);
if (input == 1) {
createNewStudent(&stud);
printf("name: %s\n Surname: %s\n id = %d\n", stud.name, stud.lastname, stud.id);
}
return 0;
}
The complete program for test:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
struct Student {
char name[50];
char lastname[50];
int id;
int mid1;
int mid2;
int final;
double average;
};
struct Course {
char courseName[50];
char courseCode[50];
struct Student myStudentArray[5];
int currentstudentcount;
};
void createNewStudent(struct Student *s1);
int main() {
struct Student stud;
int input = 0;
scanf("%d", & input);
if (input == 1) {
createNewStudent(&stud);
printf("name: %s\nSurname: %s\nid = %d\n", stud.name, stud.lastname, stud.id);
}
return 0;
}
void createNewStudent(struct Student *s1) {
printf("Enter name: ");
scanf("%49s", s1->name);
printf("Enter Surname: ");
scanf("%49s", s1->lastname);
printf("Enter id: ");
scanf("%d", & s1->id);
}
The output:
#./test
1
Enter name: abc
Enter Surname: def
Enter id: 100
name: abc
Surname: def
id = 100
Update for your question in the comment:
If you want to store student info in an array, you can change the code to:
struct Student myStudentArray[5];
int input = 0;
scanf("%d", & input);
if (input == 1) {
for (int i = 0; i < 5; i++) {
createNewStudent(&myStudentArray[i]);
}
for (int i = 0; i < 5; i++) {
printf("name: %s\nSurname: %s\nid = %d\n", myStudentArray[i].name, myStudentArray[i].lastname, myStudentArray[i].id);
}
}
For Course structure you can create one function as the function createNewStudent but for struct Course to create the new course. After creating new 5 students (for example the code above), you can copy the myStudentArray to new_course.myStudentArray. Then now you have the info of 5 students in new_course. When you copy value from an array to another, you can use memcpy or using one loop to copy each element from one array to another one. Do not use something like myStudentArray = new_course.myStudentArray for the array.
You are making a declaration as a parameter of the createNewStudent() function. In C, functions require expressions as parameters, which is why you got the error message "expected expression...".
So, just create the struct pointer before you call the function:
if (input == 1) {
struct Course *myCourse = malloc(sizeof(struct Course));
createNewStudent(myCourse);
}
Notice the use of malloc(), which returns a pointer to a place in memory of sufficient size to hold that particular Course struct. When dealing with pointers to structs, you need to allocate memory for the structs that will ultimately be pointed to, in order to avoid dereferencing unallocated regions of memory.
In your function CerateNewStudent, the proper way to address the variables into which to place the data read by scanf should be:
myCourse->myStudentArray[myCourse->currentstudentcount].name
as the variable to read name into. Use this syntax for all data items to read. After that, increment the counter:
myCourse->currentstudentcount++;
Note: what is missing in all your functions (and in the assignment?) is a way to create a course. The students created are all added to courses. First a course should be created and then students can be added to it.
I want to pass a structure pointer to a function that will dynamically create a array of structures at the location pointed to by the structure pointer that was passed. I am able to create and fill the array of structure successfully but when trying to print the data in the calling function using the pointer that was passed gives me a garbage values. Please help me know why my structure pointer is pointing to garbage and how can I access my data correctly.
The following is just some example code to demonstrate how the structure is passed and dynamically filled using malloc & realloc. this is INCORRECT method:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
int id;
char name[20];
float percentage;
};
void func(struct student *record);
int main()
{
struct student *record = NULL;
record = (struct student *)malloc(sizeof(struct student));
func(record);
if(record != NULL)
{
for(int i=0; i<2; i++)
{
printf(" 1 Id is: %d \n", record[i].id);
printf(" 1 Name is: %s \n", record[i].name);
printf(" 1 Percentage is: %f \n", record[i].percentage);
printf("\n");
}
}
else
{
printf("record pointer is null");
}
return 0;
}
void func(struct student *record1)
{
for(int i=0; i<2; i++)
{
if(i)
{
record1 = (struct student *)realloc(record1,sizeof(struct student)*(i+1));
}
record1[i].id=1;
strcpy(record1[i].name, "Raju");
record1[i].percentage = 86.5;
}
}
The following is a similar example using double pointer which is the CORRECT way to do this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
int id;
char name[20];
float percentage;
};
void func(struct student **record);
int main()
{
struct student *record = NULL;
func(&record);
if(record != NULL)
{
for(int i=0; i<2; i++)
{
printf(" 1 Id is: %d \n", record[i].id);
printf(" 1 Name is: %s \n", record[i].name);
printf(" 1 Percentage is: %f \n", record[i].percentage);
printf("\n");
}
}
else
{
printf("record pointer is null");
}
free(record);
return 0;
}
void func(struct student **record1)
{
*record1 = (struct student *)malloc(sizeof(struct student));
for(int i=0; i<2; i++)
{
if(i)
{
*record1 = (struct student *)realloc(*record1,sizeof(struct student)*(i+1));
}
(*record1)[i].id=1;
strcpy((*record1)[i].name, "Raju");
(*record1)[i].percentage = 86.5;
}
}
Your first solution,
record1 = (struct student *)realloc(record1,sizeof(struct student)*(i+1));
works as long as realloc does not have to move the pointer! That is, realloc just expands the memory area it gave earlier to record1. Should, at some later stage, realloc be required to give you another piece of memory, then the earlier pointer record in main will become invalid and could now contain your "garbage".
As you were thinking, you need a double pointer to be able to see the changed pointer in main. You were nearly there, just a typo:
*record1 = (struct student *)realloc(record1,sizeof(struct student)*(i+1));
in the above line the second occurrence of record1 must also be dereferenced, so *record1 because you must give realloc the original pointer.
Oh, and don't cast the result of malloc! Although the compiler does not complain, it can cause future problems.
I was working on a circular linked list problem and solved it.But i got stuck in other problem. The program takes names of persons in circular linked list nodes and prints them.
My question is that program works fine if and only if the names are 4 characters or less.If the length of the names exceeds 4,it shows weird behaviour.
If the length of name is 5 characters,then the program is stuck on second iteration of the for loop of the initiate function.
If the length of name is 6 characters or more then program terminates immediately showing the names entered.
The source code is:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define SIZE 10
#define NUM_PER_LINE 3
typedef struct node
{
char name[SIZE];
struct node * next;
} CListNode;
void get_name(char *a);
void print_list(CListNode *end_ptr);
CListNode *initiate(int n);
CListNode *insert_at_end(CListNode *first,CListNode *end_ptr, char *a);
int main(void)
{
CListNode *list_end_ptr;
int n=6;
list_end_ptr=initiate(n);
print_list(list_end_ptr);
return 0;
}
void get_name(char *a)
{
char *aa=(char *)malloc(10*sizeof(char));
a=aa;
scanf("%s", a);
}
CListNode *insert_at_end(CListNode *first,CListNode *end_ptr, char *a)
{
CListNode *temp, *head=NULL;
head=first;
temp=(CListNode *) malloc(sizeof(CListNode));
end_ptr->next=temp;
strcpy(temp->name, a);
temp->next=head;
return temp;
}
CListNode *initiate(int n)
{
CListNode *end, *first=NULL,*ptr=NULL;
int i;
char new_name;
end=(CListNode *) malloc(sizeof(CListNode));
if (end==0) {
printf("Allocation error...\n");
exit(0); }
end->next=end;
for (i=0; i<n; i++) {
if (i<1) {
printf("Enter the name of the %d person: ", i+1);
get_name(&new_name);
strcpy(end->name, &new_name);
first=end;
}
else
{
printf("Enter the name of the %d person: ", i+1);
get_name(&new_name);
ptr=insert_at_end(first,end, &new_name);
end=ptr;
}
}
return end;
}
void print_list(CListNode *end_ptr)
{
int i=1;
CListNode *str_ptr;
if (end_ptr == NULL)
printf("\n List is empty");
else
{
str_ptr = end_ptr->next;
while (str_ptr != end_ptr)
{
printf("%s \t", str_ptr->name);
str_ptr = str_ptr->next;
if (i%NUM_PER_LINE==0) {
printf("\n");
}
i++;
}
printf("%s\n", str_ptr->name);
}
}
The problem is in your get_name function and the way you use it. Its signature assumes that the storage is already allocated, because you take a pointer, not a pointer to pointer. Your code ignores the allocation completely; on top of that, it passes a pointer to character.
Since you allocate name within the node, remove malloc, remove new_name, and pass name array to get_name:
void get_name(char *a) {
scanf("%9s", a); // Limit the size to 9 chars
}
...
printf("Enter the name of the %d person: ", i+1);
get_name(end->name);
I have come across this wierd and mysterous (at least to me) error that I am finding a very hard time finding. It gives me an error at the line where I call my function input(student_list1[MAX], &total_entries); where the compiler says:
incompatible type for agument 1 in 'input'
What am I doing wrong here? I sense it something very simple and stupid but I have gone through the code several times now without any avail.
#define MAX 10
#define NAME_LEN 15
struct person {
char name[NAME_LEN+1];
int age;
};
void input(struct person student_list1[MAX], int *total_entries);
int main(void)
{
struct person student_list1[MAX];
int total_entries=0, i;
input(student_list1[MAX], &total_entries);
for(i=0; i<total_entries; i++)
{
printf("Student 1:\tNamn: %s.\tAge: %s.\n", student_list1[i].name, student_list1[i].age);
}
return 0;
} //main end
void input(struct person student_list1[MAX], int *total_entries)
{
int done=0;
while(done!=1)
{
int i=0;
printf("Name of student: ");
fgets(student_list1[i].name, strlen(student_list1[i].name), stdin);
student_list1[i].name[strlen(student_list1[i].name)-1]=0;
if(student_list1[i].name==0) {
done=1;
}
else {
printf("Age of student: ");
scanf("%d", student_list1[i].age);
*total_entries++;
i++;
}
}
}
struct person student_list1[MAX] in the function argument is actually a pointer to struct person student_list1.
student_list1[MAX] you passed is a (out of bound) member of the array struct person student_list1[MAX]. Valid array index shoudl be between 0 to MAX - 1.
Change it to:
input(student_list1, &total_entries);
Note that here the array name student_list1 is automatically converted to a pointer to student_list1[0].
There are many things wrong with the code; this is my attempt at making it somewhat more robust:
#include <stdio.h>
#include <string.h>
#define MAX 10
#define NAME_LEN 15
// use a typedef to simplify code
typedef struct person {
char name[NAME_LEN];
int age;
} person_t;
// size qualifier on student_list is redundent and person_t* does the same
void input(person_t *student_list, int *total_entries);
int main(void)
{
person_t student_list[MAX];
int total_entries, i;
// pass array and not the non-existent 'student_list[MAX]' element
input(student_list, &total_entries);
for(i=0; i<total_entries; i++)
{
// age is an int, not a string so use %d
printf("Student 1:\tName: %s.\tAge: %d.\n", student_list[i].name, student_list[i].age);
}
return 0;
} //main end
void input(person_t *student_list, int *total_entries)
{
int done = 0, i = 0;
*total_entries = 0;
while (i < MAX) {
printf("Name of student: ");
// use NAME_LEN instead of strlen(list[i].name) because latter is
// probably not initialized at this stage
if (fgets(student_list[i].name, NAME_LEN, stdin) == NULL) {
return;
}
// detect zero-length string
if (student_list[i].name[0] == '\n') {
return;
}
printf("Age of student: ");
scanf("%d", &student_list[i].age);
// read the newline
fgetc(stdin);
*total_entries = ++i;
}
}
input(student_list1[MAX], &total_entries); shoud be input(student_list1, &total_entries);.
In C,
void input(struct person student_list1[MAX], int *total_entries);
equals
void input(struct person *student_list1, int *total_entries);