Ir ao conteúdo

C Por que não consigo pegar o tamanho de um array de structs


Ir à solução Resolvido por Flávio Pedroza,

Posts recomendados

Postado

Gostaria de pegar o tamanho do array, mas não sei porque estou errando:

 

#include <stdio.h>
#include <stdlib.h>
#define MAX 100



typedef struct
{
	char nome[50];
	int idade;
} pessoa;


int escrever_arquivo(pessoa pessoas[])
{
	FILE * arq;
	arq = fopen("dados.bin", "ab");

	//to apanhando aqui e tentei várias coisas sem sucesso:
	int len_vet = sizeof(pessoas);
	//int len_vet = sizeof(pessoas)/sizeof(pessoas[0]);
	//int len_vet = sizeof(pessoas)/sizeof(pessoa);
	printf("tamanho deveria ser 3, mas é = %i\n", len_vet);
	printf("tamanho do tipo = %i, tá errado esse tamanho!\n", sizeof(pessoa));
	printf("tamanho do pessoas[0] = %i, tá errado esse tamanho!\n", sizeof(pessoas[0]));

	if(arq == NULL)
	{
		printf("\nErro ao abrir o arquivo para leitura!\n");
		fclose(arq);
		return -1;
	}
	for(int i=0; i<len_vet; i++)
	{
		fwrite(&pessoas[i], sizeof(pessoa), 1, arq);
	}
	fclose(arq);
	return 0;
}


int ler_arquivo(pessoa aux_pessoas[])
{
	FILE * arq = fopen("dados.bin", "rb");
	if(arq == NULL)
	{
		printf("\nErro ao abrir o arquivo para leitura!\n");
		return -1;
	}
	int indice = 0;
	pessoa p;
	while(fread(&p, sizeof(pessoa), 1, arq))
	{
		aux_pessoas[indice++] = p;
	}
	fclose(arq);
	return indice;
}

int main(int argc, char *argv[])
{
	char oper;
	int len_vet;
	pessoa aux_pessoas[MAX];

	while (oper != 's') 
	{
		printf("================ MENU ================ \n");
		printf("Escolha: \ng - Para gravar\nl - para ler\ns - para sair\n");
		scanf(" %c", &oper);
		switch (oper) 
		{
			case 'g':
				;
				pessoa pessoas[] = {{"Luiz", 44}, {"Sofia", 11}, {"Daniele", 35}};
				escrever_arquivo(pessoas);
				break;
			case 'l':
				len_vet = ler_arquivo(aux_pessoas);
				if(len_vet>0)
				{
					printf("=========================================\n");
					for(int i=0; i<len_vet; i++)
					{
						printf("Nome: %s\n", aux_pessoas[i].nome);
						printf("Idade: %d\n", aux_pessoas[i].idade);
						printf("-----------------------------------------\n");
					}
				}
				break;
			case 's':
				break;
			default:
				printf("opcao invalida!\n");
				break;
		}
	}
	return 0;
}

 

porque sempre tenho que adicionar ';' dentro do primeiro case?
 

			case 'g':
				; // <- aqui!
				pessoa pessoas[] = {{"Luiz", 44}, {"Sofia", 11}, {"Daniele", 35}};

 

  • Curtir 1
  • Solução
Postado

"porque sempre tenho que adicionar ';' dentro do primeiro case?"

A linguagem não permite colocar declaração de variável logo após um rotulo, apenas instrução. Então você coloca uma instrução vazia (;) para superar essa limitação.

Em relação ao outro problema, acredito que não há como fazer o que quer. Sugiro mudar a função acrescentando um parâmetro:

int escrever_arquivo(pessoa pessoas[], int n) //n eh a quantidade de pessoas

Lembrando que isso

int escrever_arquivo(pessoa pessoas[])

é equivalente a isso

int escrever_arquivo(pessoa* pessoas)

E

int len_vet = sizeof(pessoas);

retorna o tamanho em bytes do ponteiro de memoria (8 bytes, para sistemas de 64 bits).

  • Curtir 1
  • Obrigado 1
Postado
3 horas atrás, Flávio Pedroza disse:

"porque sempre tenho que adicionar ';' dentro do primeiro case?"

A linguagem não permite colocar declaração de variável logo após um rotulo, apenas instrução. Então você coloca uma instrução vazia (;) para superar essa limitação.

Em relação ao outro problema, acredito que não há como fazer o que quer. Sugiro mudar a função acrescentando um parâmetro:

int escrever_arquivo(pessoa pessoas[], int n) //n eh a quantidade de pessoas

Lembrando que isso

int escrever_arquivo(pessoa pessoas[])

é equivalente a isso

int escrever_arquivo(pessoa* pessoas)

E

int len_vet = sizeof(pessoas);

retorna o tamanho em bytes do ponteiro de memoria (8 bytes, para sistemas de 64 bits).


Muito obrigado!
Achei isso estranho. Estou acostumado com java. por isso achei isso feio...
Parece (estou certo?) que eu só devo utilizar ponteiros na passagem de parametros se eu tiver criado ele com maloc. De outro modo, a passagem de ponteiros é desnecessário, sendo melhor trabalhar com o array. Veja que consegui fazer usando arrays acrescentando mais um parametro, como sugeriu:
 

#include <stdio.h>
#include <stdlib.h>
#define MAX 100

typedef struct
{
	char nome[50];
	int idade;
} pessoa;

int escrever_arquivo(pessoa pessoas[], int tm)
{
	FILE * arq;
	arq = fopen("dados.bin", "ab");

	if(arq == NULL)
	{
		printf("\nErro ao abrir o arquivo para leitura!\n");
		fclose(arq);
		return -1;
	}
	for(int i=0; i<tm; i++)
	{
		fwrite(&pessoas[i], sizeof(pessoa), 1, arq);
	}
	fclose(arq);
	return 0;
}

int ler_arquivo(pessoa aux_pessoas[])
{
	FILE * arq = fopen("dados.bin", "rb");
	if(arq == NULL)
	{
		printf("\nErro ao abrir o arquivo para leitura!\n");
		return -1;
	}
	int indice = 0;
	pessoa p;
	while(fread(&p, sizeof(pessoa), 1, arq))
	{
		aux_pessoas[indice++] = p;
	}
	fclose(arq);
	return indice;
}

int main(int argc)
{
	char oper;
	int len_vet;
	pessoa aux_pessoas[MAX];

	while (oper != 's')
	{
		printf("================ MENU ================ \n");
		printf("Escolha: \ng - Para gravar\nl - para ler\ns - para sair\n");
		scanf(" %c", &oper);
		switch (oper) 
		{
			case 'g':;
				pessoa pessoas[] = {{"Luiz", 44}, {"Sofia", 11}, {"Daniele", 35}, {"claudia", 55}};
            	// Sei que é 4, mas aqui pego o tamanho de forma dinamica:
				int tm = sizeof(pessoas)/sizeof(pessoa); 
            	// É estranho que a função consiga ler todo o conteudo, mas não sabe onde ele termina
            	// mesmo trabalhando com ponteiro, fazendo algo assim:
            	// pessoa *p = pessoas;
            	// e passando por parametro o p, sou obrigado a passar tm por parametro. Ou seja, 
            	// não faz diferença fazer isso e por simplicidade é melhor deixar como está. 
				escrever_arquivo(pessoas, tm);
				break;
			case 'l':
				len_vet = ler_arquivo(aux_pessoas);
				if(len_vet>0)
				{
					printf("=========================================\n");
					for(int i=0; i<len_vet; i++)
					{
						printf("Nome: %s\n", aux_pessoas[i].nome);
						printf("Idade: %d\n", aux_pessoas[i].idade);
						printf("-----------------------------------------\n");
					}
				}
				break;
			case 's':
				break;
			default:
				printf("opcao invalida!\n");
				break;
		}
	}
	return 0;
}


 

  • Curtir 2
Postado
14 horas atrás, codigo rápido disse:
	//int len_vet = sizeof(pessoas)/sizeof(pessoas[0]);

 

Esse é o modo certo. Está errando apenas porque na função declarou pessoas como pessoa[] e o que você quer é o que você NÃO colocou lá: o tamanho entre os colchetes. Assim o compilador não tem como saber.

 

São 3 as maneiras comuns de fazer isso que quer. Note que você até declarou uma:

 

    int main(int argc, char *argv[])

 

  1. Um contador e um vetor de ponteiros

 

typedef struct
{
    unsigned    N;  // quantas
    Pessoa**    Pessoa;

}   Grupo1;

 

2. Um contador e um vetor a partir de um ponteiro

 

typedef struct
{
    unsigned N;  // quantas
    Pessoa*  Pessoa;

}   Grupo2;

 

3. Um vetor de ponteiros null-terminated
 

typedef struct
{
    Pessoa**     Pessoa;

}   Grupo3;

 

E nesse caso você pega o tamanho como strlen() faz para toda string: pega o endereço inicial e conta até achar um 0.

 

Esse programa

 

#include <stdio.h>

typedef struct
{
    char nome[50];
    int  idade;
    int  nsu;

} Pessoa;

typedef struct
{
    unsigned N;  // quantas
    Pessoa **Pessoa;

}   Grupo1;


typedef struct
{
    unsigned N;  // quantas
    Pessoa * Pessoa;

}   Grupo2;


typedef struct
{
    Pessoa **Pessoa;

}   Grupo3;


int main(void)
{
    Pessoa gente[20];
    printf("Tamanho do vetor: %zd\n", sizeof(gente) / sizeof(gente[0]));
    return 0;
}

// https://www.clubedohardware.com.br/forums/topic/
// 1558998-por-que-n%C3%A3o-consigo-pegar-o-tamanho
//-de-um-array-de-structs/

 

