Array de struct pode ter tamanho 0? [RESOLVIDO]

1. Array de struct pode ter tamanho 0? [RESOLVIDO]

João Paulo
princknoby

(usa Arch Linux)

Enviado em 11/12/2019 - 20:36h

Olá a todos, recentemente comecei a estudar structs em C... Então comecei a brincar um pouco com isso, não sou nenhum profissional, apenas um estudando, não tenho intenção em colocar este programa em linha de produção(não sou louco), só estou me divertindo mesmo.

Estou fazendo um programa para inserir dados de clientes em um "banco de dados" <- no caso a memória RAM rsrss

Vou deixar aqui o código do programa


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

struct dadosCliente {
char nome[100], endereco[100], CPF[20], dataNascimento[11];
};
typedef struct dadosCliente Cliente;
/*agora o comando struct dadosCliente
pode ser chamado apenas de -> Cliente
*/

void bufferClear() {
int ch;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF);
}

int menu(int option) {
system("clear");
printf("\tBEM VINDO\n\n");
printf("Digite 1 para inserir um cliente no banco de dados\n");
printf("Digite 2 para mostrar todos os clientes no bando de dados\n");
printf("Digite 0 para sair\n");

printf("\nDigite a opcao desejada: ");
scanf("%d", &option);
bufferClear();

return option;
}

void inserirDados(Cliente *dados) {
system("clear");
printf("Digite o nome do(a) cliente: ");
scanf("%99[^\n]", dados -> nome);
//dados->nome é equivalente a: (*dados).nome
bufferClear();

printf("Digite a data de nascimento de '%s': ", (*dados).nome);
scanf("%10[^\n]", dados -> dataNascimento);
bufferClear();

printf("Digite o CPF de '%s': ", (*dados).nome);
scanf("%19[^\n]", (*dados).CPF);
bufferClear();

printf("Digite o endereco de '%s': ", (*dados).nome);
scanf("%99[^\n]", (*dados).endereco);
bufferClear();
}

void mostrarClientes(Cliente *dados, int tamVet) {
system("clear");
printf("----------------------------------------------------------\n");
printf("\tClientes cadastrados\n");
printf("----------------------------------------------------------\n\n");

for (int i = 0; i < tamVet - 1; i++) {
printf("----------------------------------------------------------\n");
printf("Nome: %s\nEndereco: %s\nCPF: %s\nData de nascimento: %s\n", dados[i].nome, dados[i].endereco, dados[i].CPF, dados[i].dataNascimento);
printf("----------------------------------------------------------\n\n");
}
scanf ("%*c");
}

void sair () {
printf ("Pressione [ENTER] para encerrar o programa...");
scanf ("%*c");
}

int main(void) {
int tamVet = 1, option;
Cliente dados[tamVet];

do {
option = menu(option);
if (option == 1) {
inserirDados(&dados[tamVet-1]); //como vamos usar ponteiros devemos usar o '&'
//Usamos tamVet -1 pois essa se refere a uma posicao do vetor
//O vetor inicialmente tem tamanho 1
//Ou seja, possui duas posições -> 0 e 1
//Precisamos modificar primeiro a posicao 0
//Por isso passamos a posicao [tamVet - 1]
printf("\nCLIENTE '%s' INSERIDO(A) COM SUCESSO!\n", dados[tamVet-1].nome);
printf ("Pressione [ENTER] para continuar...");
scanf ("%*c");
system("clear");
tamVet++; //aumentamos o tamanho do vetor para podermos adicionar novos clientes
} else if (option == 2) {
mostrarClientes(dados, tamVet);
} else if (option == 0) {
break;
} else {
printf ("OPCAO INVALIDA!\n");
printf ("Pressione [ENTER] para tentar uma nova opcao...");
scanf ("%*c");
}

} while (option != 0);

printf ("Saindo do programa....\n");
sair();

return 0;
}


Minha duvida é referente ao seguinte trecho:

