In your binary search routine, your if's are comparing idNo
against list[middle]
when they need to compare against list[middle].idNo
You could simplify a bit by using a 1D array that gets realloc'ed rather than a 2D array of pointers. The entire code will be simpler and you won't lose any functionality.
UPDATE
I've switched your code to use an array of structs rather than an array of pointers to structs. It simplifies things and the two level lookup was just adding complexity that was probably tripping you up. Also, cleaned up more style-wise--Sorry about that but it's how I was able to see enough of your logic in order to make the changes.
Note: I agree completely with David [and many others] about compiler warnings. They are your friends. They usually show bugs that are 10x harder to find with a running program. I've been doing C for many years, I [still] always use -Wall -Werror
If you'd like to learn more about pointers to structs, arrays of structs, see my recent answer Issue implementing dynamic array of structures It has a primer on the various ways to switch between arrays, pointers to arrays, indexing of pointers, etc. that may be useful.
Added a full diagnostic suite that proves the binsrch algorithm, including edge cases that might not appear for a given set of data before turning it loose on real/large data. A good technique to remember.
Note that I'm not sure why you passed low/high as arguments as they serve no purpose for binary search in general. They're useful if you wanted a specific subset of the data. If so, comment out my extra code resetting them.
// binsrch -- program to do binary search
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int IDno;
char name[20];
int project;
int exam;
double final;
} student;
student *
create_class_list(char *filename,int *sizeptr)
{
int n;
int i;
FILE *fptr;
student *cur;
student *list;
fptr = fopen(filename,"r");
if (fptr == NULL)
printf("The file could not be opened.\n");
else
fscanf(fptr,"%d",sizeptr);
n = *sizeptr;
list = calloc(n,sizeof(student));
for (i = 0; i < n; i++) {
cur = &list[i];
fscanf(fptr,"%d %[^\n]s",&cur->IDno,cur->name);
}
fclose(fptr);
return list;
}
void
print_list(student *list,int count)
{
int i;
student *cur;
for (i = 0; i < count; i++) {
cur = &list[i];
printf("%d %s\n",cur->IDno,cur->name);
}
}
student *
find_binsrch(int idNo,student *list,int count,int low,int high)
{
student *cur;
int middle;
student *match;
match = NULL;
// what is the purpose of the limited range? -- ignore for now
low = 0;
high = count - 1;
while (low <= high) {
middle = (low + high) / 2;
cur = &list[middle];
//printf("find_binsrch: TRACE middle=%d\n",middle);
if (idNo == cur->IDno) {
match = cur;
break;
}
if (idNo < cur->IDno)
high = middle - 1;
else
low = middle + 1;
}
return match;
}
#define RAND0(_lim) \
(rand() % _lim)
#define RAND1(_lim) \
(RAND0(_lim) + 1)
// diag_binsrch -- run diagnostic on single array size
void
diag_binsrch(int count)
{
student *list;
student *cur;
int searchidx;
student *match;
int err;
list = calloc(count,sizeof(student));
searchidx = 0;
cur = &list[searchidx];
cur->IDno = RAND1(30);
// create interesting data
++searchidx;
for (; searchidx < count; ++searchidx)
list[searchidx].IDno = list[searchidx - 1].IDno + RAND1(137);
err = 0;
// search for something lower that the lowest -- we _want_ it to fail
searchidx = 0;
cur = &list[searchidx];
match = find_binsrch(cur->IDno - 1,list,count,1200,4580);
if (match != NULL) {
printf("DIAG: expected failure -- searchidx=%d cur=%d match=%d\n",
searchidx,cur->IDno - 1,match->IDno);
++err;
}
// search for something higher that the highest -- we _want_ it to fail
searchidx = count - 1;
cur = &list[searchidx];
match = find_binsrch(cur->IDno + 1,list,count,0,count - 1);
if (match != NULL) {
printf("DIAG: expected failure -- searchidx=%d cur=%d match=%d\n",
searchidx,cur->IDno + 1,match->IDno);
++err;
}
// search for all remaining entries -- they should all match
cur = list;
for (searchidx = 0; searchidx < count; ++searchidx, ++cur) {
match = find_binsrch(cur->IDno,list,count,0,count - 1);
if (match == NULL) {
printf("DIAG: null return -- searchidx=%d IDno=%d\n",
searchidx,cur->IDno);
++err;
continue;
}
if (match->IDno != cur->IDno) {
printf("DIAG: mismatch -- searchidx=%d cur=%d match=%d\n",
searchidx,cur->IDno,match->IDno);
++err;
continue;
}
}
free(list);
if (err)
exit(1);
}
// diag_binsrch_full -- run full diagnostic
void
diag_binsrch_full(void)
{
int count;
printf("diag_binsrch_full: start ...\n");
for (count = 1; count < 1000; ++count)
diag_binsrch(count);
for (count = 1000; count <= 10000000; count *= 10)
diag_binsrch(count);
printf("diag_binsrch_full: complete\n");
}
int
main(void)
{
int listCount;
student *listPtr;
//student *cur;
//student *match;
// run diagnostic
diag_binsrch_full();
exit(0);
listPtr = create_class_list("student.txt",&listCount);
print_list(listPtr,listCount);
#if 0
match = find_binsrch(searchID,listPtr,n,1200,4580);
if (match != NULL)
printf("main: MATCH IDno=%d name='%s'\n",match->IDno,match->name);
#endif
return 0;
}