проблема, когда я пытаюсь добавить структуру в другую структуру и использовать свободную функцию - PullRequest
0 голосов
/ 05 ноября 2010

Я создал функцию в C под названием 'remover', которая используется для удаления структуры массива 'lista'. Эта функция изменяет размер списка. Проблема в том, что я пытался напечатать элементы «lista», но он печатает странные вещи. Когда я не освобождаю lista_aux, программа работает нормально. Почему это происходит?

typedef struct localidade{
    char nome[31];
    float local[3];
}Localidade;

Localidade** remover(Localidade** lista, char end_remover[], int posicao){
    int i, j;
    int pos_remover;
    char nome_aux[31];
    Localidade** lista_aux;
    lista_aux = (Localidade**) malloc((posicao) * sizeof(Localidade*));
    if( lista_aux == NULL){
        printf("Erro na alocacao de memoria!\n");
        exit(-1);
    }
    for( i = 0; i < posicao; i++){
        lista_aux[i] = (Localidade*) malloc(sizeof(Localidade));
        if( lista_aux[i] == NULL){
        printf("Erro na alocacao de memoria!\n");
        exit(-1);
        }
    }
    for( i = 0; end_remover[i]; i++ ){
        end_remover[i] = toupper( end_remover[i] );
    }
    for( i = 1; i < posicao; i++){
        strcpy( nome_aux, lista[i]->nome);
        for( j = 0; nome_aux[j]; j++){
            nome_aux[j] = toupper( nome_aux[j] );
        }
        if( !(strcmp( end_remover, nome_aux)) ){
            pos_remover = i;
            break;
        }
        else if( i == posicao ){
            printf("Endereco nao cadastrado.\n");
        }
    }
    for( i = 0; i < posicao; i++){
        if( i < pos_remover ){
            lista_aux[i] = lista[i];
        }
        else{
            lista_aux[i] = lista[i + 1];
        }
        //printf("***%s\n", lista_aux[i]->nome);
    }
    lista = (Localidade**) realloc( lista, (posicao)*sizeof(Localidade*));
    lista = lista_aux;
    //printf("*****%s\n", lista[1]->nome);
    /*for( i = 0; i < posicao; i++ ){
        printf("***%s\n", lista[i]->nome);
    }
    for( i = 0; i < posicao; i++ ){
        printf("*****%s\n", lista_aux[i]->nome);
    }*/
    /*for( i = 0; i < posicao; i++){
        free( lista_aux[i] );
    }
    free( lista_aux );*/

    return lista;
}

Ответы [ 2 ]

1 голос
/ 05 ноября 2010

Если вы освободите lista_aux, ваш код будет возвращать недопустимый (освобожденный) указатель на вызывающую функцию из-за этой строки:

lista = lista_aux;

В вашем коде есть другие проблемы (в зависимости от того, как вы его называете, для начала у вас может быть утечка памяти), и я бы посоветовал вам пересмотреть свой алгоритм удаления записи из "lista". Одним из предложений было бы иметь известный размер списка (или список, заканчивающийся NULL), и использовать memmove () вместо того, чтобы вручную копировать вещи вокруг.

1 голос
/ 05 ноября 2010

Ваша проблема (ну, одна из них), кажется, лежит здесь:

lista = (Localidade**) realloc( lista, (posicao)*sizeof(Localidade*));
lista = lista_aux;

Это не копирует все в lista_aux в lista, это просто изменяетlista указатель на указатель на данные lista_aux (перезаписывает память, которую вы только что перераспределили).

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

free (lista);
lista = lista_aux;

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

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

Я также изменил его, чтобы он также возвращал вам новый размер.Вот полная программа, набор тестов и все:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct localidade {
    char nome[31];
    float local[3];
} Localidade;

static void dump ( int sz, Localidade **lista) {
    int i;

    printf ("Size = %d\n", sz);
    for (i = 0; i < sz; i++)
        printf ("   [%s]\n", lista[i]->nome);

}

Localidade **remover (
    Localidade **lista,
    char end_remover[],
    int posicao,
    int *new_posicao)
{
    int sidx, didx;

    // Maintain separate source and destination indexes.

    sidx = didx = 0;
    while (sidx < posicao) {
        // If need to remove, just increment source after freeing.

        if (stricmp (end_remover, lista[sidx]->nome) == 0) {
            free (lista[sidx]);
            lista[sidx++] = NULL;
            continue;
        }

        // Otherwise transfer and increment both indexes.

        lista[didx++] = lista[sidx++];
    }

    *new_posicao = didx;
    if (sidx != didx)
        lista = realloc (lista, (*new_posicao) * sizeof(Localidade*));
    return lista;
}

int main (void) {
    int sz;

    Localidade **x = malloc (3 * sizeof(Localidade*));
    x[0] = malloc (sizeof(Localidade));
    x[1] = malloc (sizeof(Localidade));
    x[2] = malloc (sizeof(Localidade));
    sz = 3;
    strcpy (x[0]->nome, "PaxDiablo");
    strcpy (x[1]->nome, "Adriano");
    strcpy (x[2]->nome, "Kate Bush");

    dump (sz, x);

    x = remover (x, "AdRiAnO", sz, &sz);
    dump (sz, x);

    return 0;
}

, который выдает, как ожидается:

Size = 3
   [PaxDiablo]
   [Adriano]
   [Kate Bush]
Size = 2
   [PaxDiablo]
   [Kate Bush]
...