我目前正在处理一个问题,将输入文件中的数据存储到以下格式的结构中:
typedef struct school_{
char *name;
char *state;
}School;
我正在读取以下格式的输入文件:
name1, state1
name2, state2
我想通过指针将每个学校的数据动态存储在一个结构中,因为名称的长度是未知的k是文件中的行数到目前为止,这就是我所拥有的:
void input_schools(FILE *IN, School **Sch, int k) {
int i, j;
char ch;
for (i=0; i<k; i++)
{ fscanf(IN, "%c", &ch);
Sch[i].name = (char *)malloc(sizeof (char));
j = 0;
Sch[i].name[j] = ch;
while(ch != '-') {
fscanf(IN, "%c", &ch);
j++;
Sch[i].name = (char *) realloc(Sch[i].name, sizeof(char)*(j+1));
Sch[i].name[j] = ch;
}
}
Sch[i].name[j-1] = ' ';
然而,我收到了一个seg错误,我认为这是因为我在写"Sch[I].name[j]"时试图存储"ch"的方式。我也尝试过Sch[I]->name[j],但没有成功。如果您能帮助我了解写入地址以存储数据的正确方式,我将不胜感激?
我调用函数时使用:input_schools(school_info、TOP100、school_size(;其中学校信息是输入文件学校*TOP100[School_size];是前100名school_size是文件中的行数
您的文件在形状上与csv非常相似。查看是否可以使用任何csv解析库或代码。
不检查每个字符,而是将整行读取到缓冲区并使用strtok。strtok是一个用于通过分隔符分隔字符串的函数。a在你的情况下是","。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE* stream = fopen("in.md", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp1 = strdup(line);
char* tmp2 = strdup(line);
printf("Name is %sn", getfield(tmp1, 1));
printf("State is %sn", getfield(tmp2, 2));
// NOTE strtok changes the string. Hence two vars. You can try duplicating in the function instead.
// Note that I'm freeing the data. copying with strdup instead of directly assigning may be wise.
free(tmp1);
free(tmp2);
}
}
你可以用这样的东西从你提供的FILE*
中读取一个学校条目:
bool School_read(School* s, FILE* in) {
int scan = fscanf(in, " %m[^,n], %m[^n]", &s->name, &s->state);
// the fscanf format string:
// <space> = skip leading whitespaces (like a newline from the line before)
// %m[^,n] = read a string until, but not including, "," or "n" m = allocate space for it
// , = expect a comma and discard it
// %m[^n] = read a string until, but not including, "n" and allocate space for it
// just a debug print
fprintf(stderr, " -- got %d hits, >%s< >%s<n", scan, s->name, s->state);
if(scan<2) {
// not a complete scan, failure
if(scan==1) {
// apparently, we got one match, free it
free(s->name);
s->name = NULL;
}
return false;
}
return true;
}
不过,我不知道对为字符串动态分配内存的"m"修饰符的支持有多广泛。最近的gcc和clang编译器无论如何都支持它。
你也可以制作创建和摧毁学校的功能:
School* School_create() {
School* s = malloc(sizeof(School));
if(s!=NULL) {
s->name = NULL;
s->state = NULL;
}
return s;
}
void School_destroy(School** sp) {
if(sp) {
School* s = *sp;
if(s) {
if(s->state) free(s->state);
if(s->name) free(s->name);
free(s);
}
*sp = NULL;
}
}
并将它们全部组合起来:
School* School_create_and_read(FILE* in) {
School* s = School_create();
if(s) {
if(School_read(s, in)==false) {
School_destroy(&s);
}
}
return s;
}
因此,在填充学校阵列的函数中:
void input_schools(FILE* IN, School** Sch, int k) {
School* s;
while( (s=School_create_and_read(IN)) ) {
// s is a valid School pointer
// store it in your array
}
}