Pergunta

Eu estou tentando criar uma função que leva uma matriz como um argumento, adiciona valores a ele (aumentando seu tamanho, se necessário) e retorna a contagem de itens. Até agora eu tenho:

int main(int argc, char** argv) {
    int mSize = 10;
    ent a[mSize];
    int n;
    n = addValues(a,mSize);

    for(i=0;i<n;i++) {
       //Print values from a
    }
}

int addValues(ent *a, int mSize) {
    int size = mSize;

    i = 0;

    while(....) { //Loop to add items to array
        if(i>=size-1) { 
            size = size*2;
            a = realloc(a, (size)*sizeof(ent));
        }
        //Add to array
        i++;
    }
    return i;
}

Isso funciona se msize é grande o suficiente para conter todos os elementos potenciais da matriz, mas se ele precisa redimensionar, recebo uma falha de segmentação.

Eu também tentei:

int main(int argc, char** argv) {
    ...
    ent *a;
    ...
}

int addValues(ent *a, int mSize) {
    ...
    a = calloc(1, sizeof(ent);
    //usual loop
    ...
}

sem sucesso.

Eu assumo isso é porque quando eu chamar realloc, a cópia de 'a' está em outro lugar pontas - como é possível modificar isso para que 'a' sempre aponta para o mesmo local

Am I ir sobre isso corretamente? Existem melhores formas de lidar com estruturas dinâmicas em C? Devo ser a implementação de uma lista ligada para lidar com isso?

Foi útil?

Solução

O principal problema aqui é que você está tentando usar realloc com uma matriz alocada-stack. Você tem:

ent a[mSize];

Isso é atribuição automática na pilha. Se você quisesse usar realloc () sobre isso mais tarde, você iria criar a matriz na pilha usando malloc (), assim:

ent *a = (ent*)malloc(mSize * sizeof(ent));

Assim que a biblioteca malloc (e, portanto, realloc (), etc.) sabe sobre o seu array. Dos olhares isso, você pode ser confuso matrizes C99 de comprimento variável com a verdadeira matrizes dinâmicas , por isso certifique-se entender a diferença que existe antes de tentar corrigir isso.

Realmente, porém, se você está escrevendo matrizes dinâmicas em C, você deve tentar usar o projeto OOP-ish à informação encapsular sobre suas matrizes e escondê-lo a partir do usuário. Você deseja consolidar informações (por exemplo, ponteiro e tamanho) sobre sua matriz em uma estrutura e operações (por exemplo, alocação, adicionando elementos, removendo elementos, libertando, etc.) em funções especiais que o trabalho com a sua estrutura. Assim que você pode ter:

typedef struct dynarray {
   elt *data;
   int size;
} dynarray;

E você pode definir algumas funções para trabalhar com dynarrays:

// malloc a dynarray and its data and returns a pointer to the dynarray    
dynarray *dynarray_create();     

// add an element to dynarray and adjust its size if necessary
void dynarray_add_elt(dynarray *arr, elt value);

// return a particular element in the dynarray
elt dynarray_get_elt(dynarray *arr, int index);

// free the dynarray and its data.
void dynarray_free(dynarray *arr);

Desta forma, o usuário não tem que se lembrar exatamente como alocar as coisas ou o tamanho do array é atualmente. Esperança de que se você começou.

Outras dicas

Tente retrabalhar-lo para um apontador para um apontador para a matriz é passado em, isto é ent **a. Então, você será capaz de atualizar o chamador sobre a nova localização da matriz.

Esta é uma boa razão para usar OOP. sim, você pode fazer OOP em C, e ainda parece bom, se feito corretamente.

Neste caso simples você não precisa herança nem polimorfismo, apenas os conceitos de encapsulamento e métodos:

  • definir uma estrutura com um comprimento e um ponteiro de dados. talvez um tamanho de elemento.
  • funções de gravação de apanhador / definidor que operam em ponteiros para que struct.
  • a 'crescer' modifica função o ponteiro de dados dentro da estrutura, mas nenhum estadias ponteiro struct válido.

Se você alterou a declaração de variável no principal para ser

ent *a = NULL;

o código funcionaria mais como você imaginou, não liberando uma matriz alocada-stack. Definir um para NULL funciona porque trata realloc isso como se o usuário chamado malloc (tamanho). Tenha em mente que, com esta alteração, o protótipo para AddValue precisa mudar para

int addValues(ent **a, int mSize)

e que as necessidades de código para lidar com o caso de falhar realloc. Por exemplo

while(....) { //Loop to add items to array
    tmp = realloc(*a, size*sizeof(ent));
    if (tmp) {
        *a = tmp;
    } else {
        // allocation failed. either free *a or keep *a and
        // return an error
    }
    //Add to array
    i++;
}

Eu esperaria que a maioria das implementações de realloc irá alocar internamente duas vezes mais memória, se as necessidades buffer atual redimensionamento fazendo do código original

size = size * 2;

desnecessário.

Você está passando o ponteiro matriz por valor. O que isto significa é:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
}

int addValues(ent *a, int mSize) {
    ...
    a = calloc(1, sizeof(ent); // ...is not the same as this
    //usual loop
    ...
}

para alterar o valor de um na função addValues não altera o valor de um em principal. Para alterar o valor de um em principal que você precisa para passar uma referência a ele para addValues. No momento, o valor de uma está sendo copiado e passado para addValues. Para passar uma referência a um uso:

int addValues (int **a, int mSize)

e chamá-lo assim:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
    addValues (&a, mSize);
}

No addValues, acesso os elementos de um como este:

(*a)[element]

e realocar a matriz como este:

(*a) = calloc (...);

Xahtep explica como o interlocutor possa lidar com o fato de que realloc () pode mover a matriz para um novo local. Contanto que você fizer isso, você deve ser fino.

realloc () pode ficar caro se você começar a trabalhar com grandes matrizes. Isso é quando é hora de começar a pensar em usar outras estruturas de dados -. Uma lista ligada, uma árvore binária, etc

Como afirmado você deve passar ponteiro para ponteiro para atualizar o valor do ponteiro.
Mas gostaria de sugerir redesenho e evitar esta técnica, na maioria dos casos ele pode e deve ser evitado. Sem saber o que exatamente você está tentando alcançar é difícil sugerir projeto alternativo, mas estou 99% certo de que é factível outra maneira. E, como Javier triste - pensar orientada a objeto e você sempre terá um código melhor.

Você realmente necessário para usar C? Este seria um ótimo aplicativo de C ++ 's 'std :: vector', que é precisamente uma matriz dinâmica de tamanho (facilmente resizeble com uma única chamada você não tem que escrever e depurar-se).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top