我正在尝试建立一个数据库,其中包含一些关于团队的数据。问题是我无法通过记录读取输入的数据记录。我想用一个例子来解释它:
insert manunited,manchester,old_trafford,1878,black-rd to teams
insert chelsea,london,stamford_bridge,1905,blue-whte to teams
select colors,team_name,founding_date from teams
在屏幕上选择指定信息,即颜色,体育场等。
insert现在接受团队信息。因此,根据select命令,应该遵循输出:
black-rd manunited 1878
blue-whte chelsea 1905
但是,我得到了
black-rd manunited 1878 blue-whte
我一直试图分析我的错误几个小时。我找不到错误和错误。 谢谢你们所有赞赏的答案。顺便说一句,我还没有maden while循环插入或选择命令。我正在考虑找出错误。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char team_name[TEAM_NAME];
char city[TEAM_NAME];
char stadium[STADIUM_NAME];
int founding_date;
char colors[COLOR];
}teams;
int main()
{
char read_command[12];
/* checking insert */
char str1[100],str2[5],str3[18];
FILE *fptr;
teams t;
scanf("%s", read_command);
if(strcmp(read_command,"insert") == 0)
{
scanf("%s %s %s", str1, str2, str3);
//printf("%s\n%s\n%s",str1,str2,str3);
insertfunc(fptr,str1, str2, str3);
}
if(strcmp(read_command,"select") == 0)
{
scanf("%s %s %s", str1, str2, str3);
selectfunc(fptr,str1, str2, str3);
}
return 0;
}
void selectfunc(FILE *fptr,char *str1,char *str2,char *str3)
{
char *buff;
buff = (char*) malloc(strlen(str1) + 1);
strcpy(buff,str1);
char *token;
const char comma[2] = ",";
if(strcmp(str3,"teams") == 0)
{
teams t;
fptr = fopen("teams.bin","rb");
if( fptr == NULL )
{
perror("File cannot be opened.");
exit(1);
}
else
{
while(fread(&t,sizeof(teams),1,fptr) == 1)
{
/* get the first token */
token = strtok(buff, comma);
while( token != NULL )
{
if(strcmp(token,"team_name") == 0)
{
printf(" %s ",t.team_name);
}
else if(strcmp(token,"city") == 0)
{
printf(" %s ",t.city);
}
else if(strcmp(token,"stadium") == 0)
{
printf(" %s ",t.stadium);
}
else if(strcmp(token,"colors") == 0)
{
printf(" %s ",t.colors);
}
else
{
printf(" %d ",t.founding_date);
}
token = strtok(NULL, comma);
}
}
}
fclose(fptr);
}
}
void insertfunc(FILE *fptr,char *str1,char *str2,char *str3)
{
char *buff;
buff = (char*) malloc(strlen(str1) + 1);
strcpy(buff,str1);
const char comma[2] = ",";
/*
if(buff == NULL)
perror("error");
*/
if(strcmp(str3,"teams") == 0)
{
teams t;
int date;
strcpy(t.team_name,strtok(buff, comma));
strcpy(t.city, strtok(NULL, comma));
strcpy(t.stadium, strtok(NULL, comma));
date = atoi(strtok(NULL, comma));
t.founding_date = date;
strcpy(t.colors, strtok(NULL, comma));
fptr = fopen("teams.bin","ab+");
if( fptr == NULL )
{
perror("File cannot be opened.");
exit(1);
}
else
{
fwrite(&t,sizeof(teams),1,fptr);
fclose(fptr);
}
}
free(buff);
}
答案 0 :(得分:2)
下面的工作代码。
除了进行构建所需的更改(主要是定义结构字段的大小)之外,dump_teams()
函数用于记录团队记录中的信息,err_exit()
函数简洁地报告错误。您的错误检查未更改。我对perror()
的主要反对意见是,您通常无法获取关键信息,例如未报告的文件名。升级err_exit()
以报告系统错误以及有意义的消息(例如failed to open file "teams.bin": No such file or directory
) - 为OP进行练习并不困难。这些功能用于验证信息,并确保检测到意外拼写。请注意,调试中的字段值用双尖括号<<…info…>>
括起来;这样可以更容易地发现各种问题,例如前导或尾随空格,或输入数据中的'\r'
个字符。 assert()
确保str2
用于两个主要功能。选择数据格式化更加统一。有一个名称data_file
来保存数据文件名。
关键错误修复位于selectfunc()
循环中,其中str1
的值会重新复制到buff
每条记录。
这是一种懒惰的工作方式;最好先预先分析字符串,然后使用预分析生成的数据结构迭代数据记录。如果有数百万条记录,那么这比仅有2条记录更重要。
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { TEAM_NAME = 20, STADIUM_NAME = 20, COLOR = 20 };
static const char data_file[] = "teams.bin";
typedef struct
{
char team_name[TEAM_NAME];
char city[TEAM_NAME];
char stadium[STADIUM_NAME];
int founding_date;
char colors[COLOR];
} teams;
void insertfunc(char *str1, char *str2, char *str3);
void selectfunc(char *str1, char *str2, char *str3);
void err_exit(const char *fmt, ...);
void dump_teams(FILE *fp, const char *tag, const teams *team);
int main(void)
{
char read_command[12];
char str1[100], str2[5], str3[18];
if (scanf("%s", read_command) != 1)
err_exit("read for command failed");
else if (strcmp(read_command, "insert") == 0)
{
if (scanf("%99s %4s %17s", str1, str2, str3) != 3)
err_exit("read for insert failed");
insertfunc(str1, str2, str3);
}
else if (strcmp(read_command, "select") == 0)
{
if (scanf("%99s %4s %17s", str1, str2, str3) != 3)
err_exit("read for select failed");
selectfunc(str1, str2, str3);
}
else
err_exit("Unrecognized command <<%s>>", read_command);
return 0;
}
void selectfunc(char *str1, char *str2, char *str3)
{
FILE *fptr;
char *buff;
buff = (char*) malloc(strlen(str1) + 1);
char *token;
fprintf(stderr, "select: <<%s>> <<%s> <<%s>>\n", str1, str2, str3);
assert(strcmp(str2, "from") == 0);
const char comma[2] = ",";
if (strcmp(str3, "teams") == 0)
{
teams t;
fptr = fopen(data_file, "rb");
if (fptr == NULL)
{
perror("File cannot be opened.");
exit(1);
}
else
{
while (fread(&t, sizeof(teams), 1, fptr) == 1)
{
dump_teams(stderr, "select", &t);
strcpy(buff, str1);
/* get the first token from command str1 */
token = strtok(buff, comma);
while (token != NULL)
{
fprintf(stderr, "token = <<%s>>\n", token);
if (strcmp(token, "team_name") == 0)
{
printf(" %-20s", t.team_name);
}
else if (strcmp(token, "city") == 0)
{
printf(" %-20s", t.city);
}
else if (strcmp(token, "stadium") == 0)
{
printf(" %-20s", t.stadium);
}
else if (strcmp(token, "colors") == 0)
{
printf(" %-20s", t.colors);
}
else if (strcmp(token, "founding_date") == 0)
{
printf(" %d", t.founding_date);
}
else
err_exit("Unrecognized field name <<%s>>", token);
token = strtok(NULL, comma);
}
putchar('\n');
}
}
fclose(fptr);
}
else
err_exit("Unrecognized data source <<%s>>", str3);
}
void insertfunc(char *str1, char *str2, char *str3)
{
FILE *fptr;
char *buff;
buff = (char*) malloc(strlen(str1) + 1);
strcpy(buff, str1);
fprintf(stderr, "select: <<%s>> <<%s> <<%s>>\n", str1, str2, str3);
assert(strcmp(str2, "to") == 0);
const char comma[2] = ",";
if (strcmp(str3, "teams") == 0)
{
teams t;
int date;
strcpy(t.team_name, strtok(buff, comma));
strcpy(t.city, strtok(NULL, comma));
strcpy(t.stadium, strtok(NULL, comma));
date = atoi(strtok(NULL, comma));
t.founding_date = date;
strcpy(t.colors, strtok(NULL, comma));
dump_teams(stderr, "insert", &t);
fptr = fopen(data_file, "ab+");
if (fptr == NULL)
{
perror("File cannot be opened.");
exit(1);
}
else
{
if (fwrite(&t, sizeof(teams), 1, fptr) != 1)
err_exit("fwrite failed");
fclose(fptr);
}
}
else
err_exit("Unrecognized data destination <<%s>>", str3);
free(buff);
}
void dump_teams(FILE *fp, const char *tag, const teams *team)
{
assert(fp != 0 && tag != 0 && team != 0);
fprintf(fp, "%s\n", tag);
fprintf(fp, "%8s: <<%s>>\n", "Team", team->team_name);
fprintf(fp, "%8s: <<%s>>\n", "City", team->city);
fprintf(fp, "%8s: <<%s>>\n", "Stadium", team->stadium);
fprintf(fp, "%8s: <<%d>>\n", "Founded", team->founding_date);
fprintf(fp, "%8s: <<%s>>\n", "Colours", team->colors);
fflush(fp);
}
#include <stdarg.h>
void err_exit(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
putc('\n', stderr);
exit(EXIT_FAILURE);
}
文件cmd1
,cmd2
和cmd3
包含问题中的三个命令行。
$ ./rw < cmd1
select: <<manunited,manchester,old_trafford,1878,black-red>> <<to> <<teams>>
insert
Team: <<manunited>>
City: <<manchester>>
Stadium: <<old_trafford>>
Founded: <<1878>>
Colours: <<black-red>>
$ ./rw < cmd2
select: <<chelsea,london,stamford_bridge,1905,blue-white>> <<to> <<teams>>
insert
Team: <<chelsea>>
City: <<london>>
Stadium: <<stamford_bridge>>
Founded: <<1905>>
Colours: <<blue-white>>
$ ./rw < cmd3
select: <<colors,team_name,founding_date>> <<from> <<teams>>
select
Team: <<manunited>>
City: <<manchester>>
Stadium: <<old_trafford>>
Founded: <<1878>>
Colours: <<black-red>>
token = <<colors>>
token = <<team_name>>
token = <<founding_date>>
black-red manunited 1878
select
Team: <<chelsea>>
City: <<london>>
Stadium: <<stamford_bridge>>
Founded: <<1905>>
Colours: <<blue-white>>
token = <<colors>>
token = <<team_name>>
token = <<founding_date>>
blue-white chelsea 1905
$ ./rw < cmd3 2>/dev/null
black-red manunited 1878
blue-white chelsea 1905
$
请注意,通过将调试信息放在标准错误上,很容易将调试信息与正常输出分开,就像上次运行一样。