Por que declarar uma estrutura que contém apenas uma matriz em C?

131

Me deparei com um código contendo o seguinte:

struct ABC {
    unsigned long array[MAX];
} abc;

Quando faz sentido usar uma declaração como essa?

Joe.Z
fonte

Respostas:

184

Ele permite que você passe o array para uma função por valor ou obtenha-o retornado pelo valor de uma função.

As estruturas podem ser passadas por valor, diferentemente das matrizes que se deterioram para um ponteiro nesses contextos.

Blagovest Buyukliev
fonte
1
Cuidado ao fazer isso com matrizes, mais do que 16 ou 32 bytes, para funções que não estão alinhadas: é mais eficiente passá-las por referência constante, a menos que o receptor já precise de uma cópia tmp que possa destruir. Se a chamada / retorno não otimizar, uma matriz de médio a grande porte (milhares de bytes) é algo terrível de se passar por valor.
Peter Cordes
85

Outra vantagem é que ele abstrai o tamanho, para que você não precise usar [MAX]todo o seu código onde quer que declare esse objeto. Isso também poderia ser alcançado com

typedef char ABC[MAX];

mas então você tem um problema muito maior: você deve estar ciente de que ABCé um tipo de matriz (mesmo que não possa vê-lo quando declara variáveis ​​do tipo ABC) ou então será afetado pelo fato de ABCsignificar algo diferente em uma lista de argumentos de função versus em uma declaração / definição de variável.

Mais uma vantagem é que a estrutura permite que você adicione mais elementos posteriormente, se necessário, sem precisar reescrever muito código.

R .. GitHub PARE DE AJUDAR GELO
fonte
45

Você pode copiar uma estrutura e retornar uma estrutura de uma função.

Você não pode fazer isso com uma matriz - a menos que faça parte de uma estrutura!

Bo Persson
fonte
26

Você pode copiá-lo assim.

struct ABC a, b;
........
a = b;

Para uma matriz, você precisaria usar a função memcpy ou um loop para atribuir cada elemento.

MetallicPriest
fonte
6
(para que ele permite que o código mais limpo - não vai fazer qualquer diferença na velocidade etc)
John Carter
3
Isso é útil. Infelizmente você não pode fazer se (a == b)!?! quão inconsistente é isso. Para C ++, ele procura um operador ==. Em C diz "operandos inválidos para binários ==".
Matt
11

Você pode usar struct para criar um novo tipo de dados como string . você pode definir:

struct String {
    char Char[MAX];
};

ou você pode criar uma lista de dados que você pode usá-lo por argumento de funções ou retorná-lo em seus métodos. A estrutura é mais flexível que uma matriz, porque pode suportar alguns operadores como = e você pode definir alguns métodos nela.

Espero que seja útil para você :)

Hossein Mobasher
fonte
2
Basicamente, é a coisa mais próxima que C tem para criar uma classe. Eu gosto desta resposta porque ela é a mais próxima de apontar isso.
Nate CK
1
Não existe um método em C. estruturas em C são dados antigos simples. Tem um operador = suportado por padrão (que as outras respostas mostram é a razão para fazer isso), mas isso é enganoso e principalmente se aplica a C ++, não C.
Jonathan Sternberg
3
@ J Sternberg: "Método" é apenas uma maneira de pensar nas sub-rotinas como estando relacionadas aos "objetos" de dados que eles afetam. Você certamente pode criar "classes" de "objetos" e "métodos" que operam neles em C. A linguagem simplesmente não define formalmente essas coisas. Se você deseja criar melhores abstrações em C, incluir coisas em uma estrutura é geralmente a melhor maneira de fazê-lo.
Nate CK
Além disso, se você realmente deseja "criar" métodos em C, pode usar ponteiros de função (sim, sim, sintaxe complicada, sem proteção de dados, etc.) para associar funções aos dados em que operam. Você precisa passar "self" no primeiro argumento (você pode até chamá-lo de "this", se quiser), já que não há criação automática desse ponteiro dentro da função em C. Claro, é tudo ginástica, você recebe coisas como esta por padrão em C ++, embora seja verdade que poderia ser escondido em cima como um bônus ...
BenPen
2

Outra vantagem de usá- structlo é que ele aplica segurança de tipo onde quer que structseja usado; especialmente se você tiver dois tipos que consistem em matrizes do mesmo tamanho usadas para propósitos diferentes, esses tipos ajudarão a evitar o uso acidental de uma matriz de forma inadequada.

Se você não agrupar uma matriz em a struct, ainda poderá declarar um typedefpara isso: isso tem algumas das vantagens de struct- • o tipo é declarado uma vez, • o tamanho é automaticamente correto, • a intenção do código fica mais clara, • e o código é mais fácil de manter - mas você perde a segurança estrita do tipo, a capacidade de copiar e retornar valores do tipo e a capacidade de adicionar membros posteriormente sem interromper o restante do código. Dois typedefs para matrizes nuas de um determinado tipo só produzem tipos diferentes se tiverem tamanhos diferentes. Além disso, se você usar o typedefsem *em um argumento de função, será equivalente a char *reduzir drasticamente a segurança de tipo.

Em resumo :

typedef struct A_s_s { char m[113]; } A_s_t; // Full type safey, assignable
typedef char   A_c_t[113];                   // Partial type-safety, not assignable

A_s_t          v_s(void);     // Allowed
A_c_t          v_c(void);     // Forbidden

void           s__v(A_s_t);     // Type-safe, pass by value
void           sP_v(A_s_t *);   // Type-safe
void           c__v(A_c_t);     // UNSAFE, just means char * (GRRR!)
void           cP_v(A_c_t *);   // SEMI-safe, accepts any array of 113
PJTraill
fonte
1

Uma estrutura pode conter funções de inicialização, cópia e fini de matriz, simulando algumas das vantagens dos paradigmas de gerenciamento de memória OOP. De fato, é muito fácil estender esse conceito para escrever um utilitário genérico de gerenciamento de memória (usando a estrutura sizeof () para saber exatamente quantos bytes estão sendo gerenciados) para gerenciar qualquer estrutura definida pelo usuário. Muitas das bases de códigos de produção inteligentes escritas em C usam muito essas ferramentas e geralmente nunca usam uma matriz, a menos que seu escopo seja muito local.

De fato, para uma matriz incorporada em uma estrutura, você pode fazer outras "coisas inteligentes", como a verificação vinculada sempre que quiser acessar essa matriz. Novamente, a menos que o escopo do array seja muito limitado, é uma má idéia usá-lo e transmitir informações entre os programas. Mais cedo ou mais tarde, você encontrará bugs que o manterão acordado durante a noite e arruinarão seus fins de semana.

Aniket
fonte
Isso não responde à pergunta por que alguém pode usar um structcontendo apenas uma matriz.
PJTraill