Не могу найти ошибку в манипуляциях со строками / указателями - PullRequest
3 голосов
/ 03 декабря 2010

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

Основой кода является то, что это адрес/ баланс 'книга.У меня есть структура с моими переменными, но по какой-то причине мой двусвязный список запутался, и я не могу понять, как.С немного причудливой (не совсем) отладкой я понял, что думаю fgets (string, 200, file);строка как-то перезаписывает мой указатель head-> name, что, кажется, отбрасывает остальную часть кода.Соответствующие фрагменты кода здесь:

Заполнение списка:

void populate_list(char* filename){
    FILE *file = NULL;
    char* name = NULL;
    char* streetaddress = NULL;
    char* city = NULL;
    char* state = NULL;
    char line[200];
    int zip;
    float balance;

    file = fopen(filename,"r");

    if(file==NULL){
        printf("Invalid input file\n");
        exit(1);
    }
    if(file == 0){
        printf("Invalid file.\n");
        exit(1);
    }

    while(!feof(file)){

        fgets(line, 200, file);

        name = strtok(line, ",");
        streetaddress = strtok(NULL, ",");
        city = strtok(NULL,",");
        state = strtok(NULL,",");
        zip = atoi(strtok(NULL,","));
        balance = atof(strtok(NULL,","));

        strip_spaces(name);
        strip_spaces(streetaddress);
        strip_spaces(city);
        strip_spaces(state);

        add_node(name, streetaddress, city, state, zip, balance);

    }

    fclose(file);
    return;
}

Затем код add_node:

void add_node(char* name, char* streetaddress, char* city, char* state, int zip, float, balance){
    struct customer* addnode = NULL;

    if(find_duplicate(name)){
        print_filler(1);
        printf("DUPLICATE RECORD: %s\n", name);
        return;
    } else {
        addnode = (struct customer *) malloc(sizeof(struct customer));
        addnode->name = name;
        addnode->streetaddress = streetaddress;
        addnode->city = city;
        addnode->state = state;
        addnode->zip = zip;
        addnode->balance = balance;

        if(head == NULL) {
            head = addnode;
            addnode->prev = NULL;
        } else {
            tail->next = addnode;
            addnode->prev = tail;
        }

        tail = addnode;
        addnode->next = NULL;
    }

    print_list();
    return;
}

Кажется, что ошибка возникает после того, как add_node в первый разВызывается и происходит, когда fgets () отключается во второй раз.По какой-то причине он перезаписывает head-> name всей строкой fgets ().

Есть и другие случайные раздражающие ошибки, которые я еще не зафиксировал, но эта, я думаю, может быть источником других.

Полный код здесь, если он помогает: http://pastebin.com/k0pqyvT0

Я думаю, что это связано с тем, что указатель head-> name перезаписывается fgets (), но я не могуесли бы я понял, что именно делает это, любая помощь / совет будут оценены.

Редактировать: Решением было реализовать strdup () и продублировать строки, когда они передаются в add_node ().Спасибо за все ответы.

Ответы [ 4 ]

2 голосов
/ 03 декабря 2010
  1. Переменная «строка» является указателем на ничто.Вам нужно фактически выделить буфер, в который вы читаете данные.
  2. strtok возвращает указатель на исходную строку, которая затем изменяется.Вам нужно выделить новый буфер и скопировать строку в него, если вы хотите сохранить его в своей структуре клиента.
1 голос
/ 03 декабря 2010

Основная проблема заключается в том, что вы назначаете элементы узла, которые вы выделяете, для указания на буфер line, и этот буфер перезаписывается каждый раз, когда вы вызываете fgets() для его заполнения. Таким образом, указатели в каждом узле всегда указывают на один и тот же буфер (который находится в стеке).

Решение (как упоминалось в других ответах) заключается в использовании strdup() для выделения отдельной копии каждой строки, которую вы сохраняете для каждого члена узла. Так что-то вроде этого будет работать:

....
} else {
    addnode = (struct customer *) malloc(sizeof(struct customer));
    addnode->name = strdup(name);
    addnode->streetaddress = strdup(streetaddress);
    addnode->city = strdup(city);
    addnode->state = strdup(state);
    addnode->zip = strdup(zip);
    addnode->balance = strdup(balance);
    ...
}

Хорошей идеей также является обнуление содержимого узла сразу после его выделения, чтобы вы не попали в мусор:

   addnode = (struct customer *) malloc(sizeof(struct customer));
   memset(addnode, '\0', sizeof(struct customer));
1 голос
/ 03 декабря 2010

Я не знаю, связано ли это, но ваш указатель struct customer* addnode = NULL; является локальным внутри add_node (), он не будет сохранен (т. Е. Каждый раз, когда функция завершается, он уничтожается). Также будьте осторожны при использовании указателя на символ, он может казаться интуитивно понятным как строка, но есть ошибка,

Так что, если вы делаете такие вещи, как:

while(!feof(file)) {

   name = strtoke(string, ",");
   // etc

   add_node(name, ... //etc);
}

, поскольку вы копируете только ссылку, т. Е. addnode->name = name, чтение следующей строки заменит содержимое того же указателя , использованного в качестве предыдущей записи, поэтому у вас будет список с такими же свойствами.

0 голосов
/ 03 декабря 2010

Как указывает Dark Falcon , ваш код * add_node * неверен.Вместо этого вам нужно сделать что-то вроде этого:

  void add_node(char* name, char* streetaddress, char* city, char* state, int zip, float balance){
    struct customer* addnode = NULL;

    strip_spaces(name);
    strip_spaces(streetaddress);
    strip_spaces(city);
    strip_spaces(state);

    if(find_duplicate(name)){
        print_filler(1);
        printf("DUPLICATE RECORD: %s\n", name);
        return;
    } else {
        addnode = (struct customer *) malloc(sizeof(struct customer));
        addnode->name = name;
        addnode->streetaddress = streetaddress;
        addnode->city = city;
        addnode->state = state;
        addnode->zip = zip;
        addnode->balance = balance;

        if(head == NULL) {
            head = addnode;
            addnode->prev = NULL;
        } else {
            tail->next = addnode;
            addnode->prev = tail;
        }

        tail = addnode;
        addnode->next = NULL;
    }

    print_list();
    return;
  }

и затем назвать это так:

    add_node(strdup(name), strdup(streetaddress), strdup(city), strdup(state), zip, balance);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...