int tamVet = 1, option;
Cliente dados[tamVet];
do {
option = menu(option);
if (option == 1) {
inserirDados(&dados[tamVet-1]);
....
} while(...)


Eu criei um vetor pra poder adicionar quantas pessoas eu desejar, e sempre que o usuario escolhe a opcao de adicionar um cliente, eu aumento o tamanho desse vetor (variavel tamVet).
Minha dúvida é a seguinte, um vetor tem como primeira posição posição 0, correto?
Porém quando coloco o tamanho inicial do vetor como 0 (uma única posição), ao chamar a função para inserir os dados do cliente, eu insiro os dados, mas a função retorna com erro de segmentação.

Porém se eu coloco o tamanho inicial do vetor como 1, a função retorna sem nenhum erro, porém tenho que fazer a chamada da função da seguinte forma:
inserirDados(&dados[tamVet -1]); pois se eu chamo a função somente com: inserirDados(&dados[tamVet]); a posição 0 (1º posição) fica sem nada, já que eu passo os dados para a o posição 1 do vetor (2º posição).

Meu raciocínio está correto?
Alguém poderia por favor me explicar porque isso está acontecendo? Chamar a função tendo que subtrair 1, não está me agradando, fica parecendo uma "gambiarra".

Obrigado


  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 13/12/2019 - 02:22h

princknoby escreveu:

Eu criei um vetor pra poder adicionar quantas pessoas eu desejar, e sempre que o usuario escolhe a opcao de adicionar um cliente, eu aumento o tamanho desse vetor (variavel tamVet).
Minha dúvida é a seguinte, um vetor tem como primeira posição posição 0, correto?
Porém quando coloco o tamanho inicial do vetor como 0 (uma única posição), ao chamar a função para inserir os dados do cliente, eu insiro os dados, mas a função retorna com erro de segmentação.

Porém se eu coloco o tamanho inicial do vetor como 1, a função retorna sem nenhum erro, porém tenho que fazer a chamada da função da seguinte forma:
inserirDados(&dados[tamVet -1]); pois se eu chamo a função somente com: inserirDados(&dados[tamVet]); a posição 0 (1º posição) fica sem nada, já que eu passo os dados para a o posição 1 do vetor (2º posição).

Meu raciocínio está correto?


Parece que aqui você confundiu as duas coisas. O fato do primeiro índice ser zero não significa que um array que só tenha um elemento de de ser declarado com tamanho zero. Você declara o array com o número de elementos que ele deve ter, e os índices válidos para elementos desse array tem de ser um inteiro não-negativo, em que o índice 0 corresponde ao primeiro elemento, o índice 1, ao segundo elemento, o índice 2, ao terceiro elemento, ..., o índice N-1, ao N-ésimo elemento.

Isso pode parecer estranho à primeira vista, mas com certeza você já viu isso antes. Por exemplo, pense no conjunto dos números naturais, N={0, 1, 2, 3, 4, 5, ...}. Qual o primeiro elemento desse conjunto? Não é o 0? Ou pense numa régua. Qual a primeira indicação marcada na régua? Não é o centímetro 0? Pense num cronômetro. Ele começa a marcar a partir de que valor? Não é de 0.0 segundos? E já reparou que o primeiro segundo decorrido desde que você dispara o cronômetro termina justamente quando se atinge a marca de 1.0 segundo? Já notou que o primeiro ano de vida de um bebê termina quando ele completa um ano, e justamente no seu aniversário de um ano de vida começa o segundo ano de vida? Ou que o seu vigésimo ano de vida termina no dia em que você completa (note o verbo “completar”) 20 anos?

Em C, o que acontece é mais ou menos a mesma coisa. Aliás, eu acho o exemplo da régua particularmente bom porque ele permite uma analogia direta com o que acontece com a memória. Quando você pede para alocar um array com N elementos, o programa lhe entrega um conjunto de bytes correspondentes a cada elemento. Vamos supor que N seja 20, no nosso caso, e imagine que, para representar esses 20 elementos, você tem uma tira retangular dividida em 20 quadradinhos de mesmo tamanho, um ao lado do outro. E imagine que, como numa régua, você escreve um 0 na margem esquerda, e números sucessivos a cada divisão que separa um quadrado do quadrado seguinte.

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Imagine que cada elemento está contido no espaço dentro do quadrado. Qual o deslocamento existente entre o início da memória reservada para o array (o lado esquerdo da fita) e o início da memória ocupada exclusivamente pelo primeiro elemento? E qual o deslocamento você terá entre o início da memória reservada para o array inteiro e o início do segundo elemento (que também pode ser pensado, e isso é amplamente usado na literatura e em bibliotecas de software, como “após o final do primeiro elemento” ou “após se completar o primeiro elemento”)? E você notou que o deslocamento que ainda indica o começo do último elemento que está dentro da fita é o deslocamento 19, e que o deslocamento 20 já seria correspondente a uma posição que não está mais compreendida dentro da fita?

O que acontece com arrays em C é muito parecido com o caso da fita. Quando você declara um array, o compilador reserva (ou gera código que reserva) uma “fita”, cujo tamanho total é igual ao número de elementos que consta na declaração vezes o tamanho de cada elemento (todos os elementos, sendo do mesmo tipo, têm necessariamente o mesmo tamanho). Após a declaração, toda vez que você usa o array e lhe aplica um índice, o compilador entende que você faz uma referência à posição inicial na memória (o array) e aplica um deslocamento (o índice inteiro) para determinar a posição de início do elemento correspondente.

Alguém poderia por favor me explicar porque isso está acontecendo? Chamar a função tendo que subtrair 1, não está me agradando, fica parecendo uma "gambiarra".


Tentei. Espero que tenha ajudado.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)

P.S.
Eu não sei se você se confundiu por causa de experiências anteriores com outras linguagens de programação. Fortran, por exemplo, usa índices de 1 até N para representar os elementos de um array declarado com tamanho N, de uma forma em que o valor cardinal do índice corresponde numericamente ao seu valor ordinal (1 para 1º, 2 para 2º, etc.).

BASIC faz algo bem diferente: quando você usa o comando DIM (de dimension, que poderia ser traduzido tanto como o substantivo “dimensão” quanto pelo comando verbal “dimensione”), você não diz realmente qual o tamanho, mas sim qual o último índice válido. Como os índices começam em 0, o comando “DIM A(10)”, por exemplo, faz com que A tenha onze elementos, em vez de dez (algumas variações do BASIC têm um comando para trocar globalmente o primeiro índice para 1, em vez de 0, deixando-a, nesse aspecto, parecida com Fortran, mas eu raramente vi isso ser usado, e, se usado fosse, corria-se o risco de deixar os acessos mais lentos).

Pascal, por sua vez, tem outra abordagem: cada array tem de especificar quais os valores iniciais e finais de índices válidos que ele pode aceitar, e os índices podem ser de qualquer tipo ordinal suportado pela linguagem, o que inclui inteiros e caracteres, como no C, mas também conjuntos ordenados arbitrários definidos pelo programador (cujo análogo mais próximo em C, embora ainda bastante diferente, são enumerações). A quantidade total de elementos é dada pelo valor da expressão (em Pascal) “1+ord(indice_final)-ord(indice_inicial)”.

A maior parte das linguagens em uso comum hoje (ou, pelo menos, dentre aquelas de que já ouvi falar), tais como C++, Java, C#, Python, PHP, Perl, Ruby e o próprio Assembly (ou suas variantes em que existem instruções voltadas para dados armazenados sequencialmente), no entanto, parecem fazer mais ou menos como o C; isto é: o primeiro elemento tem índice 0, e o número total de elementos do array é cardinalmente igual ao valor do último índice válido mais um.

3. Re: Array de struct pode ter tamanho 0? [RESOLVIDO]

João Paulo
princknoby

(usa Arch Linux)

Enviado em 13/12/2019 - 20:28h


paulo1205 escreveu:

princknoby escreveu:

Eu criei um vetor pra poder adicionar quantas pessoas eu desejar, e sempre que o usuario escolhe a opcao de adicionar um cliente, eu aumento o tamanho desse vetor (variavel tamVet).
Minha dúvida é a seguinte, um vetor tem como primeira posição posição 0, correto?
Porém quando coloco o tamanho inicial do vetor como 0 (uma única posição), ao chamar a função para inserir os dados do cliente, eu insiro os dados, mas a função retorna com erro de segmentação.

Porém se eu coloco o tamanho inicial do vetor como 1, a função retorna sem nenhum erro, porém tenho que fazer a chamada da função da seguinte forma:
inserirDados(&dados[tamVet -1]); pois se eu chamo a função somente com: inserirDados(&dados[tamVet]); a posição 0 (1º posição) fica sem nada, já que eu passo os dados para a o posição 1 do vetor (2º posição).

Meu raciocínio está correto?


Parece que aqui você confundiu as duas coisas. O fato do primeiro índice ser zero não significa que um array que só tenha um elemento de de ser declarado com tamanho zero. Você declara o array com o número de elementos que ele deve ter, e os índices válidos para elementos desse array tem de ser um inteiro não-negativo, em que o índice 0 corresponde ao primeiro elemento, o índice 1, ao segundo elemento, o índice 2, ao terceiro elemento, ..., o índice N-1, ao N-ésimo elemento.

Isso pode parecer estranho à primeira vista, mas com certeza você já viu isso antes. Por exemplo, pense no conjunto dos números naturais, N={0, 1, 2, 3, 4, 5, ...}. Qual o primeiro elemento desse conjunto? Não é o 0? Ou pense numa régua. Qual a primeira indicação marcada na régua? Não é o centímetro 0? Pense num cronômetro. Ele começa a marcar a partir de que valor? Não é de 0.0 segundos? E já reparou que o primeiro segundo decorrido desde que você dispara o cronômetro termina justamente quando se atinge a marca de 1.0 segundo? Já notou que o primeiro ano de vida de um bebê termina quando ele completa um ano, e justamente no seu aniversário de um ano de vida começa o segundo ano de vida? Ou que o seu vigésimo ano de vida termina no dia em que você completa (note o verbo “completar”) 20 anos?

