Как сохранить динамическую строку в структуре **, содержащей указатель char * - PullRequest
0 голосов
/ 13 ноября 2018

В настоящее время я работаю над проблемой сохранения данных из входного файла в структуру следующего формата:

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] = '\0';

Однако я получаю ошибку сегмента, которая, как я предполагаю, связана с тем, как я пытаюсь сохранить "ch" при написании "Sch [i] .name [j]". Я также пробовал Sch [i] - > Имя [j] так и не удалось. Я был бы признателен за любую помощь, зная правильный способ написать адрес для хранения данных?

Я вызываю функцию, используя: input_schools (school_info, ТОП100, school_size); где информация о школе является входным файлом Школа * TOP100 [school_size]; это топ100 и school_size - количество строк в файле

Ответы [ 2 ]

0 голосов
/ 14 ноября 2018

Вы можете использовать что-то вроде этого, чтобы прочитать одну запись школы из 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 
    }               
}
0 голосов
/ 13 ноября 2018

Ваш файл очень похож по форме на CSV.Посмотрите, можете ли вы использовать любые библиотеки синтаксического анализа csv или code .

Вместо проверки каждого символа, прочитайте целую строку в буфер и используйте strtok.strtok - это функция, используемая для разделения строки разделителем.',' в вашем случае.

#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 %s\n", getfield(tmp1, 1));
        printf("State is %s\n", 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...