C中的关系数据库,具有简单查询

时间:2015-03-27 14:55:14

标签: c relational-database

我正在尝试用C实现一个关系数据库。该程序提供了一个config_file.txt,其中包含数据库中关系的数量,后跟后续行中关系的名称。然后我为每个关系提供了一个InsertRelationNameHere.sch文件,其中包含元组的结构(第一行的属性数,后跟属性和它们包含的数据的格式)。另外,我提供了一个InsertRelationNameHere.dat文件,该文件是一个二进制文件,其中存储了每个关系中的实际信息。

到目前为止我有三个问题:

nattr InsertRelationNameHere - (打印出'InsertRelationNameHere'中的属性数量)

tuplen InsertRelationNameHere - (打印每个元组在.dat文件中占用的字节数,元组长度)

count InsertRelationNameHere - (打印每个关系中的元组数)

我遇到的问题是在计数查询中:

当我使用此查询时,我遇到了段错误,我不确定原因。

这是我的func.c,其中包含所有查询的代码:

#include "globals.h"

FILE* check;

void nattr(char * str){
    char* token;
    const char s[2] = ".";
    strcpy(tempstr2, str);
    strncat(tempstr2,".sch", 4); // appends '.sch' extension to the file name
    if((check =(FILE*)fopen(tempstr2, "r")) == NULL){  // opens "InsertFileNameHere.sch"
        printf("", token);
        strcpy(token, strtok(tempstr2, s));
        fprintf(stdout,"Error: Invalid relation -- %s\n", token);
    }else{
        fscanf(check, "%d", &numattr);
        fprintf(stdout, "%d\n",numattr);
    }

    fclose(check);
}

void tuplen(char * str){

    char* token;
    const char s[2] = ".";
    strcpy(tempstr2, str);
    strncat(tempstr2,".sch", 4); // appends '.sch' extension to the file name
    if((check =(FILE*)fopen(tempstr2, "r")) == NULL){  // opens "InsertFileNameHere.sch"

        printf("", token);
        strcpy(token, strtok(tempstr2, s));
        fprintf(stdout,"Error: Invalid relation -- %s\n", token);
    }else{
        sumattr = 0;
        dummy = 0;
        fscanf(check, "%d", &numattr); // reads first line, gets number of lines to read
        for(i = 0; i < numattr; i++){
            fscanf(check, "%s", tempstr3); // reads first string on line, does nothing with it
            fscanf(check, "%s", tempstr3); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            fscanf(check, "%d", &dummy); // reads the int in third position on line, this is the number of bytes of the attribute
            fgetc(check);   // moves past the '\n'
            sumattr += dummy; // adds the amount of bytes for each attribute to the total
        }
        fprintf(stdout, "%d\n", sumattr);
    }

    fclose(check);
}

void count(char * str){
    char* token;
    const char s[2] = ".";
    strcpy(tempstr2, str);
    nattr(tempstr2);// sets numattr to the number of attributes in file: tempstr2
    tuplen(tempstr2);
    puts("here");
    printf("%s %s", numattr, sumattr);
    strncat(tempstr2,".dat", 4); // appends '.sch' extension to the file name
    if((check =(FILE*)fopen(tempstr2, "rb")) == NULL){  // opens "InsertFileNameHere.sch"
        printf("", token);
        strcpy(token, strtok(tempstr2, s));
        fprintf(stdout,"Error: Invalid relation -- %s\n", token);
    }else{

        for(i = 0; i< numattr; i++){    // these fscanf functions are only called to move through
            fread(tempstr3, 1, sumattr, check);
            fprintf(stdout, "%d\n", i);
            if(feof(check)){
                break;
            }
        }
        fprintf(stdout, "%d\n", i);
    }
    fclose(check);
}

这是我的globals.h头文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 15
#define MAX_REL 10

FILE* files[MAX_REL*2];  // Array of FILES that are the '.sch' and '.dat' files for relations
char tempstr1[MAX_LEN+1], tempstr2[MAX_LEN+1], tempstr3[MAX_LEN], tempstr4[MAX_LEN], tempstr5[MAX_LEN], temp;
int num_rel, i, numattr, sumattr, dummy;
FILE* conf; // configure file

这里也是我的Prog.c文件,我的主要方法是:

#include "globals.h"

int nattr(char * str);
//void fileOpener(FILE * conf);

int main(int argc, char * argv[]) {
    // Error checks for correct arguments
    if( argc != 4){
        fprintf(stdout, "Check usage");exit(1);
    }
    if((conf = fopen(argv[2], "r")) == NULL){
        fprintf(stdout, "could not open file %s\n", argv[1]);exit(1);
    }
    if((quef = fopen(argv[3], "r")) == NULL){
            fprintf(stdout, "could not open file %s\n", argv[2]);exit(1);
    }
    //fileOpener(conf);
    scanf("%s", tempstr1);                  // maybe you could try a switch here, getting some funky input characteristics
    while(strcmp(tempstr1, "exit") != 0){
        if(strcmp(tempstr1, "exit") == 0){
            strcpy(tempstr2, tempstr1);
            strcpy(tempstr3, tempstr1);
            strcpy(tempstr4, tempstr1);
            strcpy(tempstr5, tempstr1);
            exit(1);
        }

            while(strcmp(tempstr1, "nattr") == 0){
                scanf("%s", tempstr2);
                strcpy(tempstr3, tempstr1);
                strcpy(tempstr4, tempstr1);
                strcpy(tempstr5, tempstr1);
                nattr(tempstr2);
                scanf("%s", tempstr1);
                if(strcmp(tempstr1, "exit") == 0){
                    exit(1);
                }if(strcmp(tempstr1, "tuplen") != 0){
                    break;
                }
            }
            while(strcmp(tempstr1, "tuplen") == 0){
                scanf("%s", tempstr2);
                strcpy(tempstr3, tempstr1);
                strcpy(tempstr4, tempstr1);
                strcpy(tempstr5, tempstr1);
                tuplen(tempstr2);
                scanf("%s", tempstr1);
                if(strcmp(tempstr1, "exit") == 0){
                    exit(1);
                }if(strcmp(tempstr1, "tuplen") != 0){
                    break;
                }
            }
            while(strcmp(tempstr1, "count") == 0){
                scanf("%s", tempstr2);
                strcpy(tempstr3, tempstr1);
                strcpy(tempstr4, tempstr1);
                strcpy(tempstr5, tempstr1);
                count(tempstr2);
                scanf("%s", tempstr1);
                if(strcmp(tempstr1, "exit") == 0){
                    exit(1);
                }if(strcmp(tempstr1, "tuplen") != 0){
                    break;
                }
            }
    }
    return 0;
}

以下是我们用来测试这些功能的文件 Student.sch:

5
Name   S  25
Major  S  4
Minor  S  4
Totcr  I  4
Majcr  I  4

Student.dat:

536d 6974 682c 526f 6265 7274 0000 0000
0000 0000 0000 0000 0050 5359 0043 5349
0000 0000 3900 0000 2757 6f6f 6473 2c4a
616e 6500 0000 0000 0000 0000 0000 0000
0000 4353 4900 4255 5300 0000 0061 0000
0044 5261 6d73 6579 2c45 6c61 696e 6500
0000 0000 0000 0000 0000 0042 5553 0050
5359 0000 0000 6b00 0000 5857 6861 7274
6f6e 2c54 6f6d 0000 0000 0000 0000 0000
0000 0000 4255 5300 5053 5900 0000 0075
0000 0062 4261 6b65 722c 4e6f 726d 6100
0000 0000 0000 0000 0000 0000 0042 494f
0043 5349 0000 0000 2700 0000 19

config_file.txt:

2
Students
Courses

query_file.txt :(此文件尚未使用,但代码才能正常运行)

nattr     Students
nattr     Norelation
tuplen    Badrelation
tuplen    Students  
infattr   Students  Minor
infattr   Students  Majorcr
infattr   Students  Totcr
infattr   Courses   Badattr
infattr   Courses   CName
infattr   Courses   Credits
count     Students
count     Student
count     Corses
count     Courses
project   Students     Name
project   courses      Credits
project   Students     Minor
project   Students     Majcredit
project   Courses      Credits
project   Courses      Instr
select    Students     Major !=  "BUS"
select    Students     Totcr   <   39
select    Courses      Credits  ==  3
select    Courses      Instr  ==  "KELLER"
select    Students     Name  >  40
select    Courses      Instr  ==  "Keller"
select    Courses      Credits  ==  "Keller"
select    Courses      Instructor  ==  "Keller"
quit

前两个查询的预期输出应如下所示:

gcc Prog3.c func.c globals.h   
./a.out Prog3.c config_file.txt query_file.txt
nattr Students
5
nattr Norelation
Error: Invalid relation -- Norelation
tuplen Students
41
tuplen Norelation
Error: Invalid relation -- Norelation

然后当使用“计算学生”时,我得到了一个段错误。

如果有任何帮助,只有当通过count函数调用“tuplen()”时,我的程序才会在tuplen函数strcpy(token, strtok(tempstr2, s));的行中进行段错误,但是当我自己使用tuplen查询时则不会。

我知道这是一个很长的问题,对不起!但我仍然试着尽量缩短它,同时还在解释自己。如果有什么不清楚请告诉我,我可以详细说明。任何帮助表示赞赏!谢谢!

1 个答案:

答案 0 :(得分:1)

问题在于count中的这些行。

nattr(tempstr2);// sets numattr to the number of attributes in file: tempstr2
tuplen(tempstr2);

您应该用

替换它
nattr(str);// sets numattr to the number of attributes in file: tempstr2
tuplen(str);

在调用nattr之后,缓冲区tempstr2包含&#34; Student.sch&#34;。当你用这个字符串调用tuplen时,它会附加.sch,它会产生&#34; Student.sch.sch&#34;。打开此文件失败,因为它不存在。 在这种情况下执行的代码是

printf("", token);
strcpy(token, strtok(tempstr2, s));
...

第一行什么也没做。由于token未初始化且包含一些随机值,strcpy会尝试将strtok的输出复制到此随机位置。这会导致分段错误。

您可以通过将str传递给nattrtuplen来避免此细分错误。但是在fopen失败的情况下执行的代码很糟糕,需要更改。使用全局变量也很糟糕。


摆脱全局变量。编程错误,容易出错。 使用结构,并传递指向它的指针。清楚说明哪个函数初始化结构,并且没有其他函数错误地覆盖其字段。

这是一个如何编写nattr()的示例。

// returns the nattr value of the given table or -1 if failed getting the value 
int nattr(char * str){
    char tmpstr[MAX_LEN+1+4];
    FILE * f;
    int numattr = -1;

    strcpy(tmpstr, str);
    strncat(tmpstr,".sch", 4); // appends '.sch' extension to the file name
    f = fopen(tmpstr, "r");  // opens "InsertFileNameHere.sch"
    if (f == NULL){ 
        printf("Error: Invalid relation -- %s\n", str);
        return -1;
    }

    // Try read numattr, leave it unchanged if fails. numattr is then -1
    if (fscanf(f, "%d", &numattr) != 1)
        return -1;
    printf("%d\n", numattr);
    fclose(f);
    return numattr;
}

由于我有更多时间,这里是tuplen

// Return the byte size of a tuple or -1 if failed 
int tuplen(char * str){
    char tmpstr[MAX_LEN+1+4];
    char attrName[MAX_LEN+1];
    char attrType[2];
    int numattr = -1, sumattr = 0, attrSize;
    FILE * f;

    strcpy(tmpstr, str);
    strncat(tmpstr,".sch", 4); // appends '.sch' extension to the file name
    f = fopen(tmpstr, "r");
    if (f == NULL){ 
        printf("Error: Invalid relation -- %s\n", str);
        return -1;
    }

    if (fscanf(f, "%d", &numattr) != 1)
        return -1;
    for (i = 0; i < numattr; i++){
        if (fscanf(f, " %s %1s %d", attrName, attrType, &attrSize) != 3)
            return -1; // try reading the three fields of one line
        sumattr += attrSize; // adds the amount of bytes for each attribute to the total
    }
    printf("%d\n", sumattr);
    fclose(f);
    return sumattr;
}