Como fazer uma Lista MUITO Simples em C? [RESOLVIDO]

1. Como fazer uma Lista MUITO Simples em C? [RESOLVIDO]

Nick Us
Nick-us

(usa Slackware)

Enviado em 23/02/2019 - 01:27h

Vou explicar o meu problema. Pense na seguinte variável abaixo, Pois é a idéia do que preciso!
char *List1[] = {"Slackware 1", "Slackware 2", "Slackware 3", "Slackware 4"}; 

Meu objetivo é simples. Eu quero criar uma lista (Tipo 3 nomes, ou 10 nomes).
O Problema que estou tendo é que:
1) Não sei o tamanho dessa lista. Ela pode ter 400 Mil linhas, ou apenas 3 linhas.
2) Não sei a Qtd de Caracteres que essa linha terá, pode ser 20 caracteres ou 40 mil caracteres.

Pensei em usar ponteiro como no exemplo acima, pq pareceu melhor do que um vetor de caracteres. Isso porque vou precisar depois comparar determinada linha dessa lista com a linha de outra... Mas isso não é minha dúvida agora!

Minha dificuldade está na seguinte situação! Eu consigo atribuir valores a ela no código abaixo: Porém não serve isso pra mim!
   List1[0] = "Bom dia 1";
List1[1] = "Bom dia 2";
List1[2] = "Bom dia 3";
List1[3] = "Bom dia 4";


O que eu quero e não sei fazer:
1) Quero declarar a Lista VAZIA mas minha idéia abaixo não funciona
char *List1[]; 


2) Quero adicionar items a minha lista através de uma variável tipo como abaixo que também não funciona
MINHA_VARIAVEL do tipo char (Lembrando não tem um tamanho fixo como informei acima, na verdade o valor dela é a linha que pego de um arquivo)
   List1[0] = MINHA_VARIAVEL;
List1[1] = MINHA_VARIAVEL;


Agora Resumindo o que estou fazendo! Eu tenho 1 arquivo atual com 300 mil linhas onde juntei listas do Adblock. Eu leio cada linha desse arquivo e vou enviando para a minha PRIMEIRA Lista, caso a linha exista nessa lista meu programa vai gravar na outra lista. Que dei os nomes: No_Duplicados e Duplicados.
No FIM ao acabar de ler o arquivo, meu programa vai GRAVAR essas 2 listas em 2 arquivos diferentes!

Eu não quis gravar direto em arquivos linha a linha pq não consegui fazer, pois apenas entendi que pra gravar no arquivo eu teria que fechar ele, o que resultaria que eu estaria mechendo no meu HD Linha a Linha ou seja 300 mil vezes.... Pois eu não consegui por não saber, como eu conseguiria LER o arquivo se ele ainda nem foi gravado, pois a variável onde mandei gravar não mostrava nada!

Motivo pelo qual, pensei em criar essas 2 Listas Temporárias na memoria e gravar apenas ao terminar o trabalho no arquivo.

Eu tinha usado por exemplo:
fputs(Line_File, File_Duplicates);

Porém não conseguia em código sequer imprimir pra ver o que foi feito! Somente ao fechar o arquivo os dados estavam lá.
Alguém pode ajudar? Ou alguém tem alguma idéia do que posso fazer? Se posso trabalhar direto com arquivo sem sobrecarregar gravação no HD, ou se minha opção por variável como eu disse acima seria melhor?

Meu FOCO GERAL é: Ler esse meu arquivo de 300 mil linhas, enviar somente as linhas sem duplicidade para 1, e outro arquivo com as duplicidades (Sem repetir linhas iguais)

Ainda estou aprendendo a entender melhor Ponteiros, como mandar um valor do tipo vetor para um ponteiro e etc...
Pois os exemplos na internet só falam em inteiros, e claro uma letrinha só fica fácil mas não me ajuda a entender como usar mais que isso.

Mostrando 2 exemplos. Esse abaixo funciona:
#include <stdio.h>
void main () {
int Qtd_Linhas = 5;
char Simples[18] = "Slackware Simples";
char *List[Qtd_Linhas];

for (int i = 0; i < Qtd_Linhas; i++) {
List[i] = Simples; // NÃO SEI se isso é correto de se fazer!
printf("List = %s\n", List[i]);
}
}


Isso não funciona!
#include <stdio.h>
void main () {
int Qtd_Linhas = 0;
char Simples[18] = "Slackware Simples";
char *List[Qtd_Linhas];

Qtd_Linhas = 5; // ISSO NÃO FUNCIONA ele não aceita eu informar as linhas depois. Tipo MODIFICAR
for (int i = 0; i < Qtd_Linhas; i++) {
List[i] = Simples;
printf("List = %s\n", List[i]);
}
}


Fiquei sem saber se SOU OBRIGADO a tratar essa linha
char *List[Qtd_Linhas]; 

Antes de declarar ela, ou seja saber o valor dela.
Ou se posso não saber o valor e declarar ela e aumentar conforme o uso!


  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 23/02/2019 - 17:20h

Lista geralmente dá a entender uma estrutura de dados em que cada elemento colocado na lista, chamado de nó, tem um apontamento para o próximo nó.
typedef /* ... alguma coisa... */ conteudo;
struct no_lista {
conteudo valor;
struct no_lista *proximo_no;
struct no_lista *no_anterior; /* Algumas listas não têm informação sobre nó anterior. */
};

typedef struct lista_t {
struct no_lista *inicio, *atual, *fim;
} *lista;

/* Funções de criação e destruição de listas. */
lista cria_lista(void);
void destroi_lista(lista &l);