mostra

 

    Tamanho do vetor: 20

 

Se precisar escrevo um exemplo de como criar os 3 casos

  • Curtir 1
Postado
    Pessoa gente[20];
    printf("Tamanho do vetor: %zd\n", sizeof(gente) / sizeof(gente[0]));
    return 0;


Isso eu sei. Mas como fazer isso sem ser obrigado a passar por parametro o tamanho. Nem sempre se sabe o tamanho antes de se chamar a função. E é nisso que mora a beleza da coisa. Quando o array é populado de forma dinamica.

Mas acredito que essa seja a solução:
 

Citação

3. Um vetor de ponteiros null-terminated

E nesse caso você pega o tamanho como strlen() faz para toda string: pega o endereço inicial e conta até achar um 0.

 

Então eu uso o tamanho da struct do array (no caso pessoa), e vou retirando, a partir do endereço de pessoas até encontrar \0.

vou testar isso.

Obrigado

 

  • Curtir 1
Postado

 

Citação

 

Abaixo --- bem abaixo :) --- seque um exemplo de como criar e acessar um vetor de estruturas em C usando alocação dinâmica. De 3 maneiras comuns. E um exemplo de como gravar em disco depois os arquivos.

 

E depois um exemplo de como acessar os arquivos para ler as struct direto do disco pela posição sequencial delas, como um vetor, mas sem que ter que manter TODO o arquivo na memória.

 

Sempre achei que tinha que ter um exemplo assim no forum e juntei uns que eu já tinha postado.

ARFNeto

 

 

De volta ao tópico


 

Em 22/08/2021 às 01:17, codigo rápido disse:

Achei isso estranho. Estou acostumado com java. por isso achei isso feio...

 

java não tem ponteiros como char* mas ao passar uma classe vai passar por referência :) o ponteiro. E se a classe em questão tiver o atributo de tamanho você vai ter acesso, claro. É outro animal. 

 

ArrayList em java é uma classe, implementa Collection que tem size()... Implemente ArrayList em C e terá a mesma coisa, se implementar as mesmas coisas ;). É simples.

 

Em 22/08/2021 às 01:17, codigo rápido disse:

Parece (estou certo?) que eu só devo utilizar ponteiros na passagem de parametros se eu tiver criado ele com maloc. De outro modo, a passagem de ponteiros é desnecessário, sendo melhor trabalhar com o array

 

Provavelmente não. Ponteiros representam TODOS os casos, array não. 

 

Como te disse acima, ao invés disso

 

typedef struct
{
	char nome[50];
	int idade;
} pessoa;

int escrever_arquivo(pessoa pessoas[], int tm)

 

prefira algo como te mostrei

 

typedef struct
{
    char nome[50];
    int idade;

}   Pessoa;

typedef struct
{
    unsigned N; // quantas
    Pessoa*  p;

}   Pessoas;

int escrever_arquivo(Pessoas* grupo, const char* arquivo);

 

Porque? É o simples: encapsulamento: dentro de Pessoas tem  o tamanho. Você pode mudar a implementação sem mudar a assinatura da função, e o nome do arquivo DEVE ser um parâmetro.

 

22 horas atrás, codigo rápido disse:

Mas como fazer isso sem ser obrigado a passar por parametro o tamanho. Nem sempre se sabe o tamanho antes de se chamar a função. E é nisso que mora a beleza da coisa. Quando o array é populado de forma dinamica

 

Beleza é um conceito subjetivo :) mas arrays "populados de forma dinâmica" são belos como utopia. Vetores são a estrutura básica de dados, tem a melhor performance possível e tem seus casos de uso.

 

Aumentar dinamicamente não funciona: é prático mas tem um custo muito alto e derruba as vantagens todas de usar um array. Por isso estruturas de dados são tão importantes, por isso os livros de estruturas de dados tem mais de 1.000 páginas.

 

Eis o que acontece:

  • conforme o array aumenta essas realocações podem e vão rapidamente se transformar em cópias de tudo que já tem para a nova área. E o sistema não vai pedir licença para copiar.  Quando for a hora acontece. E o programa para. e vai perder o cache. Um desastre
  • ao excluir registros
    • teria que movimentar todo o vetor para eliminar o infeliz excluído. 
    •  Pode só marcar os excluídos mas aí vai perder tempo a cada acesso porque precisa testar CADA registro pra ver se é válido e lá se vai a performance
    • só que de tempos em tempos precisa passar a régua em tudo e eliminar os excluídos porque vai degradar a performance e aumentar o desperdício. Quando entrar com a compactação vai perder um tempo enorme.

Por isso se usam listas ligadas, pilhas, filas,  conjuntos, árvores, dicionários, hash e tal... São dados com comportamento. Algoritmos.

 

Usando vetores de estruturas com tamanho dinâmico

 

De todo modo muitos casos importantes são resolvidos com ArrayList() e similares. Eu mostrei 3 exemplos acima, e já postei aqui muitos exemplos dos 3 casos, nesses tempos de pandemia.

 

No geral o que se faz é usar, como fazer o sistema, alocação em blocos, e ajustar esses tamanhos de acordo com o esperado pelos dados. Se houver muita exclusão quase certamente será usada outra estrutura, como a óbvia lista ligada ou uma árvore. Se for algo tipo texto, um dicionário dinâmico, uma árvore de prefixo. Se as consultas forem em posições aleatórias quase certamente uma tabela hash.

 

A melhor fonte de inspiração para isso é provavelmente Introduction to Algorithms, a bíblia dessas coisas desde a primeira edição

 

3 métodos  comuns

 

Como eu disse antes, C e java por exemplo usam isso em todo programa.

 

  1. um vetor de ponteiros para as estruturas e um contador
  2. um vetor de estruturas e um contador
  3. um vetor de ponteiros terminados por um NULL

Um exemplo usando os 3 métodos

 

Usando o poderoso recurso de recortar e colar vou pegar um exemplo desses e colocar aqui, adaptando para os 3 casos. Claro, é bem parecido: o objetivo é criar e percorrer um vetor de estruturas e gravar tudo em disco ao final.

 

O exemplo vai gravar com os mesmos dados 3 arquivos e assim fica trivial de testar, porque os arquivos devem ser idênticos ao final. Só que o modelo numera os Pessoa gravados, e assim se pode conferir sem esforço, em especial porque também vou deixar um navegador para o arquivo "binário".

 

O programa exemplo trata até 99.999 registros.

 

Percorrendo um vetor de estruturas gravado em disco, como um vetor

 

Ao final vou deixar um exemplo de um programa que lê o arquivo de Pessoa gravado em disco e permite acessar pela posição, de 1 até o total gravado.

 

As estruturas: modo 1
 

// [1] um vetor de ponteiros como em main()

typedef struct
{
    unsigned N;    // quantas
    unsigned cap;  // total
    unsigned inc;  // incremento

    Pessoa** pss;  // os dados

}   Grupo1;

Grupo1*     apaga_grp1(Grupo1* grupo);
Grupo1*     cria_grp1(unsigned inicio, unsigned incr);
int         grava_1(Grupo1* pessoas, const char* arquivo);
int         mostra_1(Grupo1* grupo);
int         insere_1(Pessoa* uma, Grupo1* grupo);

 

E é auto explicativo eu acho:

  • como aloca memória é mais fácil controlar a criação e destruição usando construtores e destrutores ;) 
  • é claro bom ter uma função para mostrar o grupo na tela, afinal é um teste.
  • insere() insere uma Pessoa num Grupo, o simples. 2 ponteiros, sem frescura.
  • grava() pega a estrutura e grava em disco. Eu ia classificar por nome e sequência antes de gravar no disco, mas estou com preguiça. Seria legal ter um exemplo assim completo e talvez eu reescreva essa parte.
  • nada de void: em caso de erro retorna algo negativo ou NULL

As estruturas: modo 2
 

    Claro que eu copiei tudo e só alterei para o novo modelo, então é tudo igual.

 

// [2] um vetor de struct com um contador
typedef struct
{
    unsigned N;    // quantas
    unsigned cap;  // capacidade
    unsigned inc;  // incremento

    Pessoa* pss;  // os dados

} Grupo2;

Grupo2* apaga_grp2(Grupo2*);
Grupo2* cria_grp2(unsigned inicio, unsigned incremento);
int     grava_2(Grupo2* pessoas, const char* arquivo);
int     mostra_2(Grupo2* grupo);
int     insere_2(Pessoa* pessoa, Grupo2* grupo);

 

As estruturas: modo 3

 

Esse modo é útil quando se tem processos intermediários, que vão pegar estruturas e passar todas pela ordem para outra fase, processando em lote. Isso porque se pode apenas seguir no loop até vir um NULL.
 

// [3] um vetor de ponteiros para Pessoa,
// terminado por NULL
typedef struct
{
    unsigned cap;
    unsigned inc;

    Pessoa** pss;  // dados

} Grupo3;

Grupo3*     apaga_grp3(Grupo3*);
Grupo3*     cria_grp3(unsigned inicio, unsigned limite);
int         grava_3(Grupo3* pessoas, const char* arquivo);
int         mostra_3(Grupo3* grupo);
int         insere_3(Pessoa* um, Grupo3* todos);

 

O programa teste:

 

	teste N;

 

Pois é: o N é opcional e se usar só o nome vai criar os 3 arquivos com 8 registros. Se for usado é claro o total de registros e funciona até 99.999.

 

main() em partes :) 

 