Em C, o que acontece é mais ou menos a mesma coisa. Aliás, eu acho o exemplo da régua particularmente bom porque ele permite uma analogia direta com o que acontece com a memória. Quando você pede para alocar um array com N elementos, o programa lhe entrega um conjunto de bytes correspondentes a cada elemento. Vamos supor que N seja 20, no nosso caso, e imagine que, para representar esses 20 elementos, você tem uma tira retangular dividida em 20 quadradinhos de mesmo tamanho, um ao lado do outro. E imagine que, como numa régua, você escreve um 0 na margem esquerda, e números sucessivos a cada divisão que separa um quadrado do quadrado seguinte.

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Imagine que cada elemento está contido no espaço dentro do quadrado. Qual o deslocamento existente entre o início da memória reservada para o array (o lado esquerdo da fita) e o início da memória ocupada exclusivamente pelo primeiro elemento? E qual o deslocamento você terá entre o início da memória reservada para o array inteiro e o início do segundo elemento (que também pode ser pensado, e isso é amplamente usado na literatura e em bibliotecas de software, como “após o final do primeiro elemento” ou “após se completar o primeiro elemento”)? E você notou que o deslocamento que ainda indica o começo do último elemento que está dentro da fita é o deslocamento 19, e que o deslocamento 20 já seria correspondente a uma posição que não está mais compreendida dentro da fita?

O que acontece com arrays em C é muito parecido com o caso da fita. Quando você declara um array, o compilador reserva (ou gera código que reserva) uma “fita”, cujo tamanho total é igual ao número de elementos que consta na declaração vezes o tamanho de cada elemento (todos os elementos, sendo do mesmo tipo, têm necessariamente o mesmo tamanho). Após a declaração, toda vez que você usa o array e lhe aplica um índice, o compilador entende que você faz uma referência à posição inicial na memória (o array) e aplica um deslocamento (o índice inteiro) para determinar a posição de início do elemento correspondente.

Alguém poderia por favor me explicar porque isso está acontecendo? Chamar a função tendo que subtrair 1, não está me agradando, fica parecendo uma "gambiarra".


Tentei. Espero que tenha ajudado.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)

P.S.
Eu não sei se você se confundiu por causa de experiências anteriores com outras linguagens de programação. Fortran, por exemplo, usa índices de 1 até N para representar os elementos de um array declarado com tamanho N, de uma forma em que o valor cardinal do índice corresponde numericamente ao seu valor ordinal (1 para 1º, 2 para 2º, etc.).

BASIC faz algo bem diferente: quando você usa o comando DIM (de dimension, que poderia ser traduzido tanto como o substantivo “dimensão” quanto pelo comando verbal “dimensione”), você não diz realmente qual o tamanho, mas sim qual o último índice válido. Como os índices começam em 0, o comando “DIM A(10)”, por exemplo, faz com que A tenha onze elementos, em vez de dez (algumas variações do BASIC têm um comando para trocar globalmente o primeiro índice para 1, em vez de 0, deixando-a, nesse aspecto, parecida com Fortran, mas eu raramente vi isso ser usado, e, se usado fosse, corria-se o risco de deixar os acessos mais lentos).

Pascal, por sua vez, tem outra abordagem: cada array tem de especificar quais os valores iniciais e finais de índices válidos que ele pode aceitar, e os índices podem ser de qualquer tipo ordinal suportado pela linguagem, o que inclui inteiros e caracteres, como no C, mas também conjuntos ordenados arbitrários definidos pelo programador (cujo análogo mais próximo em C, embora ainda bastante diferente, são enumerações). A quantidade total de elementos é dada pelo valor da expressão (em Pascal) “1+ord(indice_final)-ord(indice_inicial)”.

A maior parte das linguagens em uso comum hoje (ou, pelo menos, dentre aquelas de que já ouvi falar), tais como C++, Java, C#, Python, PHP, Perl, Ruby e o próprio Assembly (ou suas variantes em que existem instruções voltadas para dados armazenados sequencialmente), no entanto, parecem fazer mais ou menos como o C; isto é: o primeiro elemento tem índice 0, e o número total de elementos do array é cardinalmente igual ao valor do último índice válido mais um.


Entendi perfeitamente!

Eu realmente estava embaralhando a mente em alguns conceitos aqui...

Muitíssimo obrigado!






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts