TransWikia.com

É incorreto (ou problemático) criar um struct com array de strings?

Stack Overflow em Português Asked on November 10, 2021

Não sei bem qual a maneira ideal para se criar uma estrutura (struct) que contenha um array de string, no caso tenho uma estrutura assim:

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

typedef struct
{
    char nome[81];
    char atores[81][100];
} Filme;

int main()
{
    Filme x[1000];

    return 0;
}

Ao executar isto simplesmente o programa finaliza (crash), então depurei com GDB para tentar entender o que poderia ser a causa e obtive somente a mensagem:

Program received signal SIGSEGV, Segmentation fault.

Presumo que seja erro meu por estar usando de maneira que a memória exceda ou talvez não consiga gerenciar, pois ao executar isto Filme x[1000] são criados muitas estruturas, quando crio algo menor, por exemplo Filme x[20], o problema não ocorre.

Então eu pensei em criar uma estrutura para os atores separada e referenciar/relacionar elas através de uma ID (que no caso seria o próprio index do item), algo como:

typedef struct
{
    char nome[81];
} Filme;

typedef struct
{
    int filmeref;
    char ator[81];
} Atores;

isto seria “correto”?

One Answer

É aquela coisa de sempre, tudo depende. Onde vai usar? Qual o objetivo? Como vai manipular isso?

Tamanhos

Uma instância da estrutura Filme terá sempre mais de 8KB de tamanho, não importa se precisar bem menos, ou se precisar de mais, não ter onde colocar. É isto que deseja? É improvável.

Pensa em um banco de dados. Você quer usar char ou varchar? Nesse caso usou char. Mais ainda, se uma coluna pode ter N elementos prefere que isto seja colocado em: outra tabela; normalizando ou ainda com um formato variável; como XML, JSON, ou algo parecido até mesmo um próprio? Ou algo fixo? É isso que fez.

Mas tem casos que pode ser interessante fazer assim.

Deve-se questionar também se quer realmente criar um array com 1000 elementos. São mais de 8MB ocupados, e se quiser mais de 1000 filmes, não tem como. Claro pode criar outro maior e copiar tudo, o que não é algo tão trivial.

Se quiser manipular algo assim em uma aplicação real, pode ser tornar bem complicado ou desperdiçar recursos. Isto serve para algo muito simples, que se tem controle ou em exercício.

Alocação

Uma das coisas que provavelmente faria é ter um array de ponteiros para elementos de Filme, provavelmente alocados no heap. Provavelmente o próprio array deveria ser alocado no heap com malloc() no lugar de usar na stack. Tem um monte de links em outra pergunta. Mas precisa analisar bem qual é a melhor estratégia de alocação.

É provável que neste caso haveria benefícios em usar indireções em tudo. Mas depende de fatores que não podem ser definidos só por esta descrição. Provavelmente terá ponteiro de ponteiro.

Crash

Para resolver o crash pode gerar um executável com uma pilha maior para caber tudo, geralmente a pilha padrão é de 1MB. Mas ainda é uma solução, provavelmente, ruim, a pilha não deveria ser abusada assim na maioria dos casos.

Se não mudar a arquitetura geral então a solução proposta de separar as estruturas não ajudará muito, embora já seja um ganho por ser normalizado, agora haverá menos desperdício e poderá atender filmes com mais de 100 atores. Demorará mais para estourar, mas ainda terá problemas se continuar alocando na stack.

A stack é para coisas bem pequenas, ou pra um teste rápido, ou ainda quando se tem muito domínio do seu uso e precisa demais daquilo. Eu já fiz coisas onde abusei do stack e defini um de 4GB :), mas isto não é comum.

Modelagem

Ainda assim há um erro conceitual de modelagem já que o ator está vinculado ao filme, portanto haverá dezenas de Jerry Lewis cadastrados, quando só existe 1 Jerry Lewis. É o problema que eu falo sempre sobre orientação a objetos onde as pessoas seguem as receitas dos livros e modelam tudo errado. Seria melhor ter uma lista de identificadores de atores no filme e só uma instância daquele ator.

Mas aí voltamos ao problema da falta de normalização (segunda forma, a primeira estaria sendo respeitada). Então a solução seria ter uma lista separada de atores (só os IDs que apontam para a ficha do ator em si). Essa lista poderia ser um array, ou uma lista ligada com o primeiro elemento já colocado na estrutura do filme, ou uma árvore se precisar de certas características, ou uma tabela de espalhamento, ou outra estrutura que atenda melhor a demanda, cada um com suas vantagens e desvantagens. Se optar por uma lista dinâmica baseado em array terá que bolar estratégias de crescimento.

Há uma forma de manter uma única estrutura para todos os atores dos filmes, ou seja, em vez de ter uma lista por elenco, terá todo mundo junto, aí teria que ter uma chave e valor, com o ID do filme e o ID do ator, isso é uma lista de amarração. Em bancos de dados relacionais tradicionais é a única forma de fazer de forma sã.

A não ser que pegue uma biblioteca pronta terá que fazer tudo na mão, inclusive gerenciar a memória.

De qualquer forma fica claro para um caso real que a stack é inviável para isso tudo.

Uma ideia:

typedef struct {
    const char *nome;
    //outros campos
} Filme;

typedef struct {
    const char *nome;
    //outros campos
} Ator;

Cada nome, de Filme ou de Ator ficará no heap com malloc() (veja a diferença).

Cada Filme ou cada Ator seriam alocados individualmente do heap, sempre com malloc(), claro, a não ser que precise de uma estratégia mais personalizada, o que é raro e bem avançado. As pessoas confundem essa coisa de array físico e array formado por elementos referenciados.

A lista Filmes e a lista Elencos (esta é uma estratégia, que se liga bem com DB relacional) também ficaria no heap, provavelmente como um array, mas não necessariamente. No caso de Filmes teriam apenas ponteiros para cada Filme. E Elencos variaria, mas poderia ser uma estrutura assim:

typedef struct {
    Filme *filme;
    Ator *ator;
} AmarracaoFilmeAtor;

Coloquei no GitHub para referência futura.

Se optar por um array por filme aí poderia usar o ponteiro para o ator direto no array (no heap), o que pode ser um ganho, mas complica um pouco algum gerenciamento, aí um dos campos do Filme seria um ponteiro para a lista Elenco desse filme. Conceitualmente gosto mais disto. Inclusive um dos motivos de eu fazer experimentos com desenvolvimento de banco de dados é justamente ter este tipo de liberdade (NoSQL seria solução óbvia se não tivesse certos custos que não quero pagar).

Conclusão

Nada disso parece muito correto.

Também pode interessar:

Answered by Maniero on November 10, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP