В вашей двоичной рутине, ваши, если являются сравнение idNo
против list[middle]
, когда нужно сравнить с list[middle].idNo
Вы могли бы упростить немного, используя массив 1D, который получает realloc'ed, а не 2D массив указателей. Весь код будет проще, и вы не потеряете никаких функций.
UPDATE
Я переключился свой код, чтобы использовать массив структур, а не массив указателей на структуры. Это упрощает вещи, и поиск по двум уровням просто добавляет сложности, которые, вероятно, сбивают вас с толку. Кроме того, убрали больше стиля - извините, но это то, как я смог увидеть достаточно вашей логики, чтобы внести изменения.
Примечание: Я полностью согласен с Дэвидом [и многими другими] в отношении предупреждений о компиляторе. Они твои друзья. Обычно они показывают ошибки, которые сложнее найти в 10 раз с запущенной программой. Я делал C в течение многих лет, я [еще] всегда использование -Wall -Werror
Если вы хотите узнать больше о указателях на структуры, массивы структур, увидеть мой недавний ответ Issue implementing dynamic array of structures Он имеет грунтовку на различные способы переключения между массивами, указатели на массивы, индексирование указателей и т. д., которые могут быть полезны.
Добавлен полный диагностический набор, который доказывает алгоритм binsrch, включая краевые случаи, которые могут не отображаться для заданного набора данных, прежде чем повернуть его на реальные/большие данные. Хорошая техника для запоминания.
Заметьте, что я не уверен, почему вы передали low/high как аргументы, поскольку они не служат цели для двоичного поиска в целом. Они полезны, если вы хотите получить определенное подмножество данных. Если это так, закомментируйте мой дополнительный код, сбросив его.
// 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;
}
Напишите функцию 'print_list', которая имеет тот же цикл' for', что и указанный код. Вызовите 'printf' вместо' fscanf' в цикле. Вызовите 'print_list' после вызова' create_class_list'. Если это не поможет, проясните, что вы действительно спрашиваете. – kaylum
@kaylum спасибо. Чтобы уточнить, я прошу помощи в использовании оператора указателя структуры. – tansy
Выглядит в основном нормально. Просто измените '& (list [i] -> IDno)' to 'list [i] -> IDno' – kaylum