您的代码中有一个很大的网格,我将尝试对其进行解码,向您显示错误:
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#define MAX 10000
int elever = 1;
struct likaprogramms {
char civilekonom[50];
char högskoleingenjör[50];
char civilingenjör[50];
char systemutvecklare[50];
};
struct student {
char personnummer[32];
char förnamn[32];
char efternamn[32];
char gender[32];
char programmdife[32];
char age[32];
char email[32];
struct likaprogramms *likaprogramm;
};
struct student *personer;
struct programms {
char namnen;
char mcode;
char responsible;
char email;
};
void (*display[5])();
display 是一个由 5 个指向 void 函数的指针组成的数组,这些函数采用未确定数量的参数(一个不完整的类型定义,因为要存储的参数类型和函数数量未在定义中指定)这在 C 中维护是为了与旧代码兼容,但今天不推荐。虽然这不是错误,但我不明白您为什么要为数组设计如此复杂的声明。
void* base(char *display[5]) {
这里,display 是一个由 5 个指向 char 的指针组成的数组(或字符串,如果它们要被 '\0' 终止)问题是您已将 display 局部变量命名为与全局数组相同的名称(也有 5 个指向函数的指针)所以我现在只能说你以后会遇到麻烦。
//char fileA[MAX];
char tal;
int columns;
FILE *f;
f = fopen("elever.txt", "r");
personer = (struct student*) malloc(elever * sizeof(struct student));
personer->likaprogramm = malloc(sizeof(struct likaprogramms) * elever);
display = malloc(sizeof *display);
for (elever = 0; !feof(f);) {
feof(f) 仅在您尝试读取文件之后返回有效值,而不是在您检查之前。虽然这不是问题,但您将使用此for 循环将垃圾记录添加到数组中,因为只有当您已经尝试读取不完整的内容时它才会返回 EOF(但您已经将其添加到数据库中) )。
tal = fgetc(f);
您之前可以使用 while ((tal = fgetc(f)) != EOF) 代替(因为您正在逐个读取字符)。但是tal 必须声明为int(而不是char),因为EOF 是一个整数常量,它可以存储在char 变量中的任何可能的字符值之外。无论如何,您都可以在以下代码中对 int 变量进行操作,但这样一来,您就可以在处理任何无效数据之前检测文件结束条件。
if (tal == '\n')
printf("\n");
{
elever++;
columns = 0;
if (tal == ' ') {
columns++;
}
if (columns == 0) {
fscanf(f, " %s", &personer[elever].personnummer);
//printf("%s",personer[elever].personnummer);
// return (personer[elever].personnummer);
//columns++;
}
columns++;
if (columns == 1) {
fscanf(f, " %s", &personer[elever].förnamn);
// return (personer[elever].förnamn);
}
columns++;
if (columns == 2) {
fscanf(f, " %s", &personer[elever].efternamn);
//return (personer[elever].efternamn);
}
columns++;
if (columns == 3) {
fscanf(f, " %s", &personer[elever].gender);
// return( personer[elever].gender);
}
columns++;
if (columns == 4) {
fscanf(f, " %s ", &personer[elever].programmdife);
// return( personer[elever].programmdife);
}
columns++;
if (columns == 5) {
fscanf(f, " %s", &personer[elever].age);
// return(personer[elever].age);
}
columns++;
if (columns == 6) {
fscanf(f, " %s", &personer[elever].email);
// return(personer[elever].email);
}
return &personer[elever];
}
//free(personer);
}
// return 0;
//fclose("elever.txt");
}
int i;
int main() {
display[i] = base(*display[i]);
您为什么将分配给display[i] 的读者与未初始化的i 变量(全局为零)混淆,而不是说display[0] = base(*display[0]);
更重要的是,为什么要分配base() 的函数指针单元格结果,它应该是一个结构。对函数指针唯一能做的就是分配它并执行它指向的函数。但是您正在分配一个指向结构的指针(该信息隐藏在您已将其定义为返回 void * 的事实下,我不知道您从哪里了解到,但不值得在这里使用)如果您的功能是为数组动态分配内存,数组应该被定义为struct student * display[5];或更好的struct student **display;(因为内存分配的动态性质,你可以处理可变数量的结构数组。
FILE *h;
h = fopen("Filedatabase.txt", "w");
if (h == NULL) {
printf("Could not write the file!\n");
exit(1);
} else {
for (int i = 0; i < 7;) {
如果您已经为一个包含五个条目的数组编写了所有内容,为什么还要在这里增加七个?在代码中使用常量很重要,所以你永远不会因为这个错误而失败。
fprintf(h, "%s\n", display[i]);
printf("\n");
i++;
}
printf("open the file");
}
fclose(h);
free(display);
return 0;
}
如果你想学习返回一个完整的结构,有一个示例代码可以做我猜你想做的事情,返回一个结构并将其复制回作业中的正确位置(但没有malloc在这种情况下使用,因此,程序中没有动态内容,您将始终有 5 个学生的空间 --- 或常量的值 --- 并且已经为您分配了一个适当的 struct student 数组)这是一个比您的示例更简单的示例,基于您的代码来说明 C 函数中的结构返回(我认为在您的代码中会更容易理解和更好地使用):
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
/* the two macros below allow pretty printing of error,
* including the file and the line where the error
* was detected. */
#define F(_fmt) "%s:%d:"_fmt,__FILE__,__LINE__
#define ERR(_cod, _fmt, ...) do{ \
fprintf(stderr, F(_fmt),##__VA_ARGS__); \
if(_cod) \
exit(_cod); \
}while(0)
struct student {
char personnummer[32];
char förnamn[32];
char efternamn[32];
char gender[32];
char programmdife[32];
char age[32];
char email[32];
struct likaprogramms *likaprogramm; /* I don;t use this field in my code */
};
/* use a constant, so if you want to change it later,
* you need only to change it here. */
#define N_STUDENTS (5)
#define MAX_LINE 1000
/* static allocation done by the compiler */
struct student display[N_STUDENTS];
/* the function now reads a single student from the already
* open FILE descriptor f, and returns a struct student,
* filled with the read data, ready for assignment in the
* proper place. */
struct student base(FILE *f)
{
//char fileA[MAX];
int tal;
int columns;
/* use a local structure that will be copied back to
* the proper place in the return statement */
struct student return_value = {0};
char line[MAX_LINE];
char *p = fgets(line, sizeof line, f);
if (!p) { /* EOF */
return return_value; /* return it as it is to
* indicate nothing was
* returned */
}
/* process the fields */
p = strtok(p, " \t\n");
if (!p) { /* no more fields */
return return_value; /* same as above */
}
strncpy(return_value.personnummer, p,
sizeof return_value.personnummer);
p = strtok(NULL, " \t\n"); /* next field */
if (!p) { /* no more fields */
return return_value; /* same as above */
}
strncpy(return_value.förnamn, p,
sizeof return_value.förnamn);
p = strtok(NULL, " \t\n"); /* next field */
if (!p) { /* no more fields */
return return_value; /* same as above */
}
strncpy(return_value.efternamn, p,
sizeof return_value.efternamn);
p = strtok(NULL, " \t\n"); /* next field */
if (!p) { /* no more fields */
return return_value; /* same as above */
}
strncpy(return_value.gender, p,
sizeof return_value.gender);
p = strtok(NULL, " \t\n"); /* next field */
if (!p) { /* no more fields */
return return_value; /* same as above */
}
strncpy(return_value.programmdife, p,
sizeof return_value.programmdife);
p = strtok(NULL, " \t\n"); /* next field */
if (!p) { /* no more fields */
return return_value; /* same as above */
}
strncpy(return_value.age, p,
sizeof return_value.age);
p = strtok(NULL, " \t\n"); /* next field */
if (!p) { /* no more fields */
return return_value; /* same as above */
}
strncpy(return_value.email, p,
sizeof return_value.email);
/* the full reading process for each field could have
* been condensed in a macro call for each field, as it
* is done in the macro definition below to print entries.
* I preferred to shorten one and not the other to show
* the better readability of the macro code. */
return return_value;
}
void print_entry(struct student *entry, FILE *out)
{
/* print the result for field _fn of entry variable */
#define PR(_fn) fprintf(out, #_fn ": %s\n", entry->_fn)
PR(personnummer);
PR(förnamn);
PR(efternamn);
PR(gender);
PR(programmdife);
PR(age);
PR(email);
#undef PR /* not needed anymore */
}
int main()
{
int i;
char *students_filename = "elever.txt";
FILE *in = fopen(students_filename, "r");
if (!in) {
ERR(1, "Cannot open %s: %s (errno = %d)\n",
students_filename, strerror(errno), errno);
/* NOTREACHED */
}
for (i = 0; i < N_STUDENTS; i++) {
display[i] = base(in); /* assign to display[i] the read
* data from next student in in
* FILE descriptor */
}
fclose(in); /* close file */
char *database_filename = "Filedatabase.txt";
FILE *out = fopen(database_filename, "w");
if (!out) {
ERR(1, "Cannot create %s: %s (errno = %d)\n",
database_filename, strerror(errno), errno);
/* NOTREACHED */
}
for (i = 0; i < N_STUDENTS; i++) {
print_entry(&display[i], out); /* we pass it by
* reference to
* minimice copying
*/
}
fclose(out); /* again, flush buffer and close file */
return 0;
}