结构指针运算符

时间:2015-11-06 00:21:50

标签: c arrays pointers

代码用于创建指向学生结构的指针数组,以便在其他函数中使用指针数组。我不确定如何在二进制函数中使用箭头运算符。它不会返回找到id的索引的值。

typedef struct{
    int IDno;
    char name[20];
    int project;
    int exam;
    double final;
} student;

student **create_class_list(char*filename, int *sizePtr);
void print_list(student**list,int *sizePtr);
int find_binsrch(int idNo, student **list, int size,int low, int high);

int main(void){

    int i, n; 
    student **listPtr;
    listPtr = create_class_list("student.txt", &n);
    print_list(listPtr,&n); 
    index2 = find_binsrch(searchID, listPtr, n, 1200, 4580);     
}

student **create_class_list(char *filename, int *sizeptr){

    int n,i;
    FILE *fptr; 
    fptr=fopen(filename,"r");
    if(fptr==NULL)
        printf("The file could not be opened.\n");
    else
        fscanf(fptr, "%d",sizeptr);

    n=*sizeptr;

    student **list;
    list = (student**)calloc(1, sizeof(student*));


    for(i=0;i<n;i++){
        list[i]=(student*)calloc(n,sizeof(student));
        fscanf(fptr,"%d %[^\n]s", &(list[i]->IDno),(list[i]->name));
    }

    return list;
}

void print_list(student**list,int *sizePtr){
    int i; 
    for(i=0; i<*sizePtr; i++){
        printf("%d %s\n",&(list[i]->IDno),(list[i]->name));
    }
}

int find_binsrch(int idNo, student **list, int size, int low, int high){
    int middle, i;

    while(low<=high){
        middle =(low+high)/2;

        printf("%d\n", middle); 

        if(idNo==list[middle]->IDno)
            return list[i]->IDno;

        if(idNo<list[middle]->IDno)
            high = middle -1;
        else
            low = middle +1;
    return -1;    
    }
}

2 个答案:

答案 0 :(得分:1)

每次编译时,您必须学会做的是启用警告。这允许编译器识别代码中需要注意的许多区域。您不应接受编译警告的代码。只有非常非常罕见的情况,依赖编译警告的代码是可以接受的(在编程的第一年你可能不会遇到这种情况)所以总是启用-Wall -Wextra作为编译字符串的一部分。 (您也可以启用-pedantic查看其他警告以及一些特定的警告请求,但对于一般用途-Wall -Wextra会这样做)

如果您编辑了警告,您会看到:

students3.c: In function ‘main’:
students3.c:23:5: error: ‘index2’ undeclared (first use in this function)
    index2 = find_binsrch(searchID, listPtr, n, 1200, 4580);
    ^
students3.c:23:5: note: each undeclared identifier is reported only once for each function it appears in
students3.c:23:27: error: ‘searchID’ undeclared (first use in this function)
    index2 = find_binsrch(searchID, listPtr, n, 1200, 4580);
                        ^
students3.c:19:9: warning: unused variable ‘i’ [-Wunused-variable]
    int i, n;
        ^
students3.c: In function ‘print_list’:
students3.c:53:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
        printf("%d %s\n",&(list[i]->IDno),(list[i]->name));
        ^
students3.c: In function ‘find_binsrch’:
students3.c:57:48: warning: unused parameter ‘size’ [-Wunused-parameter]
int find_binsrch(int idNo, student **list, int size, int low, int high){
                                                ^
students3.c: In function ‘main’:
students3.c:24:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
students3.c: In function ‘find_binsrch’:
students3.c:74:1: warning: control reaches end of non-void function [-Wreturn-type]
}
<snip>

简单地解决警告/错误并重新编译(以及解决修复第一个列表时发现的新警告/错误)将允许您系统地更正代码。采取这些基本步骤将允许您将代码更正为编译而无需警告:

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

typedef struct{
    int IDno;
    char name[20];
    int project;
    int exam;
    double final;
} student;

student **create_class_list(char*filename, int *sizePtr);
void print_list(student**list,int *sizePtr);
int find_binsrch(int idNo, student **list, int size,int low, int high);

int main(void){

    int n, index2, searchID = 2; 
    student **listPtr = NULL;
    listPtr = create_class_list("student.txt", &n);
    if (!listPtr) {
        fprintf (stderr, "error: create_class_list failed.\n");
        return 1;
    }
    print_list(listPtr,&n); 
    index2 = find_binsrch(searchID, listPtr, n, 1200, 4580);

    if (index2) {} /* stub to eliminate unused warning */

    return 0;
}

student **create_class_list(char *filename, int *sizeptr){

    int n,i;
    FILE *fptr; 
    fptr=fopen(filename,"r");
    if(fptr==NULL)
        printf("The file could not be opened.\n");
    else
        fscanf(fptr, "%d",sizeptr);

    n=*sizeptr;

    student **list;
    list = (student**)calloc(n, sizeof(student*));


    for(i=0;i<n;i++){
        list[i]=(student*)calloc(n,sizeof(student));
        fscanf(fptr,"%d %[^\n]s", &(list[i]->IDno),(list[i]->name));
    }

    return list;
}

void print_list(student**list,int *sizePtr){
    int i; 
    for(i=0; i<*sizePtr; i++){
        printf("%d %s\n",list[i]->IDno, list[i]->name);
    }
}

int find_binsrch(int idNo, student **list, int size, int low, int high)
{
    int middle;

    if (size) {}  /* stub to eliminate unused warning */

    while(low<=high){
        middle =(low+high)/2;

        printf("%d\n", middle); 

        if(idNo==list[middle]->IDno)
            return list[middle]->IDno;

        if(idNo<list[middle]->IDno)
            high = middle -1;
        else
            low = middle +1;
    }
    return -1;    
}

注意:它是否正确运行确实是一个不同的问题,这取决于您的数据和消除任何逻辑错误。

答案 1 :(得分:0)

在您的二进制搜索例程中,当您需要与idNo进行比较时,您的if list[middle]list[middle].idNo进行比较

您可以通过使用获取重新分配的1D数组而不是2D指针数组来简化一点。整个代码将更简单,您将不会失去任何功能。

<强>更新

我已经将代码切换为使用结构数组而不是指向结构的指针数组。它简化了事情,两级查找只是增加了可能使你绊倒的复杂性。此外,清理更多的风格 - 对此抱歉,但它是如何我能够看到足够的逻辑,以进行更改。

注意:我完全同意David [和许多其他人]关于编译器警告的内容。他们是你的朋友。他们通常会显示使用正在运行的程序难以找到的错误。我已经做了很多年的C,我[仍] 总是使用-Wall -Werror

如果您想了解更多有关结构,结构数组的指针,请参阅我最近的回答Issue implementing dynamic array of structures它介绍了在数组之间切换的各种方法,指向数组的指针,索引可能有用的指针等。

添加了一个完整的诊断套件,用于证明binsrch算法,包括在对实际/大数据进行松散之前可能不会出现给定数据集的边缘情况。一个很好的记忆技巧。

请注意,我不确定为什么你传递低/高作为参数,因为它们通常不用于二进制搜索。如果您想要特定的数据子集,它们将非常有用。如果是这样,请注释掉我的额外代码重置它们。

// 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;
}