c-如何将动态字符串存储在包含char*指针的结构体**中



我目前正在处理一个问题,将输入文件中的数据存储到以下格式的结构中:

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 
    }               
}

最新更新