Могу ли я выделить указатель на символ с собственной памятью? - PullRequest
1 голос
/ 30 марта 2019

Я во втором семестре моего колледжа, поэтому я только начал программировать. Недавно мы узнали кое-что о бинарных деревьях. Поэтому я просто хотел написать свои собственные. Я решил закодировать двоичный список контактов в дереве.

Сначала я сохраняю свою структуру в файл .txt. (Я хочу, чтобы он был в текстовом файле, а не в двоичном, потому что тогда я смогу прочитать его после программы.) После этого я пытаюсь снова загрузить его в узел, чтобы перестроить мое двоичное дерево.

Здесь мы идем с сокращенной версией. Я прокомментировал важные части.

#define CLEN 100

struct binarytree {
    struct binarytree *left;
    struct binarytree *right;
    char *firstname;
    char *lastname;
    char *city;
    char *street;
    char *addr;
    char *tel;
} typedef btree;

//-----------------------------------------

btree *creatnullnode(void);
btree *loadtree(char *filename);

//-----------------------------------------

btree *creatnullnode(void) {
    btree *node = malloc(sizeof(btree));
    node->left  = NULL;
    node->right = NULL;

    //TODO: the memmory is not right allocated..
    node->firstname = (char*)malloc(CLEN * sizeof(char));
    node->lastname  = (char*)malloc(CLEN * sizeof(char));
    node->city      = (char*)malloc(CLEN * sizeof(char)); 
    node->street    = (char*)malloc(CLEN * sizeof(char));
    node->addr      = (char*)malloc(CLEN * sizeof(char));
    node->tel       = (char*)malloc(CLEN * sizeof(char));
    return node;
}

btree *loadtree(char *filename) {
    FILE *fp;
    btree *tree = NULL;
    btree *node = creatnullnode();
    char ch = "";
    int lines = 0;

    fp = fopen(filename,"r");
    if (!fp) {
        printf("Error. no file\n");
        return NULL;
    } else {
        while (!feof(fp)) {
            ch = fgetc(fp);
            if (ch == '\n')
                lines++;
        }
        fseek(fp, 0,(int)lines % 2);

        //TODO: right here the memory of every char can't be read anymore
        fscanf(fp, "%s\t\t%s\t\t\t%s\t%s\t\t%s\t\t%s\n",
               &node->firstname, &node->lastname, &node->addr, &node->city, 
               &node->street, &node->tel);

        tree = insertnode(tree, node);

        fseek(fp, 0, 0);
        //rekursiveload(&tree, fp);      //TODO: - ausprogrammieren -
    }

    fclose(fp);
    return tree;
}

Во время отладки я увидел, что память не была правильно распределена. Но я не знаю, как это исправить.

после выделения char [] устанавливается в: node->firstname = 0x007db250 "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýýM¸Þµ¦æ" Отладчик говорит: <Error reading the characters of the string.> после fscanf

1 Ответ

2 голосов
/ 30 марта 2019

В вашем коде есть несколько проблем:

  • while (!feof(fp)) всегда неверно для проверки конца файла: Почему «while (! Feof (file))» всегда неверно? Вместо этого вы должны написать это:

        while ((ch = fgetc(fp)) != EOF) {
            ...
    
  • вы должны создать новый узел для каждой строки, которую вы читаете из файла. В настоящее время вы используете одну и ту же память для каждого узла и перезаписываете поля новыми данными. insertnode, отсутствующий во фрагменте кода, скорее всего создает цикл в списке, вызывая неопределенное поведение при попытке освободить его.

  • char ch = ""; неверно: "" является строкой, а не char, и ch должен быть определен как int для чтения байтов с fgetc() и сохранения EOF тоже .

  • fseek(fp, 0,(int)lines % 2); не имеет смысла. Чего ты пытаешься достичь? вы можете попытаться перемотать поток с помощью rewind(fp) или fseek(fp, 0L, SEEK_SET), но вы сможете прочитать только одну строку.

  • fscanf(fp, "%s\t\t%s\t\t\t%s\t%s\t\t%s\t\t%s\n", &node->firstname, ... имеет несколько проблем: вы не можете предотвратить неправильный ввод, приводящий к тому, что слишком много символов будет храниться в массивах назначения, и вы должны передавать указатели на массивы назначения, а не адреса указателей. Другими словами, код должен быть:

        char eol;
        if (fscanf(fp, "%99s%99s%99s%99s%99s%99s%c",
            node->firstname, node->lastname, node->addr, 
            node->city, node->street, node->tel, &eol) != 7 || eol != '\n') {
            /* invalid input... */
        }
    

    Гораздо более безопасный подход для чтения этого ввода - прочитать одну строку в больший массив char и использовать sscanf() для разбора этой строки в полях узла ... но, глядя на строку формата, кажется, вы имеете дело с разделенными табуляцией значениями и

  • Ни fscanf(), ни sscanf(), ни даже strtok() не могут правильно анализировать значения, разделенные TAB, из текстового файла. Вам нужно написать собственный код для этого. Я предлагаю вам использовать strcspn() для вычисления длин полей и strndup() для выделения строк из диапазона в массиве char.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...