/* Funções que manipulam conteúdo da lista. */
bool insere_elemento_final(lista l, conteudo c);
bool insere_elemento_inicio(lista l, conteudo c);
bool insere_elemento_posicao_atual(lista l, conteudo c);
bool remove_primeiro(lista l);
bool remove_ultimo(lista l);
bool remove_posicao_atual(lista l);

/* Funções que manipulam ponteiro da posição atual. */
bool avanca_cursor(lista l);
bool retrocede_cursor(lista l);
bool rebobina_cursor(lista l);
bool avanca_tudo_cursor(lista l);
bool esta_no_inicio(lista l);
bool esta_no_fim(lista l);
bool localiza_elemento(lista l, conteudo c);
#define localiza_e_remove(l, c) ( localiza_elemento(l, c) && remove_posicao_atual(l) )


O que você tem no seu programa não se parece com isso que eu rapidamente mostrei acima. Você parece estar mais interessado num array alocado dinamicamente, que é algo muito mais simples de fazer e manipular.
conteudo *dyn_array;
size_t tamanho_dyn_array, usados_dyn_array;

/* Alocação inicial. */
tamanho_dyn_array=10; usados_dyn_array=0;
dyn_array=malloc(tamanho_dyn_array * sizeof dyn_array[0]);
if(dyn_array==NULL) /* alocacao falhou */ {
perror("falha de alocacao");
exit(1);
}

/* Novos elementos que sejam incluídos no final podem usar o seguinte código. */
if(tem_novo_conteudo){
if(usados_dyn_array==tamanho_dyn_array){
void *temp=realloc(dyn_array, (tamanho_dyn_array+10)*sizeof dyn_array[0]);
if(temp==NULL){
perror("falha de realocação");
exit(1);
}
tamanho_dyn_array+=10;
}
dyn_array[usados_dyn_array++]=copia_conteudo(conteudo_novo);
}

/* O acesso a um elemento do array dinâmico é semelhante ao de arrays comuns. */
// Lê elemento do array.
conteudo_atual=copia_conteudo(dyn_array[indice1]); // indice1 tem de ser maior ou igual a zero e menor que tamanho_dyn_array.

// Escreve elemento no array.
libera_conteudo(dyn_array[indice2]); // indice2 tem de ser maior ou igual a zero e menor que tamanho_dyn_array.
dyn_array[indice2]=copia_conteudo(outro_conteudo);

/* Parar liberar o array dinâmico, faz-se o seguinte. */
while(usados_dyn_array>0)
libera_conteudo(dyn_array[--usados_dyn_array]);
free(dyn_array);
tamanho_dyn_array=0;


Note que, acima, eu faço uma cópia cautelosa de valores, pois o tipo conteudo pode ser um objeto complexo, que inclui ponteiros dentro dele, por isso as funções copia_conteudo() e libera_conteudo(). Se, em vez disso, você trabalhar com tipos nativos, como int, double ou char (mas não arrays!) ou estruturas que não incluam ponteiros, então a função de cópia pode ser substituída por atribuição comum (e.g. “dyn_array[indice2]=outro_conteudo”) e a de liberação pode ser totalmente suprimida. Se o conteúdo for de strings representadas como ponteiros, como no seu programa, a cópia pode ser feita com strdup() (e.g. “dyn_array[indice2]=strdup(outro_conteudo)”) e a liberação é feita com free() (e.g. “free(dyn_array[indice2])”).

---

Você parece ser iniciante em C. Se de fato o for, eu sugiro deixar C de lado e usar C++, que oferece tudo o que o C oferece, incluindo alto desempenho, e ainda muito mais.

Entre o muito que o C++ oferece estão partes de sua biblioteca que já implementam listas, arrays dinâmicos (chamados de vetores), mapas, conjuntos, pilhas e outros tipos de contêineres de dados. Tudo aquilo que eu mostrei sobre listas já está pronto, e de modo muito melhor do que o que eu fiz aqui. Até mesmo o suporte a strings é muito melhor do que qualquer coisa oferecida em C.

Além disso, tipos complexos, de variedades que têm operações de criação, cópia e liberação não-triviais, podem ser construídos em C++ de modo a esconder tal complexidade. Você possivelmente não precisaria de nada parecido com copia_conteudo() e libera_conteudo().

---

Os trechos de programas que você mostrou têm alguns erros.

O primeiro deles a é a forma de declarar a função main. O tipo de retorno de main tem de ser int, e não void, como no seu programa. E se você não espera receber nenhum argumento, você tem de deixar isso claro, colocando a palavra “void” na lista de parâmetros da função. Em outras palavras, a forma correta de declara main é a seguinte: “int main(void)”.

Se, por outro lado, você quiser passar argumentos a main a partir do ambiente de execução, pode fazê-lo. Nesse caso, esses argumentos serão recebidos como strings contida num array, e a declaração de main deve ser feita com dois parâmetros: um inteiro que informa a quantidade de elementos do array, e outro que declara um array dinâmico de ponteiros de caracteres. Como você já viu acima arrays dinâmicos são feitos usando ponteiros, então a declaração da função terá a forma “int main(int argc, char **argv)” (os nomes argc e argv são convencionais, abreviando “argument counter” e “argument vector”, respectivamente, mas você pode usar outros, se quiser).

A forma de declaração “char *List1[]” é um fóssil histórico da antiga linguagem B, o qual só é válido na declaração de parâmetro de funções. Ele é sinônimo de “char **List” (ou seja: em ambos os casos, List é do tipo “ponteiro para dado do tipo ponteiro para dado do tipo char”). Fora do contexto de declaração de parâmetro, você tem de usar a forma que deixa explícitos os dois níveis de ponteiros.


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





Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts