我正在尝试用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查询时则不会。
我知道这是一个很长的问题,对不起!但我仍然试着尽量缩短它,同时还在解释自己。如果有什么不清楚请告诉我,我可以详细说明。任何帮助表示赞赏!谢谢!
答案 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
传递给nattr
和tuplen
来避免此细分错误。但是在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;
}