int main(int argc, char** argv)
{
    srand(210821);

    // cria e mostra 3 grupos
    Grupo1* grp1 = cria_grp1(40, 8);    // inicia com 40
    Grupo2* grp2 = cria_grp2(200, 0);   // não pode aumentar
    Grupo3* grp3 = cria_grp3(10, 20);  // aumenta de 20 em 20
    mostra_1(grp1);
    mostra_2(grp2);
    mostra_3(grp3);

 

Os 3 grupos são criados e mostrados, ainda claro vazios. Note que o grupo 2 não pode passar de 200 Pessoa já que o parâmetro de incremento é 0. 

 


        [Modo 1]
        Grupo tem  0 [de 40 pessoas] [incr = 8]


        [Modo 2]
        Grupo tem  0 [de 200 pessoas] [incr = 0]


        [Modo 3]
        Grupo[limite de 10 pessoas] [incr = 20]

        Total de 0 pessoas

 

Depois o total é calculado:
 

    // ajusta total de pessoas a inserir
    int total = 8;
    if (argc > 1)
    {  // so por garantia... entre 2 e 99999 testes, ou 8 apenas
        total = atoi(argv[1]);
        if ( (total >= 100000) || (total < 2) ) total = 8;
    };
    printf("\tTestando para %u 'Pessoa' no arquivo\n", total);

 

E os registros são criados, 8 sem parâmetros ou até 99.999.

 

    // insere as mesmas pessoas nos 3 grupos
    for (int i = 0; i < total; i += 1)
    {   // cria uma pessoa e insere os 3 grupos
        Pessoa* p = fabrica();
        insere_1(p, grp1);
        insere_2(p, grp2);
        insere_3(p, grp3);
        free(p); // apaga a Pessoa
    };

 

Uma factory function fabrica() retorna uma Pessoa nova sempre que chamada, com nome e idade aleatórios e a sequência numerada a partir de 1. Bem conveniente a menos que se queira ficar num menu digitando milhares de valores.

 

A tal Pessoa é inserida nos 3 grupos, onde cada um usa um dos métodos, e a seguir é destruída.

 

    mostra_1(grp1);
    grava_1(grp1, "modo1.dat");
    mostra_2(grp2);
    grava_2(grp2, "modo2.dat");
    mostra_3(grp3);
    grava_3(grp3, "modo3.dat");
	return 0;

 

E afinal os 3 arquivos são gerados no disco.

 

Saída completa de um teste com 5 registros

 



        Testando para 5 Pessoa no arquivo

        [Modo 1]
        Grupo tem  5 [de 40 pessoas] [incr = 8]
    NomeDaPessoa N791 Jr. (21)    [SEQ = #00001]
    NomeDaPessoa N857 Jr. (76)    [SEQ = #00002]
    NomeDaPessoa N963 Jr. (58)    [SEQ = #00003]
    NomeDaPessoa N032 Jr. (64)    [SEQ = #00004]
    NomeDaPessoa N092 Jr. (56)    [SEQ = #00005]

[grava 1]  vai gravar 5 registros em "modo1.dat"

        . . . . .
[grava 1]  ok!

        [Modo 2]
        Grupo tem  5 [de 200 pessoas] [incr = 0]
    NomeDaPessoa N791 Jr. (21)    [SEQ = #00001]
    NomeDaPessoa N857 Jr. (76)    [SEQ = #00002]
    NomeDaPessoa N963 Jr. (58)    [SEQ = #00003]
    NomeDaPessoa N032 Jr. (64)    [SEQ = #00004]
    NomeDaPessoa N092 Jr. (56)    [SEQ = #00005]

[grava 2]  vai gravar 5 registros em "modo2.dat"

        . . . . .
[grava 2]  ok!

        [Modo 3]
        Grupo[limite de 10 pessoas] [incr = 20]
    NomeDaPessoa N791 Jr. (21)    [SEQ = #00001]
    NomeDaPessoa N857 Jr. (76)    [SEQ = #00002]
    NomeDaPessoa N963 Jr. (58)    [SEQ = #00003]
    NomeDaPessoa N032 Jr. (64)    [SEQ = #00004]
    NomeDaPessoa N092 Jr. (56)    [SEQ = #00005]

        Total de 5 pessoas


[grava 3]  vai gravar registros em "modo3.dat"

        . . . . .
[grava 3]  gravados 5 registros
[grava 3]  ok!

 

Um dump do final de modo3.dat no disco
 

         sp   N   0   3   2  sp   J   r   . nul  sp  sp  sp  sp  sp  sp  > N032 Jr..      <
0000320        20202020        20202020        20202020        20202020
         sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  >                <
0000340        20202020        00402020        30300000        00343030
         sp  sp  sp  sp  sp  sp   @ nul nul nul   0   0   0   0   4 nul  >      @...00004.<
0000360        656d6f4e        65506144        616f7373        39304e20
          N   o   m   e   D   a   P   e   s   s   o   a  sp   N   0   9  >NomeDaPessoa N09<
0000400        724a2032        2020002e        20202020        20202020
          2  sp   J   r   . nul  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  >2 Jr..          <
0000420        20202020        20202020        20202020        20202020
         sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  sp  >                <
0000440        00382020        30300000        00353030
         sp  sp   8 nul nul nul   0   0   0   0   5 nul                  >  8...00005.<
0000454

 

E assim dá pra ver o final do arquivo com o registro 5.

 

Navegando pelo arquivo no disco pelo índice, como um vetor

 

O programa tem umas 50 linhas e é só um loop: ao abrir o arquivo o programa calcula quantos registros tem lá e entra no loop lendo o número do registro e mostrando na tela esse registro, usando claro as mesmas funções que o outro que criou os registros.

 

O trivial. Qualquer valor fora do intervalo o programa termina.

 

C:\CH> fsk-test modo3.dat

Testando "modo3.dat"
Total de 300 bytes, 5 pessoas
Digite o n. do registro [1..5]: 5
    NomeDaPessoa N092 Jr. (56)    [SEQ = #00005]
Digite o n. do registro [1..5]: 1
    NomeDaPessoa N791 Jr. (21)    [SEQ = #00001]
Digite o n. do registro [1..5]: 2
    NomeDaPessoa N857 Jr. (76)    [SEQ = #00002]
Digite o n. do registro [1..5]: 5
    NomeDaPessoa N092 Jr. (56)    [SEQ = #00005]
Digite o n. do registro [1..5]: +

 

A lógica aqui é linear: abre o arquivo, calcula o tamanho, entra no loop, mostra os caras até o fim

 

Essa função é o programa todo:

 

Tem uma variável para a única Pessoa que vai usar, uns contadores e o ponteiro para o arquivo.

 

int testa_arquivo(const char* arquivo)
{
    printf("\n\nTestando \"%s\"\n", arquivo);
    FILE* F = fopen(arquivo, "rb+");
    if (F == NULL) return -1;
    // calcula o tamanho
    int res = fseek(F, 0, SEEK_END);
    if (res != 0) return -1;
    int total = ftell(F);
    unsigned n_pessoas = total / sizeof(Pessoa);
    printf("Total de %ld bytes, %u pessoas\n",
        total, n_pessoas);

    Pessoa   uma;
    unsigned r = 0;
    printf("Digite o n. do registro [1..%d]: ", n_pessoas);
    while ((res = scanf("%d", &r)) == 1)
    {
        if (r > n_pessoas) continue;
        if (r == 0) continue;
        res = fseek(F, ((r - 1) * sizeof(Pessoa)), SEEK_SET);
        if (res != 0)
        {
            printf("Erro de posicionamento, r = %d\n", r);
            break;
        }
        res = (int) fread(&uma, sizeof(Pessoa), 1, F);
        if (res != 1)
        {
            printf("Erro de leitura, r = %d\n", r);
            break;
        }
        mostra_pessoa(&uma);
        printf("Digite o n. do registro [1..%d]: ", n_pessoas);
    };
    fclose(F);
    return 0;
}

 

 

Os programas completos

 

O programa que cria os 3 arquivos

 

Pessoa.h

#pragma once
#include <memory.h>
#include <stdlib.h>

typedef struct
{
    char nome[50];
    int  idade;
    char seq[6];  // numerado

} Pessoa;


Pessoa*     fabrica()
{  // retorna uma Pessoa com
    // nome 'Nome Pessoa Nnnn' com nnn entre 1 e 999
    // idade entre 18 e 77
    // seq numerado a partir de 1
    static int seq = 1;
    Pessoa*    p   = (Pessoa*)malloc(sizeof(Pessoa));
    memset(p, ' ', sizeof(Pessoa));
    p->idade       = 18 + (rand() % 60);
    // poe a sequencia ao final para siar no DUMP
    sprintf(p->nome, "NomeDaPessoa N%03d Jr.", (1 + rand()%999));
    // seq tem 6 digitos: "00000" a "99999"
    int tmp = seq;
    for (int d = 4; d >= 0; d -= 1)
    {
        p->seq[d] = tmp % 10 + '0';
        tmp /= 10;
    };  // for()
    p->seq[5] = 0;
    seq++;
    return p;
};

void        mostra_pessoa(Pessoa* p)
{
    printf("    %20s (%d)    [SEQ = #%s]\n", p->nome, p->idade, p->seq);
    return;
}

 

modo1.h

 

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include "Pessoa.h"

// [1] um vetor de ponteiros como em main()

typedef struct
{
    unsigned N;    // quantas
    unsigned cap;  // total
    unsigned inc;  // incremento

    Pessoa** pss;  // os dados

}   Grupo1;

Grupo1*     apaga_grp1(Grupo1* grupo);
Grupo1*     cria_grp1(unsigned inicio, unsigned incr);
int         grava_1(Grupo1* pessoas, const char* arquivo);
int         mostra_1(Grupo1* grupo);
int         insere_1(Pessoa* uma, Grupo1* grupo);


Grupo1*     apaga_grp1(Grupo1* g)
{                                // Pessoa** com contador
    if (g == NULL) return NULL;  // vai que...
    for (unsigned i = 0; i < g->N; i += 1) free(g->pss[i]);
    free(g);
    return NULL;
}

Grupo1*     cria_grp1(unsigned init, unsigned incr)
{  // pss = Pessoa**, com N elementos
    Grupo1* G = (Grupo1*)malloc(sizeof(Grupo1));
    G->N      = 0;     // vazio
    G->inc    = incr;  // incremento
    G->cap    = init;  // tamanho inicial
    G->pss    = (Pessoa**)malloc(init*sizeof(Pessoa*));
    for (unsigned i = 0; i < init; i += 1)
        G->pss[i] = (Pessoa*)malloc(sizeof(Pessoa*));
    return G;
}

int         grava_1(Grupo1* pessoas, const char* arquivo)
{
    if (arquivo == NULL) return -1;
    FILE* F = fopen(arquivo, "w");
    if (F == NULL) return -2;
    printf("[grava 1]  vai gravar %u registros em \"%s\"\n", pessoas->N, arquivo);
    if (pessoas->N == 0) return 0;
    printf("\n\t");
    for (unsigned i = 0; i < pessoas->N; i += 1)
    {
        size_t r = fwrite(pessoas->pss[i], sizeof(Pessoa), 1, F);
        if ( r != 1 ) return -3;
        printf(". ");
        if (i % 50 == 49) printf("\n\t");
    }
    printf("\n[grava 1]  ok!\n");
    fclose(F);
    return 0;
};

int         insere_1(Pessoa* p, Grupo1* g)
{
    if (p == NULL) return -1;
    if (g == NULL) return -2;
    // ja no limite?
    if (g->N >= g->cap)
    {
        if (g->inc == 0) return -3;  // tamanho fixo
        // ok: pode aumentar
        unsigned n_atual = g->cap;
        unsigned n_novo  = g->cap + g->inc;
        // aloca novo bloco de ponteiros
        Pessoa** novo = realloc(g->pss, (n_novo * sizeof(Pessoa*)));
        if (novo == NULL) return -4;  // não conseguiu aumentar
        g->pss = novo;
        g->cap = n_novo;
    }
    // ok: tem lugar: cria o ponteiro
    g->pss[g->N]    = (Pessoa*)malloc(sizeof(Pessoa));
    *(g->pss[g->N]) = *p;  // copia a Pessoa
    g->N += 1;  // conta esse
    return 0;
};

int         mostra_1(Grupo1* g)
{
    if (g == NULL) return -2;
    printf(
        "\n\t[Modo 1]"
        "\n\tGrupo tem %2u [de %u pessoas] [incr = %d]\n",
        g->N, g->cap, g->inc);
    for (unsigned i = 0; i < g->N; i += 1)
        mostra_pessoa(g->pss[i]);
    printf("\n");
    return 0;
};
// fim de modo1.h

 

modo2.h

 

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include "Pessoa.h"

// [2] um vetor de struct com um contador
typedef struct
{
    unsigned N;    // quantas
    unsigned cap;  // capacidade
    unsigned inc;  // incremento

    Pessoa* pss;  // os dados

} Grupo2;

Grupo2* apaga_grp2(Grupo2*);
Grupo2* cria_grp2(unsigned inicio, unsigned incremento);
int     grava_2(Grupo2* pessoas, const char* arquivo);
int     mostra_2(Grupo2* grupo);
int     insere_2(Pessoa* pessoa, Grupo2* grupo);

Grupo2*     apaga_grp2(Grupo2* g)
{                                // Pessoa** com contador
    if (g == NULL) return NULL;  // vai que...
    free(g->pss);
    free(g);
    return NULL;
}

Grupo2*     cria_grp2(unsigned init, unsigned incr)
{  // pss = Pessoa*, com N elementos
    Grupo2* G = (Grupo2*)malloc(sizeof(Grupo2));
    G->N      = 0;     // vazio
    G->inc    = incr;  // incremento
    G->cap    = init;  // tamanho inicial
    G->pss    = (Pessoa*)malloc(init * sizeof(Pessoa));
    return G;
}

int         grava_2(Grupo2* pessoas, const char* arquivo)
{
    if (arquivo == NULL) return -1;
    FILE* F = fopen(arquivo, "w");
    if (F == NULL) return -2;
    printf(
        "[grava 2]  vai gravar %u registros em \"%s\"\n", pessoas->N,
        arquivo);
    if (pessoas->N == 0) return 0;
    printf("\n\t");
    for (unsigned i = 0; i < pessoas->N; i += 1)
    {
        size_t r = fwrite(&pessoas->pss[i], sizeof(Pessoa), 1, F);
        if (r != 1) return -3;
        printf(". ");
        if (i % 50 == 49) printf("\n\t");
    }
    printf("\n[grava 2]  ok!\n");
    fclose(F);
    return 0;
};

int         insere_2(Pessoa* p, Grupo2* g)
{
    if (p == NULL) return -1;
    if (g == NULL) return -2;
    // ja no limite?
    if (g->N >= g->cap)
    {
        if (g->inc == 0) return -3;  // tamanho fixo
        // ok: pode aumentar
        unsigned n_atual = g->cap;
        unsigned n_novo  = g->cap + g->inc;
        // aloca novo bloco de ponteiros
        Pessoa* novo = realloc(g->pss, (n_novo * sizeof(Pessoa)));
        if (novo == NULL) return -4;  // não conseguiu aumentar
        g->pss = novo;
        g->cap = n_novo;
    }
    // ok: tem lugar: cria o ponteiro
    g->pss[g->N] = *p;  // copia a Pessoa
    g->N += 1;             // conta esse
    return 0;
};

int         mostra_2(Grupo2* g)
{
    if (g == NULL) return -2;
    printf(
        "\n\t[Modo 2]\n\t\
Grupo tem %2u [de %u pessoas] [incr = %d]\n",
        g->N, g->cap, g->inc);
    for (unsigned i = 0; i < g->N; i += 1) mostra_pessoa(&g->pss[i]);
    printf("\n");
    return 0;
};
// fim de modo2.h

 

modo3.h

 

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include "Pessoa.h"

// [3] um vetor de ponteiros para Pessoa,
// terminado por NULL
typedef struct
{
    unsigned cap;
    unsigned inc;

    Pessoa** pss;  // dados

} Grupo3;

Grupo3*     apaga_grp3(Grupo3*);
Grupo3*     cria_grp3(unsigned inicio, unsigned limite);
int         grava_3(Grupo3* pessoas, const char* arquivo);
int         mostra_3(Grupo3* grupo);
int         insere_3(Pessoa* um, Grupo3* todos);

Grupo3*     apaga_grp3(Grupo3* g)
{
    // sem contador apaga ate NULL
    if (g == NULL) return NULL; // vai que...
    int i = 0;
    while (g->pss[i] != NULL) free(g->pss[i++]);
    free(g->pss);
    return NULL;
}

Grupo3*     cria_grp3(unsigned init, unsigned incr)
{  // pss = Pessoa**, sem contador
    Grupo3* G = (Grupo3*)malloc(sizeof(Grupo3));
    G->inc    = incr;  // incremento
    G->cap    = init;  // tamanho inicial
    // a diferenca do modo 1 para o 3 aparece aqui
    G->pss    = (Pessoa**)malloc((1+init)*sizeof(Pessoa*));
    G->pss[0] = NULL;
    return G;
}

int         grava_3(Grupo3* pessoas, const char* arquivo)
{
    if (arquivo == NULL) return -1;
    FILE* F = fopen(arquivo, "w");
    if (F == NULL) return -2;
    int cont = 0;
    printf(
        "[grava 3]  vai gravar registros em \"%s\"\n",
        arquivo);
    int N = 0;
    printf("\n\t");
    while (pessoas->pss[N] != NULL)
    {
        size_t r = fwrite(pessoas->pss[N], sizeof(Pessoa), 1, F);
        if (r != 1) return -3;
        printf(". ");
        if (N % 50 == 49) printf("\n\t");
        N += 1;
    };  // while()
    printf("\n[grava 3]  gravados %u registros\n", N);
    printf("[grava 3]  ok!\n");
    fclose(F);
    return 0;
};

int         insere_3(Pessoa* p, Grupo3* g)
{
    if (p == NULL) return -1;
    if (g == NULL) return -2;
    // ja no limite? precisa ir ate o fim?
    unsigned N = 0;
    while (g->pss[N] != NULL) N += 1;

    if (N > g->cap)
    {
        if (g->inc == 0) return -3;  // tamanho fixo
        // ok: pode aumentar
        unsigned n_atual = g->cap;
        unsigned n_novo  = g->cap + g->inc;
        // aloca novo bloco de ponteiros
        Pessoa** novo = realloc(g->pss, ((1+n_novo) * sizeof(Pessoa*)));
        if (novo == NULL) return -4;  // não conseguiu aumentar
        g->pss = novo;
        g->cap = n_novo;
    }
    g->pss[N]    = (Pessoa*)malloc(sizeof(Pessoa));
    *(g->pss[N]) = *p;  // copia a Pessoa
    // ok: tem lugar: cria o ponteiro
    N += 1;
    g->pss[N] = (Pessoa*)malloc(sizeof(Pessoa));
    g->pss[N] = NULL;
    return 0;
};

int         mostra_3(Grupo3* g)
{
    if (g == NULL) return -2;
    printf( "\n\t[Modo 3]\n\tGrupo"
        "[limite de %u pessoas] [incr = %d]\n",
        g->cap, g->inc);
    int n = 0;
    while (g->pss[n] != NULL)
    {
        mostra_pessoa(g->pss[n]);
        n += 1;
    }
    printf("\n\tTotal de %d pessoas\n\n\n", n);
    return 0;
};
// fim de modo3.h

 

fase2.c

 

#pragma pack( push,1 )
#pragma pack( show )

#include <stdio.h>
#include <stdlib.h>
#include "modo1.h" 
#include "modo2.h" 
#include "modo3.h" 

int main(int argc, char** argv)
{
    srand(210821);

    // cria e mostra 3 grupos
    Grupo1* grp1 = cria_grp1(40, 8);    // inicia com 40
    Grupo2* grp2 = cria_grp2(200, 0);   // não pode aumentar
    Grupo3* grp3 = cria_grp3(10, 20);  // aumenta de 20 em 20
    mostra_1(grp1);
    mostra_2(grp2);
    mostra_3(grp3);

    // ajusta total de pessoas a inserir
    int total = 8;
    if (argc > 1)
    {  // so por garantia... entre 2 e 99999 testes, ou 8 apenas
        total = atoi(argv[1]);
        if ( (total >= 100000) || (total < 2) ) total = 8;
    };
    printf("\tTestando para %u 'Pessoa' no arquivo\n", total);

    // insere as mesmas pessoas nos 3 grupos
    for (int i = 0; i < total; i += 1)
    {   // cria uma pessoa e insere os 3 grupos
        Pessoa* p = fabrica();
        insere_1(p, grp1);
        insere_2(p, grp2);
        insere_3(p, grp3);
        free(p); // apaga a Pessoa
    };
    mostra_1(grp1);
    grava_1(grp1, "modo1.dat");
    mostra_2(grp2);
    grava_2(grp2, "modo2.dat");
    mostra_3(grp3);
    grava_3(grp3, "modo3.dat");

    grp1 = apaga_grp1(grp1);
    grp2 = apaga_grp2(grp2);
    grp3 = apaga_grp3(grp3);
    return 0;
}

// https://www.clubedohardware.com.br/forums/topic/
// 1558998-por-que-n%C3%A3o-consigo-pegar-o-tamanho
//-de-um-array-de-structs/

 

O navegador para o vetor em disco

 

fseek-teste.c

 

#pragma pack( push,1 )
#pragma pack( show )
#include <stdio.h>
#include <stdlib.h>
#include "Pessoa.h"

int         testa_arquivo(const char*);
void        uso();

int main(int argc, char** argv)
{
    if (argc < 2) uso();
    testa_arquivo(argv[1]);
    return 0;
}


int testa_arquivo(const char* arquivo)
{
    printf("\n\nTestando \"%s\"\n", arquivo);
    FILE* F = fopen(arquivo, "rb+");
    if (F == NULL) return -1;
    // calcula o tamanho
    int res = fseek(F, 0, SEEK_END);
    if (res != 0) return -1;
    int total = ftell(F);
    unsigned n_pessoas = total / sizeof(Pessoa);
    printf("Total de %ld bytes, %u pessoas\n",
        total, n_pessoas);

    Pessoa   uma;
    unsigned r = 0;
    printf("Digite o n. do registro [1..%d]: ", n_pessoas);
    while ((res = scanf("%d", &r)) == 1)
    {
        if (r > n_pessoas) continue;
        if (r == 0) continue;
        res = fseek(F, ((r - 1) * sizeof(Pessoa)), SEEK_SET);
        if (res != 0)
        {
            printf("Erro de posicionamento, r = %d\n", r);
            break;
        }
        res = (int) fread(&uma, sizeof(Pessoa), 1, F);
        if (res != 1)
        {
            printf("Erro de leitura, r = %d\n", r);
            break;
        }
        mostra_pessoa(&uma);
        printf("Digite o n. do registro [1..%d]: ", n_pessoas);
    };
    fclose(F);
    return 0;
}


void uso()
{   // o classico
    printf("Use: fsktest arquivo\n");
    exit(0);
}

 

21 horas atrás, codigo rápido disse:

Acho que o terceiro fonte desse post é o exemplo perfeito do meu erro:
https://www.techiedelight.com/find-size-of-an-array-c/

E o quarto fonte parece ser a solução, mas não funcionou pra mim passando por parametro.

 

Isso é só um truque. Não funciona quase nunca. Quando funciona o modo como eu te mostrei é o oficial. Para o caso em que você quer não funciona mesmo.

  • Curtir 1
  • Obrigado 1
Postado
Citação

O programa exemplo trata até 99.999 registros.

Muito legal. Para a minhas necessidades eu só precisava de 9.999 registros!
Tá bom de mais da conta!
 

Eu fiz um exemplo desses utilizando array dinamicos (maloc), mas pensei que tinha forma mais simples do que a que fiz. Ficou um pouco parecido com a struct Grupo:
https://www.clubedohardware.com.br/forums/topic/1558865-alocação-dinamica-de-array-inclusão-exclusão-e-free/     

 

Agora aqui, busquei uma forma sem uso de strutc, querendo pegar o tamanho do array sem precisar passar parametros além do array ou ficar utilizando contadores, como na struct grupo dos seus exemplos ou do Array do link acima que passei.
Vejo que não é tão simples como pensei que fosse, pois achava que existia uma forma de pegar o tanhado do array ja dentro da função sem uso de struct e contadores. Bem... pelo menos eu não consigo fazer.
Acredito que especifiquei errado o problema. De qualuqer forma, obrigado. Gostei de muita coisa que postou aqui.

 


voltando ao seu post...
 

Citação

 Eis o que acontece:

    conforme o array aumenta essas realocações podem e vão rapidamente se transformar em cópias de tudo que já tem para a nova área. E o sistema não vai pedir licença para copiar.  Quando for a hora acontece. E o programa para. e vai perder o cache. Um desastre ao excluir registros.
        teria que movimentar todo o vetor para eliminar o infeliz excluído.
        Pode só marcar os excluídos mas aí vai perder tempo a cada acesso porque precisa testar CADA registro pra ver se é válido e lá se vai a performance
        só que de tempos em tempos precisa passar a régua em tudo e eliminar os excluídos porque vai degradar a performance e aumentar o desperdício. Quando entrar com a compactação vai perder um tempo enorme.

 

Sim. Percebi isso na função int deleteByIndexInArray(Array *a, int item) , do exemplo do link que passei. Realmente isso não é legal porque fica fazendo copias. Feio... Mas o que você fez de diferente? Não entendi. você simplesmente apagou todo o grupo. E não apenas ou uma sequencia de pessoas quais queres.
Para evitar tanta movimentação, acredito que a função void insertInArray(Array *a, myData element) multiplique o tamanho por 2 sempre que atinge o tamanho limite. Isso eu tinha achado interessante. E nos seus insere, em todos, você utiliza realloc. A diferença, que eu gostei bastante, é que você permite o tamanho do incremento passado por parametro.  Achei mais bonito. Mais elegante.
pra eu passar a régua, sem ficar copiando e apagando sempre que alterar um registro, eu teria que usar uma lista. Ou seja, uma estrutura em que existe um ponteiro apontando para o dado anterior e outro ponteiro apontando para o dado posterior. É bem legal, bonito e interessante.

Citação

Por isso se usam listas ligadas, pilhas, filas,  conjuntos, árvores, dicionários, hash e tal... São dados com comportamento. Algoritmos.

Sim. Entendo isso como metadados. Eles melhoram a eficiencia das operações com os dados. Exemplo os ponteiros que apontam para o elemento anterior e posterior ao elemento "selecionado".
 

Não entendi porque você fez isso nos grupos cria_grp1, cria_grp2 e cria_grp3:
Grupo1* G = (Grupo1*)malloc(sizeof(Grupo1));
Grupo2* G = (Grupo2*)malloc(sizeof(Grupo2));
Grupo3* G = (Grupo3*)malloc(sizeof(Grupo3));
No meu entendimento o equivalente disso é a struct Array que fiz fiz em:
https://www.clubedohardware.com.br/forums/topic/1558865-alocação-dinamica-de-array-inclusão-exclusão-e-free/
porque fez isso, algo que necessitaria de um free depois que terminasse de utilizar?
Não sei se daria certo para mim na maioria dos meus casos, pois geralmente quando gravo dados sobre pessoas, se eu for apagar, eu apago um de cada vez. Não apago todo o grupo de pessoas (array) de uma vez.
No meu entendimento, talvez tenha sido por isso que fez dessa maneira, pois não havendo necessidade de apagar o grupo e sim uma pessoa de cada vez, não precisaria fazer um maloc de cada grupo, como foi feita na sua sugestão.
Em resumo: não estou certo do porque fez o maloc de cada grupo, mas entendo porque fez de cada pessoa.

 

Citação

Esse modo é útil quando se tem processos intermediários, que vão pegar estruturas e passar todas pela ordem para outra fase, processando em lote. Isso porque se pode apenas seguir no loop até vir um NULL.


Não entendi o que quis dizer com isso. O que quer dizer processos intermediários?
O que entendi é que o NULL serve como um marcador. Mas em que isso torna melhor que os outros dois primeiros modos? Quando isso será mais util que os dois primeiros?

 

//Ok! Mas como eu faço para que a função que recebe o seguinte array como parametro pegar o tamanho dele? 
pessoa pessoas[] = {{"Luiz", 44}, {"Sofia", 11}, {"Daniele", 35}};
// usando uma função simples assim:
escrever_arquivo(pessoas);



Amei sua função int testa_arquivo(const char* arquivo). O navegador para o arquivo "binário". Lindo isso! Cara, valeu! Mesmo! De mais da conta!
 

  • Curtir 1
Postado
15 horas atrás, codigo rápido disse:

 

Eu fiz um exemplo desses utilizando array dinamicos (maloc), mas pensei que tinha forma mais simples do que a que fiz. Ficou um pouco parecido com a struct Grupo

 

O que escreveu
 

typedef struct 
{
	myData *array;
	size_t used;
	size_t size;
} Array;


é o que eu mostrei como Grupo2
 

// [2] um vetor de struct com um contador
typedef struct
{
    unsigned N;    // quantas
    unsigned cap;  // capacidade
    unsigned inc;  // incremento

    Pessoa* pss;  // os dados

} Grupo2;

Grupo2* apaga_grp2(Grupo2*);
Grupo2* cria_grp2(unsigned inicio, unsigned incremento);
int     grava_2(Grupo2* pessoas, const char* arquivo);
int     mostra_2(Grupo2* grupo);
int     insere_2(Pessoa* pessoa, Grupo2* grupo);

 

Se preciso implemente o `limite`, talvez mantendo o incremento. 

 

Como escreveu não está completo e não parece correto. Sugiro ficar com o que eu escrevi porque já tem as rotinas prontas.

 

Veja esse caso por exemplo:
 

void insertInArray(Array *a, myData element) 
{
	// a->used é o numero usado
	// a->size é o limite
	if (a->used == a->size) 
	{
		if(a->size==0)a->size=1;
		else a->size *= 2;
		a->array = realloc(a->array, a->size * sizeof(myData));
	}
	a->array[a->used++] = element;
}

 

Não está nem tratando o limite e quando está vazio aloca um só ponteiro. E no uso vai dobrando. Nem sempre isso é útil. No início pode não fazer diferença, mas se sua estrutura for grande dobrar de 100.000 para 200.000 pode não ser esperto. É melhor escolher um bloco inicial grande e adequado por algum tempo. Um incremento razoável. E um limite sadio se for colocar em produção e não quiser ter um limite "oculto" na implementação. É essencial minimizar as chamadas a realloc(), mas sem desperdiçar tempo ou memória. Acima tem os dois exemplos: ao criar com apenas 1 ponteiro desperdiça tempo. Ao dobrar em TODA expansão desperdiça memória, muita, e tempo na cópia.

 

15 horas atrás, codigo rápido disse:

Vejo que não é tão simples como pensei que fosse, pois achava que existia uma forma de pegar o tanhado do array ja dentro da função sem uso de struct e contadores. Bem... pelo menos eu não consigo fazer

 

Esse exemplos são o simples. Sugiro esquecer isso de "pegar o tamanho do array". Isso não existe. Se precisa mesmo disso, e essas técnicas que mostrei não servem, provavelmente precisa de outra estrutura de dados.

 

 

16 horas atrás, codigo rápido disse:

porque fez isso, algo que necessitaria de um free depois que terminasse de utilizar?

 

Está vendo ao contrário: você faz isso justamente porque QUER usar free() quando determinar que não precisa mais dos dados. Imagine algo bobinho como

 

    Grupo1*		departamento[100];

 

Você tem ponteiros para 100 grupos e pode tratar conforme preciso. Cada um com seus dados dentro, no caso do exemplo que mostrei cada um com até 100.000 registros. Você nunca quer algo fixo e estático. E pode carregar do disco os registros de departamentos e dispor deles em tempo real. Esse é o ponto de fazer isso em C.

 

 

16 horas atrás, codigo rápido disse:

Sim. Percebi isso na função int deleteByIndexInArray(Array *a, int item) , do exemplo do link que passei. Realmente isso não é legal porque fica fazendo copias. Feio... Mas o que você fez de diferente? Não entendi. você simplesmente apagou todo o grupo. E não apenas ou uma sequencia de pessoas quais queres.

 

Escrevi os 3 exemplos para mostrar como criar, carregar, mostrar e gravar no disco todo o conjunto, das 3 maneiras mais comuns. Isso porque eu queria deixar um exemplo online dos 3 casos e de como criar e gravar em disco e ler de volta para testar usando fseek()/ftell() direto no arquivo.

 

Isso que eu escrevi foi só um exemplo, não é minha ideia. É como se faz isso desde sempre. Não entendi o que quiz dizer com "apagou todo o grupo".

 

Em caso de colocar algo assim em produção a primeira coisa a entender é o volume dos dados e as operações mais comuns. Arrays são incrivelmente rápidos, base+descocamento e quase imbatíveis como estrutura exceto por uma tabela hash muito boa.

 

O modo mais eficiente em arrays para isso é claro o Grupo1, porque o vetor é de ponteiros, modestos 4 ou 8 bytes por registro, e aí pode encolher sem grandes sustos. 

 

16 horas atrás, codigo rápido disse:

Não sei se daria certo para mim na maioria dos meus casos, pois geralmente quando gravo dados sobre pessoas, se eu for apagar, eu apago um de cada vez. Não apago todo o grupo de pessoas (array) de uma vez.
No meu entendimento, talvez tenha sido por isso que fez dessa maneira, pois não havendo necessidade de apagar o grupo e sim uma pessoa de cada vez, não precisaria fazer um maloc de cada grupo, como foi feita na sua sugestão.
Em resumo: não estou certo do porque fez o maloc de cada grupo, mas entendo porque fez de cada pessoa.

 

Acho que você não entendeu esse mecanismo ainda. 

 

Você faz malloc() de um grupo porque é o esperto. Demora muito alocar memória. Por isso se escolhe usar um array e não uma lista ligada. E mesmo em listas ligadas muitas vezes se aloca em blocos usando índices de um vetor alocado e não ponteiros para uma pessoa. É muito mais rápido.

 

Eu não apaguei nenhum grupo, nenhuma pessoa exceto na função que apaga... :)  o grupo. Eu não fiz de cada pessoa. Não é assim que funciona.

 

realloc()

 

Entenda que realloc() faz uma cópia para outro endereço quando o sistema achar que precisa. E isso é frequente. Ninguém quer usar realloc(). Nem malloc(). Por isso você dimensiona com muito cuidado esses tamanhos.

 

A outra possibilidade é alocar e gerenciar em páginas, mas aí a complexidade aumenta muito. Estou falando aqui de coisas triviais.

 

 

E você não usava as 3 técnicas em um mesmo programa a menos que esteja escrevendo um programa para fazer exatamente isso, que era o meu caso :D 

 

Eu queria mostrar um exemplo que criasse 3 arquivos usando as 3 técnicas, para um número arbitrário de registros. E foi isso que eu fiz, de modo que você pode criar 3 arquivos com até essas 100.000 pessoas e ver que eles são idênticos no disco.

 

16 horas atrás, codigo rápido disse:

O que quer dizer processos intermediários?

 

Imagine um sistema que a cada 5s coleta os registros que chegaram e faz um processamento, como acrescentando as informações de custo de produto em orçamentos.

 

Você vai processar todos que chegaram nesses 5s, na ordem em que chegaram. Nesse caso o mais eficiente é alocar N+1 ponteiros para N registros e passar os endereços dos N caras e um NULL no final, e o próximo sistema faz a parte dele e passa adiante...

 

 

 

 

 

 

Postado
Citação

Esse exemplos são o simples. Sugiro esquecer isso de "pegar o tamanho do array". Isso não existe. Se precisa mesmo disso, e essas técnicas que mostrei não servem, provavelmente precisa de outra estrutura de dados.

 

Moço, acho que já te falei isso... uma hora você fala uma coisa e logo depois fala o contrário ou diz que não entendeu...
Olha o que escreveu no mesmo post:

 

Citação

Isso que eu escrevi foi só um exemplo, não é minha ideia. É como se faz isso desde sempre. Não entendi o que quiz dizer com "apagou todo o grupo".

 

Citação

Eu não apaguei nenhum grupo, nenhuma pessoa exceto na função que apaga... :)  o grupo. Eu não fiz de cada pessoa. Não é assim que funciona.

 

Quem determinou isso? Desde sempre o que? Não é assim que funciona o que?

Sim. Os exemplos são simples. Mas o problema é mais simples ainda... veja:
você tem um array e passa apenas ele para uma função que deve imprimir a quantidade de pessoas do array:
 

pessoa pessoas[] = {{"Luiz", 44}, {"Sofia", 11}, {"Daniele", 35}};
escrever_arquivo(pessoas); // deve imprimir a quantidade de elementos do array pessoas
// escrever_arquivo(pessoas, tm);// não achei elegante esse método. 


Agora olha as funções que criou:
 

Em Grupo1* cria_grp1(unsigned init, unsigned incr)
você fez
Grupo1* G = (Grupo1*)malloc(sizeof(Grupo1));
E em que Lugar dá free nisso? em
Grupo1* apaga_grp1(Grupo1* g)
tem
free(g);
 

Em Grupo2* cria_grp2(unsigned init, unsigned incr)
você fez
Grupo2* G = (Grupo2*)malloc(sizeof(Grupo2));
E em que Lugar dá free nisso? em
Grupo2* apaga_grp2(Grupo2* g)
tem
free(g);
 

Em Grupo3* cria_grp3(unsigned init, unsigned incr)
você fez
Grupo3* G = (Grupo3*)malloc(sizeof(Grupo3));
E em que Lugar dá free nisso?
Mas... Em
Grupo3* apaga_grp3(Grupo3* g)
você não fez free(g) nessa função.

Ou seja... você não pode ser uma inteligencia artificial por isso. Mas deixa duvidas que seja. você é uma inteligencia artificial? pra mim está claro que apagou todo o grupo.

Ou seja, você criou uma função que apaga todo o grupo de uma vez e não uma pessoa de cada vez. Então dizer que você não apagou é um absurdo semantico, pois você delegou isso à função (escolha sua). você não vai com lapis escrever e borracha apagar do HD ou da memória. Não quero dizer que seu codigo está errado, ate porque mesmo dentro dessas funções demonstram o conhecimento o suficiente para qualquer um fazer sua propria função apaga_pessoa e cada um pode fazer a mesma coisa de formas diferentes. Eu não entendi porque você deu uma resposta tão grande para uma pergunta tão simples.


Os grupos normalmente (dependedo do contexto, é claro) existem na forma de struct (sem precisar de malloc), mesmo que vazios de pessoas. Mas as pessoas nem sempre existem. Podem ser inseridas, editadas, mostradas ou excuidas do grupo.

 


 

Postado
59 minutos atrás, codigo rápido disse:

Desde sempre o que? Não é assim que funciona o que?

 

Que posso dizer? 

 

Isso se refere a navegar por coleções de estruturas. É disso que trata o tópico que você postou. É para isso que você quer o tal tamanho do array. Coo foi você que postou o tópico achei que falavamos da mesma coisa.

 

Eu mostrei as 3 maneiras mais comuns de fazer isso sem criar estruturas adicionais de paginação ou indexação.

 

Pode ter ficado confuso porque mostrei as 3 no mesmo programa e ao mesmo tempo, gerando arquivos a partir de vetores de estruturas criados pelas 3 maneiras distintas.

 

Mas achei que seria um exemplo válido porque o programa pode gerar vetores na memória de até 99.999 pessoas e gravar em disco em 3 arquivos diferentes e você ver que eles são iguais usando o próprio sistema -- diff no Unix/Linux/MacOS ou FC no Windows.

 

Mais ainda, mostrei um programa que abre os arquivos no disco e permite navegar por eles, registro a registro. E numerei os registros sequencialmente. E preenchi com conteúdos reproduzíveis registro a registro.

 

E deixei os fontes completos, os headers separados por grupo de modo que se possa usar só um dos métodos, usando por exemplo modo1.h para o método 1.

 

E deixei uma descrição do programa de testes por parte.

 

E um dump hexa do final de um arquivo.

 

E a saída completa  de uma execução do programa de geração e do programa de navegação no disco.

 

Só não ofereci o lanche nem bebida aos leitores.

 

Só não paguei o lanche e a bebida para os leitores.

 

1 hora atrás, codigo rápido disse:

Ou seja... você não pode ser uma inteligencia artificial por isso. Mas deixa duvidas que seja. você é uma inteligencia artificial? pra mim está claro que apagou todo o grupo

 

Mas essas funções --- achei que estava bem claro pelo nome delas --- são para criar e apagar os grupos, porque era pra ser um exemplo completo. Porque uma função chamada apaga_grp3() não apagaria o tal grupo? O que se pode esperar?

 

Sobre apaga_grp3():

 

em razão, tem um free() a menos. Essas funções foram copiadas uma da outra, claro. E era a última linha e nem vi que não tinha copiado :D bem observado. Essa seria a versão completa:
 

Grupo3*     apaga_grp3(Grupo3* g)
{
    // sem contador apaga ate NULL
    if (g == NULL) return NULL; // vai que...
    int i = 0;
    while (g->pss[i] != NULL) free(g->pss[i++]);
    free(g->pss);
    free(g);
    return NULL;
}

 

 

 

 

Eis o final de main()
 

    mostra_1(grp1);
    grava_1(grp1, "modo1.dat");
    mostra_2(grp2);
    grava_2(grp2, "modo2.dat");
    mostra_3(grp3);
    grava_3(grp3, "modo3.dat");

    grp1 = apaga_grp1(grp1);
    grp2 = apaga_grp2(grp2);
    grp3 = apaga_grp3(grp3);
    return 0;
}

 

Ao final da execução apaga os grupos. Não é o esperado?

 

E essa é a técnica comum.

 

Observe ainda o início:

 

    // cria e mostra 3 grupos
    Grupo1* grp1 = cria_grp1(40, 8);    // inicia com 40
    Grupo2* grp2 = cria_grp2(200, 0);   // não pode aumentar
    Grupo3* grp3 = cria_grp3(10, 20);  // aumenta de 20 em 20

 

Você cria em uma função que devolve um ponteiro, e uma outra função apaga e devolve um ponteiro, que é sempre NULL pela simples razão de poder invalidar o ponteiro em C no retorno...

 

E na criação você especifica o tamanho inicial do bloco de ponteiros, o tamanho de cada bloco de incremento (ou zero para garantir que não há expansão), e em muitos casos por sanidade também um limite que tamanho para o vetor. É o seguro e mais fácil de controlar porque não fica nada estático. A própria criação do vetor de pessoas é feita com cópias e não com os dados fornecidos.

 

Recomendo mesmo rodar e entender esse exemplo, ou separar apenas o grupo que achar mais conveniente para seu caso.

 

1 hora atrás, codigo rápido disse:

Então dizer que você não apagou é um absurdo semantico, pois você delegou isso à função (escolha sua). você não vai com lapis escrever e borracha apagar do HD ou da memória. 

 

:( Acho que não consegui explicar a motivação. 

 

Escrevi um exemplo, não só para você. Um exemplo do que eu expliquei que estava mostrando: como navegar por um vetor de estruturas na memória, em C, das 3 maneiras comuns. E como gravar em disco. E como ler do disco. 

 

Isso a partir de um tópico que buscava passar o tamanho de um array para uma função que faria exatamente o que eu mostrei... E eu expliquei que isso não funciona. E porque não funciona.

 

 

1 hora atrás, codigo rápido disse:

Não quero dizer que seu codigo está errado, ate porque mesmo dentro dessas funções demonstram o conhecimento o suficiente para qualquer um fazer sua propria função apaga_pessoa e cada um pode fazer a mesma coisa de formas diferentes. Eu não entendi porque você deu uma resposta tão grande para uma pergunta tão simples

 

O código que eu postei não está errado. Ou ao menos não creio que esteja. E você encontrou um erro na função que apaga porque eu não testei isso com ferramentas que eu usaria se fosse colocar em produção. É um exemplo para o forum que eu levei muito mais tempo para escrever o texto do que os programas.

 

Mas entenda: eu não escrevi nenhuma função para apagar registros, Pessoa no seu caso. E eu expliquei em outro post o porque.

 

Eu te disse como fazer. E seria trivial. Só que sua pergunta não era essa.

 

Eis o que está escrito acima pelo autor do tópico

image.png.9774fdd7d51d1b24ec491e409e422e3c.png

 

e é uma questão super válida para iniciantes e mesmo desenvolvedores que não tem familiaridade com ponteiros, gravação de arquivos e uso de fseek() e ftell() e fread() para acesso a arquivos em C.

 

Foi por isso que me dei ao trabalho de escrever isso "tudo", uma resposta "tão grande para uma pergunta tão simples".

 

De todo modo sugiro incorporar as coisas que eu longamente expliquei ao seu programa inicial.

 

Como apagar registros de um vetor de estruturas

 

Esse pode ser seu próximo tópico e pode conseguir respostas nesse sentido.

 

O que posso dizer sobre isso agora só pra ajudar?

 

Além do que eu já expliquei nos primeiros posts, como no #8

 

image.png.3248ec57e16f0e7a4dbca4a210d72e95.png

 

desse tópico: use a opção 1, um vetor de ponteiros para struct, e ao apagar um registro desloque os ponteiros no vetor.  São apenas 4 ou 8 bytes e é super rápido e cache-friendly.

 

Nunca use a opção que usou, em que o vetor é de estruturas, porque apagar uma struct seria abrir um buraco potencialmente maior e ficaria muito mais lento.

 

Posso te mostrar um exemplo, usando claro os programas que já escrevi e o tal Grupo1 e claro que acabaria em algo assim:

 

    int     apaga_1(Pessoa* uma, Grupo1* grupo);

 

Que apaga uma pessoa do grupo e retorna 0 se apagou um um código negativo de erro, por exemplo quando a pessoa não existe no grupo.

 

1 hora atrás, codigo rápido disse:

Os grupos normalmente (dependedo do contexto, é claro) existem na forma de struct (sem precisar de malloc), mesmo que vazios de pessoas. Mas as pessoas nem sempre existem. Podem ser inseridas, editadas, mostradas ou excuidas do grupo

 

Isso eu não entendi. O grupo é o vetor de estruturas. Sem malloc() eles teriam que ser estáticos e seria provavelmente inútil. Um grupo vazio sem malloc() seria vazio para todo o sempre, ou não? Se teria o espaço todo já alocado mais uma vez seria provavelmente inútil.

 

Pense bem no que está tentando escrever. Se você declarar

 

    Pessoa		grupo[10000]; // 10 mil pessoas. Vazio?

 

Vai declarar no seu caso um vetor de 60K. E ponto final. Com ou sem pessoas. E pode dizer que será um vetor de 60K vazio. Não para o compilador. E se colocar 5.000 caras lá e apagar um em cada 10 vai acontecer o que expliquei acima e no tópico 8.

 

 

 

 

 

 

 

Postado
3 horas atrás, arfneto disse:

Só não ofereci o lanche nem bebida aos leitores.

 

Só não paguei o lanche e a bebida para os leitores.


Eu não te pedi nada além de coerencia.
E lhe agradeci muito pelo pelo navegador que postou.
Mas isso não lhe dá direito nenhum de falar assim com ninguem.
 

Citação

Eu te disse como fazer. E seria trivial. Só que sua pergunta não era essa.


Era essa sim. E eu ainda repeti em #5. Mas a pergunta é tão compreensivel que logo no primeiro post que fiz o usuário Flavio Pedroza entendeu e respondeu rapidamente eu eu já lhe dei like e o atribui como o solucionador do problema. Por isso que quero saber se você é uma inteligencia artificial. porque por ética, você, como robo do forum é obrigado a dizer se é ou não.

deixa eu te explicar o que aconteceu...
você veio e disse que tinha uma forma de fazer. fez um post gigante #8 e eu para não te deixar no vácuo, postei um link de um post meu #9, que é mais antigo a esses seus posts pra te dar uma dica que desse modo eu sabia como pegar o tamanho de arrays. Eu tava tentando ser gente boa contigo, pra não te deixar no vácuo porque tava sendo legal ao mostrar seu navegador, que eu já lhe agradeci.

 

 

Citação

De todo modo sugiro incorporar as coisas que eu longamente expliquei ao seu programa inicial.

 

Como apagar registros de um vetor de estruturas

 

Esse pode ser seu próximo tópico e pode conseguir respostas nesse sentido.

 

O que posso dizer sobre isso agora só pra ajudar?


Ok. Mas eu não to aqui pra usar ctrl+c + ctrl+v. Eu to aqui para entender e criar meus proprios metodos. No link que eu passei, mostra que eu já fiz o equivalente. porque eu iria fazer um post como esse?
 

Citação

e é uma questão super válida para iniciantes e mesmo desenvolvedores que não tem familiaridade com ponteiros, gravação de arquivos e uso de fseek() e ftell() e fread() para acesso a arquivos em C.

 

Foi por isso que me dei ao trabalho de escrever isso "tudo", uma resposta "tão grande para uma pergunta tão simples".


ok... sua suposição foi boa porque foi além do esperado. Mas não tente advinhar o que um usuário quer fazer a partir de uma pergunta simples.

Citação

E eu expliquei que isso não funciona. E porque não funciona.

ok! Desculpa. falou sim. Mas o porque não funciona, eu não vi, ou não entendi. Se se refere ao que disse que o compilador não sabe o tamanho do registro que irá receber como parametro, isso não é uma resposta que explica o porque.

Postado

Isso é só pra demonstrar que o tamanho na declaração do array não deveria ser importante para a função que recebe o parametro:
 

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

typedef struct
{
	char nome[50];
	int idade;
} pessoa;

int s1(pessoa pessoas[])
{
	printf("----------------------------------\n");
	int i=0;
	for(; pessoas[i].idade!=NULL; i++)
	{
		//printf("Nome: %s Idade:%i\n", pessoas[i].nome, pessoas[i].idade);
	}
	printf("Tamanho: %i \n", i);
	return 0;
}

int main()
{
	pessoa pessoas1[] = {{"Luiz", 44}, {"Sofia", 11}, {"Daniele", 35}, {NULL, NULL}};
	s1(pessoas1);

	pessoa pessoas2[] = {{"Maria", 70}, {"Gabriel", 15}, {"Samuel", 11}, {"Luiz", 44}, {"Sofia", 11}, {"Daniele", 35}, {NULL, NULL}};
	s1(pessoas2);
	return 0;
}

 

E funciona.
Só que é feio porque sou obrigado a fazer um while... de alguma forma outras linguagens fazem isso de forma invisivel.
E é feito porque tenho que utilizar um marcador com a struct com NULLs...

Postado

image.png.549b543d3fd083a1be4174d26f39aecf.png

 

9 horas atrás, codigo rápido disse:

Eu não te pedi nada além de coerencia.
E lhe agradeci muito pelo pelo navegador que postou.
Mas isso não lhe dá direito nenhum de falar assim com ninguem

 

Isso de retirar uma frase do contexto e publicar só um minúsculo trecho com o propósito de reforçar algo, e que não estava no texto original, é comum em política. Citar a frase duas vezes em seguida talvez seja para reforçar a ideia.

 

Vou colocar o parágrafo todo:
 

Mas achei que seria um exemplo válido porque o programa pode gerar vetores na memória
  de até 99.999 pessoas e gravar em disco em 3 arquivos diferentes e você ver que eles
  são iguais usando o próprio sistema -- diff no Unix/Linux/MacOS ou FC no Windows.
Mais ainda, mostrei um programa que abre os arquivos no disco e permite navegar por eles,
registro a registro. E numerei os registros sequencialmente. E preenchi com conteúdos
  reproduzíveis registro a registro.
E deixei os fontes completos, os headers separados por grupo de modo que se possa usar
  só um dos métodos, usando por exemplo modo1.h para o método 1.
E deixei uma descrição do programa de testes por parte.
E um dump hexa do final de um arquivo.
E a saída completa  de uma execução do programa de geração e do programa de navegação no disco.
Só não ofereci o lanche nem bebida aos leitores. 

Só não paguei o lanche e a bebida para os leitores.

 

Me desculpe se essa linha te ofendeu.

 

E peço que leia isso no contexto em que eu escrevi, e o contexto está no post e reproduzido acima.

E ao citar tenha o cuidado de citar o parágrafo, um mínimo do contexto. Eu de fato deixei tudo aquilo que eu disse que deixei. Está lá. E a última linha era algo para ser engraçada e não ofensiva, e o sentido era dizer que eu não escrevi mais porque já tinha uma lista de coisas lá. 

 

E você disse que a resposta era muito longa.

 

Sobre seu código

 

8 horas atrás, codigo rápido disse:

Isso é só pra demonstrar que o tamanho na declaração do array não deveria ser importante para a função que recebe o parametro

 

8 horas atrás, codigo rápido disse:

E funciona.
Só que é feio porque sou obrigado a fazer um while... de alguma forma outras linguagens fazem isso de forma invisivel.
E é feito porque tenho que utilizar um marcador com a struct com NULLs

 

Eu te mostrei como fazer isso de "forma invisível"... De duas maneiras ao menos. E é a mesma forma que essas outras linguagens usam . Se chama encapsulamento. malloc() em C faz isso criando uma estrutura que descreve o bloco alocado, por exemplo.

 

int s1(pessoa pessoas[])
{
	printf("----------------------------------\n");
	int i=0;
	for(; pessoas[i].idade!=NULL; i++)
	{
		//printf("Nome: %s Idade:%i\n", pessoas[i].nome, pessoas[i].idade);
	}
	printf("Tamanho: %i \n", i);
	return 0;
}

 

Eu já expliquei isso, mas vou explicar de novo no contexto de sua função: não é o caso de ser "feio". Não tem sentido usar um loop toda vez e percorrer a estrutura inteira na função para saber o tamanho, exceto em casos em que seja de fato preciso fazer isso sempre, como te expliquei --- e você não tinha entendido inicialmente --- no caso de um processo intermediário.

 

Todo o sentido de usar um array é acessar diretamente um elemento, porque é a melhor performance possível. 

 

Eu te expliquei como funciona em java por exemplo. E deixei o link para a página do manual.

 

Sua função funciona, mas segundo seu próprio julgamento. Teste com suas 10.000 pessoas e vai descobrir rapidamente que não tem performance adequada. Simule, meça, tabele. A cada acesso em busca de um elemento acha mesmo que vai usar um loop antes para ir até o fim para saber quantas pessoas tem lá?  Seu exemplo tem 4 e 6 elementos

 

int main()
{
	pessoa pessoas1[] = {
	{"Luiz", 44},
    {"Sofia", 11},
    {"Daniele", 35},
    {NULL, NULL}
};
	s1(pessoas1);

	pessoa pessoas2[] = {
    {"Maria", 70},
    {"Gabriel", 15},
    {"Samuel", 11},
    {"Luiz", 44},
    {"Sofia", 11},
    {"Daniele", 35},
    {NULL, NULL}
    };
	s1(pessoas2);
	return 0;
}

 

Teste como eu te mostrei, com 100.000 pessoas por exemplo. Para uma certo número de acessos, digamos 1.000 acessos, teste isso que escreveu e o tal Grupo1 e o Grupo2 que te mostrei, e compare os tempos. É o que se faz na prática. E aí poste os tempos e ficará claro o quanto funciona.

 

 

 

 

14 horas atrás, codigo rápido disse:

Ou seja, você criou uma função que apaga todo o grupo de uma vez e não uma pessoa de cada vez. Então dizer que você não apagou é um absurdo semantico, pois você delegou isso à função (escolha sua). você não vai com lapis escrever e borracha apagar do HD ou da memória. Não quero dizer que seu codigo está errado, ate porque mesmo dentro dessas funções demonstram o conhecimento o suficiente para qualquer um fazer sua propria função apaga_pessoa e cada um pode fazer a mesma coisa de formas diferentes

 

9 horas atrás, codigo rápido disse:

Ok. Mas eu não to aqui pra usar ctrl+c + ctrl+v. Eu to aqui para entender e criar meus proprios metodos. No link que eu passei, mostra que eu já fiz o equivalente. porque eu iria fazer um post como esse?

 

Você está discutindo sobre como apagar pessoas, as structs do array, e por isso eu sugeri que abrisse um tópico sobre isso especificamente

 

De todo modo ainda te dei várias respostas e sugestões de como fazer isso.

 

12 horas atrás, arfneto disse:

 

Isso a partir de um tópico que buscava passar o tamanho de um array para uma função que faria exatamente o que eu mostrei... E eu expliquei que isso não funciona. E porque não funciona.

 

 

9 horas atrás, codigo rápido disse:

ok! Desculpa. falou sim. Mas o porque não funciona, eu não vi, ou não entendi. Se se refere ao que disse que o compilador não sabe o tamanho do registro que irá receber como parametro, isso não é uma resposta que explica o porque.

 

Vamos focar nos códigos. Estou escrevendo sobre como iterar em um vetor de estruturas, o tópico em questão.

 

Acima eu expliquei mais uma vez com a própria função que você postou. 

 

  • Curtir 1

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...