Error ! null list - c

I have a problem, my code is executing option 3 only the first time, if I go back to the menu and try again appears nulla. Case 3 is to list a list of names in alphabetical alphabetical order and reverse order (InsertOrd 0 / InsertDec 1);
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <locale.h>
#define N 10000
typedef struct Lista {
char *data;
struct Lista *next;
} Lista;
//Ordem Crescente
struct Lista *InsertOrd(struct Lista *head, const char *data) {
struct Lista *newp;
struct Lista *tmp;
char *new_data;
/* aloca o novo item */
newp = ((struct Lista*)malloc(sizeof(struct Lista)));
new_data = strdup(data);
//strdup aloca memória na pilha.
if (newp == NULL || new_data == NULL) {
fprintf(stderr, "out of memory");
return NULL;
}
newp->data = new_data;
newp->next = NULL;
/* check if element should be inserted at the head */
if (head == NULL || strcmp(new_data, head->data) < 0) {
newp->next = head;
head = newp;
} else {
/* otherwise find the point of insertion */
tmp = head;
while (tmp->next && strcmp(new_data, tmp->next->data) >= 0) {
tmp = tmp->next;
}
newp->next = tmp->next;
tmp->next = newp;
}
return head;
}
//Ordem decrescente
struct Lista *InsertDec(struct Lista *head, const char *data) {
struct Lista *newp;
struct Lista *tmp;
char *new_data;
/* aloca o novo item */
newp = ((struct Lista*)malloc(sizeof(struct Lista)));
new_data = strdup(data);
//strdup aloca memória na pilha.
if (newp == NULL || new_data == NULL) {
fprintf(stderr, "out of memory");
return NULL;
}
newp->data = new_data;
newp->next = NULL;
/* verificar o elemento deve ser inserido na cabeça*/
if (head == NULL || strcmp(new_data, head->data) < 0) {
newp->next = head;
head = newp;
} else {
/* caso contrário, encontre o ponto de inserção */
tmp = head;
while (tmp->next && strcmp(new_data, tmp->next->data) <= 0) {
tmp = tmp->next;
}
newp->next = tmp->next;
tmp->next = newp;
}
return head;
}
void liberar(struct Lista *filmes)
{
while (filmes != NULL) {
struct Lista *next = filmes->next;
free(filmes->data);
free(filmes);
filmes = next;
}
}
void escrever(struct Lista * film,struct Lista * filmes)
{
for (film = filmes; film != NULL; film = film->next) {
printf("\n Nome: %s", film->data);
}
}
int main()
{
struct Lista *filmes;
struct Lista *film;
FILE *arq;
char linha[600];
int opcao;
/* insert the items */
filmes = NULL;
/* open the file */
arq = fopen("asd.txt", "r");
if (arq == NULL) {
printf("Ocorreu um erro!");
return 1;
}
do{
printf("\n1- Listar todos os atores da lista em ordem alfabetica e alfabetica reversa");
printf("\n2- Listar todos os filmes de um determinado ator em ordem cronologica.");
//\n Os filmes que não tiverem a informação de ano são mostrados em último lugar
printf("\n3- Listar todos os filmes em ordem alfabetica e alfabetica reversa");
printf("\n4- Inserir novo filme");
printf("\n5- Remocao de filmes");
printf("\n6-SAIR DO PROGRAMA");
printf("\n");
scanf("%d",&opcao);
if(opcao<1 || opcao>6){
printf("\nO numero que voce digitou eh invalido!\n Por favor tente novamente.\n");
}
switch(opcao)
{
case 1:
break;
case 2:
break;
case 3:
printf("\n Voce gostaria de listar em ordem alfabetica ou alfabetica reversa (0/1) :");
int op;
scanf("%d",&op);
if(op!=0 && op!=1)
{
printf("\n Voce precisa digita o numero 1 ou 0 apenas!\n");
}
switch(op){
case 0:
while (fgets(linha, sizeof linha, arq)) {
char *p = strtok(linha, ",");
filmes = InsertOrd(filmes, p);
}
fclose(arq);
escrever(film,filmes);
liberar(filmes);
break;
case 1:
while (fgets(linha, sizeof linha, arq)) {
char *p1 = strtok(linha, ",");
filmes = InsertDec(filmes, p1);
}
fclose(arq);
escrever(film,filmes);
liberar(filmes);
break;
}
break;
case 4:
break;
case 5:
break;
case 6:
printf("\nSaindo do programa...");
break;
}
}while(opcao!=6);
// escrever(film,filmes);
/* free the list */
while (filmes != NULL) {
struct Lista *next = filmes->next;
free(filmes->data);
free(filmes);
filmes = next;
}
return 0;
}
The first time I run either option 1 or 0 of case 3 works but then this appears:

You have only one
arq = fopen("asd.txt", "r");
and you have several
fclose(arq);
Option 3 (both cases) does
while (fgets(linha, sizeof linha, arq))
// ...
fclose(arq);
So next time you use option 3 - it fails.
I suggest that instead of fclose in those options, you add rewind before reading.
Please test your code step by step as you build it.

Related

Why do I get a segfault when the for loop finishes adding elements to a list?

My code is an algorithm to solve a problem related to the longest-job first. It receives the number of process (num_programas) and for each process it gets an time (instante) and a weight(carga). When i'm inserting on the list it inserts all process but in the last one it gets segmentation fault.
It is sorting normally (i've printed the header each time the loops executes), it just gets segmentation fault in the last execution of the for loop (for instance: num programas = 7, stops working when i = 6)
/*
Vou fazer com lista duplamente encadeada só pra facilitar na funcao proximo. Não vou otimizar porque preciso me livrar
logo pra fazer o projeto e estudar
puta merda que codigo horrivel, espero que o aleardo nao leia. Otimizar depois.
8
74 11
7 20
53 17
78 13
52 11
63 19
89 17
15 20
*/
#include <stdio.h>
#include <stdlib.h>
struct processo
{
int temp;
int carga;
struct processo *next;
struct processo *prev;
};
struct processo *cadastrarProcesso(struct processo *header, int instante, int carga);
struct processo *executarAtividade(struct processo *header, int *tempo_executando);
struct processo *inserirProcessos(struct processo *programa, struct processo *header);
void imprimirLista(struct processo *header);
struct processo *proximo(struct processo *header, int *tempo_executando);
int main()
{
struct processo *header, *aux;
header = NULL;
int num_programas, instante, carga, i, tempo_executando = 0;
scanf("%d", &num_programas);
for (i = 0; i < num_programas; i++)
{
scanf("%d %d", &instante, &carga);
header = cadastrarProcesso(header, instante, carga);
}
/*
Cadastrou e ordenou em ordem de tempo, aí tem que criar uma funcao para ir printando
*/
imprimirLista(header);
for (i = 0; i < num_programas; i++)
{
header = executarAtividade(header, &tempo_executando);
}
return 0;
}
struct processo *cadastrarProcesso(struct processo *header, int instante, int carga)
{
struct processo *aux;
aux = malloc(sizeof(struct processo));
aux->next = NULL;
aux->prev = NULL;
aux->carga = carga;
aux->temp = instante;
header = inserirProcessos(aux, header);
return header;
}
struct processo *inserirProcessos(struct processo *programa, struct processo *header)
{
struct processo *aux;
if (header == NULL)
{
header = programa;
return header;
}
aux = header;
while (aux->next != NULL && programa->temp > aux->temp)
{
aux = aux->next;
}
if (aux == header)
{
// tem que fazer essa verificacao pq ele sai do while tanto se o while->next for nulo e tambem se for maior
if (programa->temp < aux->temp)
{
// insere depois do header, se tornando o novo header
aux->prev = programa;
programa->next = aux;
return programa;
// é o novo header, retorna ele
}
else // insere depois)
{
programa->next = aux->next;
aux->next = programa;
programa->prev = aux;
return header;
}
}
else
{
// vamos ver se ele saiu porque while->next é nulo ou porque é maior
if (programa->temp < aux->temp)
{
(aux->prev)->next = programa;
programa->prev = aux->prev;
programa->next = aux;
aux->prev = programa;
return header;
}
else // maior igual
{
programa->next = aux->next;
programa->prev = aux;
aux->next = programa;
return header;
}
}
}
void imprimirLista(struct processo *header) // funcao auxiliar
{
struct processo *aux;
aux = header;
while (aux != NULL)
{
printf("%d ", aux->temp);
aux = aux->next;
}
}
struct processo *executarAtividade(struct processo *header, int *tempo_executando)
{
// lembrando que já está dentro de um for
struct processo *aux;
if (*tempo_executando == 0)
{
aux = header;
*tempo_executando = aux->temp + aux->carga;
header = aux->next;
printf("%d ", aux->carga); // imprime a carga da saida que foi executada
(aux->next)->prev = NULL;
aux->next = NULL;
free(aux);
return header;
}
else
{
// TODO: reduzir esse codigo zendo tudo dentro do mesmo IF, só olhando a condicao do proximo
aux = proximo(header, tempo_executando); // recebe o que vai ser executado
*tempo_executando = *tempo_executando + aux->carga;
if (aux == header) // se o aux
{
header = aux->next;
printf("%d ", aux->carga);
(aux->next)->prev = NULL;
aux->next = NULL;
free(aux);
return header;
}
else
{
if (aux->next != NULL)
{
(aux->next)->prev = aux->prev;
(aux->prev)->next = aux->next;
}
else
{
(aux->prev)->next = aux->next;
}
printf("%d ", aux->carga);
free(aux);
return header;
}
}
}
struct processo *proximo(struct processo *header, int *tempo_executando)
{
struct processo *aux, *escolhido;
int maior_carga;
aux = header;
maior_carga = aux->carga;
escolhido = aux;
if (aux->temp >= *tempo_executando)
{
//*tempo_executando = *tempo_executando + (aux->temp - *tempo_executando);
return aux;
}
else
{
while (aux->next != NULL && aux->temp < *tempo_executando)
{
aux = aux->next;
if (aux->carga > maior_carga)
{
maior_carga = aux->carga;
escolhido = aux;
}
else if (aux->carga == maior_carga)
{
// o critério de desempate é o menor tempo
if (aux->carga < escolhido->carga)
{
escolhido = aux;
}
}
}
return escolhido;
}
}
In this code:
if (aux == header) // se o aux
{
header = aux->next;
printf("%d ", aux->carga);
(aux->next)->prev = NULL; // crash here with aux->next == NULL
aux->next = NULL;
free(aux);
return header;
}
when you are removing the last element (aux == header), aux->next is NULL and attempting to dereference it causes a crash. You must check that aux->next != NULL before doing that.
P.S. The aux->next = NULL is useless if you immediately call free(aux).

Trying to limit a list in C

right now i'm trying to build a simple program as my homework for college, this was supposed to be a simple code but i'm learning c just now and i'm having a really bad time trying to learn it, anyways, this code should be able to add to add, remove, show and clear some numbers on the console, a list(i dont know if it's called that way in english), but 1 thing that i can't do and i have been researching and tryed to figure out is in how to put a limit on this list, exactly 20 numbers.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int num;
struct node *prox;
};
typedef struct node Fila;
int t;
int menu(void);
void opcao(Fila *f, int op);
void inicia(Fila *f);
int vazia(Fila *f);
Fila *aloca();
void insere(Fila *f);
Fila *retira(Fila *f);
void exibe(Fila *f);
void libera(Fila *f);
void liberar_mem(Fila *f);
int main(void)
{
Fila *f = (Fila *)malloc(sizeof(Fila));
if (!f)
{
printf("Sem memoria disponivel!\n");
exit(1);
}
else
{
inicia(f);
int opt;
do
{
opt = menu();
opcao(f, opt);
} while (opt);
free(f);
return 0;
}
}
int menu(void)
{
int opt;
printf("Escolha a opcao\n");
printf("0. Sair\n");
printf("1. Zerar solicitacoes\n");
printf("2. Exibir solicitacoes\n");
printf("3. Inserir o numero da solicitacao\n");
printf("4. Remover solicitacao\n");
printf("Opcao: ");
scanf("%d", &opt);
return opt;
}
void opcao(Fila *f, int op)
{
Fila *tmp;
switch (op)
{
case 0:
liberar_mem(f);
break;
case 1:
libera(f);
inicia(f);
break;
case 2:
exibe(f);
break;
case 3:
insere(f);
break;
case 4:
tmp = retira(f);
if (tmp != NULL)
{
printf("Solicitacao removida: %3d\n\n", tmp->num);
free(tmp);
}
break;
default:
printf("Comando invalido\n\n");
}
}
void inicia(Fila *f)
{
f->prox = NULL;
t = 0;
}
int vazia(Fila *f)
{
if (f->prox == NULL)
return 1;
else
return 0;
}
Fila *aloca()
{
Fila *novo = (Fila *)malloc(sizeof(Fila));
if (!novo)
{
printf("Sem memoria disponivel!\n");
exit(1);
}
else
{
printf("Insira o numero da solicitacao: ");
scanf("%d", &novo->num);
return novo;
}
}
void insere(Fila *f)
{
Fila *novo = aloca();
novo->prox = NULL;
if (vazia(f))
f->prox = novo;
else
{
Fila *tmp = f->prox;
while (tmp->prox != NULL)
tmp = tmp->prox;
tmp->prox = novo;
}
t++;
}
Fila *retira(Fila *f)
{
if (f->prox == NULL)
{
printf("Lista de solicitacoes ja esta vazia\n");
return NULL;
}
else
{
Fila *tmp = f->prox;
f->prox = tmp->prox;
t--;
return tmp;
}
}
void libera(Fila *f)
{
if (f->prox == NULL)
{
printf("Lista de solicitacoes ja esta vazia\n");
Fila *proxNode, *atual;
atual = f->prox;
while (atual != NULL)
{
proxNode = atual->prox;
free(atual);
atual = proxNode;
}
}
else
{
if (!vazia(f))
{
Fila *proxNode, *atual;
atual = f->prox;
while (atual != NULL)
{
proxNode = atual->prox;
free(atual);
atual = proxNode;
}
}
}
}
void exibe(Fila *f)
{
if (vazia(f))
{
printf("Nenhuma solicitacao cadastrada!\n\n");
return;
}
Fila *tmp;
tmp = f->prox;
printf("Fila :");
while (tmp != NULL)
{
printf("%5d", tmp->num);
tmp = tmp->prox;
}
printf("\n ");
int count;
for (count = 0; count < t; count++)
printf(" ^ ");
printf("\nOrdem:");
for (count = 0; count < t; count++)
printf("%5d", count + 1);
printf("\n\n");
}
void liberar_mem(Fila *FILA)
{
if (!vazia(FILA))
{
Fila *proxNode, *atual;
atual = FILA->prox;
while (atual != NULL)
{
proxNode = atual->prox;
free(atual);
atual = proxNode;
}
}
}
You could use a global variable that keeps track of the current length of the list and return an error message when someone tries to expand the list beyond the limit.
However, while global variables are fine for simple programs, it's considered good style for larger programs to rely upon them as little as possible.
Therefore, I'd recommend using a "list header" object. For example,
#define MAX_LIST_LENGTH 20
struct list_header {
Fila *start_of_list;
unsigned int current_length;
};

Sorting Simple Linked List - C

[UPTATED WITH ANSWER AT THE END] I tried many things but I still don't know how I can do any sorting with a simple linked list. It should be sorted like the number saved on each node goes from the lower till the higher one. What can I do?
I'm not allowed to sort the numbers as I save then on the list. The sorting must be made after the list is complete.
the code isn't completely ready yet
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#define pi 3.14159265359
#define N 50
typedef struct lista{
char palavra[N];
int repeticao;
struct lista *prox;
} Lista;
Lista* lista_cria(){
return NULL;
}
int vazia(Lista *LISTA){
if(LISTA->prox == NULL) return 1;
else return 0;
}
void insere(Lista **lis, char *s){
Lista* novo = (Lista*) malloc (sizeof(Lista));
strcpy(novo->palavra, s);
novo->prox = NULL;
while (*lis)
lis = &(*lis)->prox;
*lis = novo;
}
Lista* retira(Lista* lis, char *s){
Lista* ant = NULL;
Lista* p = lis;
while(p != NULL && (strcmp(s, p->palavra) != 0)){
ant = p;
p = p->prox;
}
if(p == NULL) return lis;
if(ant == NULL) lis = p->prox;
else ant->prox = p->prox;
free(p);
return lis;
}
void imprimir_lista(Lista* lis){
Lista* p;
for(p = lis; p != NULL; p = p->prox)
printf("%s ", p->palavra);
printf("\n \n");
}
int busca(Lista* lis, char *s){
Lista *p;
int cont = 0;
for(p = lis; p != NULL; p = p->prox){
if(strcmp(p->palavra, s) == 0) cont++;
}
return cont;
}
Lista* repeticao(Lista* lis, int i){
Lista *p;
char s[50];
int cont;
printf("\n \n Doc%d", i);
for(p = lis; p != NULL; p = p->prox){
strcpy(s, p->palavra);
cont = busca(p, s);
printf(" \n\t %s: %d ", s, cont);
p->repeticao = cont;
}
return lis; /* return p*/
}
void liberar_lista(Lista *lis){
Lista *aux = lis;
while (aux != NULL) {
Lista *aux2 = aux->prox;
free(aux);
aux = aux2;
}
}
float produto_escalar (Lista *lis1, Lista *lis2) {
Lista *aux1 = lis1, *aux2 = lis2;
float resultado=0;
while (aux1 != NULL) {
while (aux2 != NULL) {
if (strcmp(aux1->palavra, aux2->palavra) == 0 ) {
resultado+=(aux1->repeticao*aux2->repeticao);
aux2 = aux2->prox;
break;
}
else {
aux2 = aux2->prox;
}
}
aux1 = aux1->prox;
aux2 = lis2;
}
return resultado;
}
float formula (Lista *lis1, Lista *lis2){
float resultado;
resultado = acos(produto_escalar(lis1, lis2)/(sqrt(produto_escalar(lis1, lis1))*sqrt(produto_escalar(lis2, lis2))));
resultado = (((resultado *50)*4)/pi)-100;
if (resultado<0){
resultado*=-1;
}
return resultado;
}
void checa_plagio (float resultado) {
if (resultado>=50) {
printf("\n O arquivo foi plagiado. \n\t Arquivo é %.3f%% parecido.", resultado);
}
else
printf("\n O arquivo não foi plagiado \n\t Arquivo é %.3f%% parecido.", resultado);
}
int main () {
char arquivo1[] = "doc1.txt", arquivo2[] = "doc2.txt";
char string[50];
double resposta;
FILE *fp1, *fp2;
Lista *lista1, *lista2;
lista1 = lista_cria();
lista2 = lista_cria();
fp1 = fopen (arquivo1, "r+") ;
if (fp1 == NULL) {
printf("\nErro. Não foi possível abrir o arquivo.\n");
return EXIT_FAILURE;
}
while(!feof(fp1)){
fscanf(fp1, "%s[A-Z a-z]", string);
insere(&lista1, string);
}
fclose(fp1);
fp2 = fopen (arquivo2, "r+") ;
if (fp2 == NULL) {
printf("\nErro. Não foi possível abrir o arquivo.\n");
return EXIT_FAILURE;
}
while(!feof(fp2)){
fscanf(fp2, "%s[A-Z a-z]", string);
insere(&lista2, string);
}
fclose(fp2);
/*imprimir_lista(lista1);
imprimir_lista(lista2);*/
lista1 = repeticao(lista1, 1);
lista2 = repeticao(lista2, 2);
resposta = formula (lista1, lista2);
checa_plagio(resposta);
liberar_lista(lista1);
liberar_lista(lista2);
return EXIT_SUCCESS;
}
[UPDATED WITH ANSWER]
THE CODE I USED TO SORT:
#define N 50
#include <stdlib.h>
#include <stdio.h>
typedef struct lista{
char palavra[N];
int repeticao;
struct lista *prox;
} Lista;
Lista* sort (Lista *lis) {
Lista *temp, *empurra;
Lista *aux1, *aux2;
Lista *guarda;
aux1 = NULL;
for (temp = lis; temp != NULL; temp = temp->prox){
aux2 = temp;
for (empurra=temp->prox; empurra != NULL; empurra = empurra->prox){
if (empurra->repeticao < temp->repeticao){
guarda = temp->prox;
temp->prox = empurra->prox;
if(guarda == empurra)
empurra->prox = temp;
else
empurra->prox = guarda;
if(aux2 != temp)
aux2->prox = temp;
if(aux1)
aux1->prox = empurra;
else
lis = empurra;
guarda = temp;
temp = empurra;
empurra = guarda;
}
aux2 = empurra;
}
aux1 = temp;
}
return lis;
}
int main (){
return 0;
}
I think the most learning approach that you can take, it's to think that the linked list is an array. With that approach you can simply, access the elements of the array and apply a sort algorithm (like bubble sort) and when make the swap of the elements using the pointer to the elements. With that would be just a matter to redirect the pointers (to next elements) for the right elements.
Also, pay attention to the particular cases of the sorts (the beginning and the end of list, in this case).
Here's a example:
Suppose that we have the structure for the linked list:
typedef struct list{
int n;
struct list *next;
} List;
And we want to sort the linked list using the int n, a code example would be something like this:
void sort (List * begin) {
List *currentElement, *previousElement;
int swapped = 1;
while (swapped) {
swapped = 1;
while (swapped != 0) {
swapped = 0;
currentElement = begin;
previousElement = NULL; //No previous element in the beginning of the list
while(currentElement->next != NULL) { //Has another element, it's not the end of the list
List *nextElement = currentElement->next;
if(currentElement->n > nextElement->n) {
//swapping the elements
if (previousElement == NULL) { //is the first element
List *auxPtr = nextElement->next;
nextElement->next = currentElement;
currentElement->next = auxPtr;
begin = nextElement; //nextElement is the first element of the list now
}
else {
previousElement->next = nextElement;
currentElement->nextElement->next;
nextElement->next = currentElement;
}
previousElement = nextElement; //The nextElement is 'behind' the currentElement so it should be the previousElement
swapped = 1; // a swap was made
//The elements where swapped so currentElement is already in the 'position' of the next element, there is no need to upload it value
}
else { // there is no need to swap, just walk foward in the list
previousElement = currentElement;
currentElement = nextElement;
}
}
}
}
}
I used a simple bubble sort for the sorting

How can I go trough an delete online one element of struct at a time

I have this lists made in structs and I need to go through and delete one of the elemments at a time, I've searched in similar questions but I still don get how to do this.
downside is the code, can someone tell me how to do this?
//Estructura para guardar pid's
struct pid
{
int numero;
int numero_padre;
struct pid *next;
struct pid *ahead;
};
struct pid *head = NULL;
struct pid *curr = NULL;
// Primer Nodo
struct pid* creaLista(int numero)
{
printf("\n Creando lista con el primer valor: [%d]\n",numero);
struct pid *ptr = (struct pid*)malloc(sizeof(struct pid));
if(NULL == ptr)
{
printf("\n Fallo al crear la lista \n");
return NULL;
}
ptr->numero = numero;
ptr->next = NULL;
head = curr = ptr;
return ptr;
}
struct pid* agregaALista(int numero, bool agrega_al_final)
{
struct pid *next = NULL;
//Si lista vacia
if(NULL == head)
{
return (creaLista(numero));
}
if(agrega_al_final)
printf("\n Agregando nodo al final de la lista [%d]\n", numero);
else
printf("\n Agregando nodo al comienzo de la lista [%d]\n",numero);
//Reservar espacio para nuevo nodo
struct pid *ptr = (struct pid*)malloc(sizeof(struct pid));
if(NULL == ptr)
{
printf("\n Fallo al agregar nodo \n");
return NULL;
}
ptr->numero = numero;
ptr->next = NULL;
if(agrega_al_final)
{
curr -> next = ptr;
curr = ptr;
}
else
{
ptr->next = head;
head = ptr;
}
return ptr;
}
void imprimeLista(void)
{
struct pid *ptr = head;
printf("\n -------Inicio de lista------- \n");
while(ptr != NULL)
{
printf("\n [%d] \n",ptr->numero);
ptr = ptr->next;
}
printf("\n -------Fin lista------- \n");
return;
}
/*void quitardeLista(int numero, bool quita_al_final)
{
struct pid *ptr = head;
struct pid *del = NULL;
//Si lista vacia
if(quita_al_final)
printf("\n quitando nodo al final de la lista [%d]\n", numero);
else
printf("\n quitando nodo al comienzo de la lista [%d]\n",numero);
//Reservar espacio para nuevo nodo
ptr->numero = numero;
if(quita_al_final)
{
curr->ahead = ptr;
curr = ptr;
rmv(del);
//free (del);
}
else
{
ptr->next = head;
head = ptr;
//free (del);
}
return ptr;
}*/
void borraLista(int i, int numero)
{
struct pid *ptr = head;
struct pid *del = NULL;
while ( ptr->next != NULL)
{
if(i == numero)
{
curr -> next = ptr;
curr = ptr;
printf("\n Se borrará [%d] \n",ptr->numero);
del = ptr;
free (del->next);
printf("\n Borrado! \n");
}
else
{
ptr->next = head;
head = ptr;
printf("\n Se borrará [%d] \n",ptr->next);
del = ptr;
free (del->next);
printf("\n Borrado! \n");
}
return ptr;
/* ptr->next = head;
head = ptr;
printf("\n next [%d] \n",ptr->next); */
}
printf("\n next [%d] \n",ptr->next);
return ptr;
//ptr = ptr->ahead;
//curr -> ahead;
}
/* while(ptr != NULL)
{
printf("\n Se borrará [%d] \n",ptr->numero);
del = ptr;
ptr = ptr->next;
free (del->next);
printf("\n Borrado! \n");
}
if(ptr != NULL)
{
printf("\n Se borrará [%d] \n",curr->numero);
del = curr;
curr = curr->ahead;
free (del->ahead);
printf("\n Borrado! \n");
}*/
//head = NULL;
//}
int main(void)
{
int i = 0;
int r = 0;
// Inicializando contenedor
struct pid *ptr = NULL;
for(i; i<10; i++)
{
r = rand() % 9999;
agregaALista(i,true);
}
imprimeLista();
borraLista(i,true);
}
Look at the definition:
void borraLista(int i, int numero)
and the call:
borraLista(i,true);
You are calling borraLista with
i=(whatever value it has after the for loop)
numero = true,
so this line in borraLista is never going to be true:
if(i == numero)

Eliminate node function from tree doesn't work in C

I have to eliminate a node from the tree. I first tried to eliminate the node root, so I don't have to search the node and it works. But then I tried to do it by searching, and when the function calls itself, the program freezes after it passes the first if-statement...
The problem is in the function, void Eliminar(struct arbol *tree, int valor);:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct arbol
{
int numero;
struct arbol *izq;
struct arbol *der;
};
struct arbol *raiz = NULL;
struct arbol *eliminador = NULL;
int encontrado = 0;
int right = 0, left = 0;
int crear_arbol(int dato);
struct arbol * crear_nodo(int valor);
void ImprimeDNI (struct arbol *tree);
void ImprimeIND (struct arbol *tree);
void ImprimeNDI (struct arbol *tree);
void Buscar (struct arbol *tree, int valor);
void Eliminar (struct arbol *tree,int valor);
int Eliminaroot ();
int Eliminarright(struct arbol *localizador);
int Eliminarleft(struct arbol *localizador);
int main ()
{
int n, i;
char opcion;
int numero;
puts("Ingrese la cantidad de numeros a ingresar");
scanf("%d", &n);
int numeros[n];
puts("Ingrese los numeros separados por espacio o enter");
for(i = 0; i < n; i++)
{
scanf("%d",&numeros[i]);
}
for(i = 0; i < n; i++)
{
crear_arbol(numeros[i]);
}
puts("");
system("pause");
system("cls");
do
{
encontrado = 0;
puts("******** OPCIONES ********");
puts("|B o b| Para buscar un numero");
puts("|E o e| Eliminar un nodo");
puts("|I o i| Imprimir de las 3 formas principales");
fflush(stdin);
opcion = getch();
switch(opcion)
{
case 'B': case 'b': puts("Ingrese el numero a buscar"); scanf("%d",&numero); Buscar(raiz,numero);
if(encontrado == 0) {puts("El numero no esta en el arbol");} break;
case 'E': case 'e': puts("Ingrese el numero a eliminar"); scanf("%d", &numero);
if(raiz->numero == numero)
{
Eliminaroot();
}
else
{
Eliminar(raiz,numero);
if(right == 0 && left == 0)
{
puts("No se encontro el numero");
}
if(right == 1)
{
Eliminarright(eliminador);
}
if(left == 1)
{
Eliminarleft(eliminador);
}
}
break;
case 'I': case 'i': ImprimeDNI(raiz); puts(""); ImprimeIND(raiz); puts(""); ImprimeNDI(raiz); puts(""); break;
default: puts("Opcion Invalida"); break;
}
puts("");
system("pause");
system("cls");
}while (opcion != 'T' || opcion != 't');
return 0;
}
int crear_arbol(int dato)
{
struct arbol *recorrer = raiz;
struct arbol *nuevo;
if(raiz == NULL)
{
raiz = crear_nodo(dato);
return 1;
}
else
{
nuevo = crear_nodo(dato);
}
while (1) {
if(recorrer->numero <= nuevo->numero)
{
if(recorrer->der == NULL)//si las ramas de donde esta el puntero que recorre son NULL, significa
{ //que es la ultima comparacion
recorrer->der = nuevo;
break;
}
recorrer = recorrer->der;
}
else
{
if(recorrer->izq == NULL)//lo mismo que el if de arriba
{
recorrer->izq = nuevo;
break;
}
recorrer = recorrer->izq;
}
}//while
return 1;
}
struct arbol * crear_nodo(int valor)
{
struct arbol *aux;
aux = (struct arbol*)malloc(sizeof(struct arbol));
aux->numero = valor;
aux->izq = NULL;
aux->der = NULL;
return aux;
}
void ImprimeDNI (struct arbol *tree)
{
if(!tree)
return;
ImprimeDNI(tree->der);
printf("%d, ", tree->numero);
ImprimeDNI(tree->izq);
}
void ImprimeIND (struct arbol *tree)
{
if(!tree)
return;
ImprimeIND(tree->izq);
printf("%d, ", tree->numero);
ImprimeIND(tree->der);
}
void ImprimeNDI (struct arbol *tree)
{
if(!tree)
return;
printf("%d, ", tree->numero);
ImprimeNDI(tree->der);
ImprimeNDI(tree->izq);
}
void Buscar (struct arbol *tree, int valor)
{
if(tree->numero == valor)
{printf("El numero si se encuentra en el arbol"); encontrado = 1;}
if(!tree)
return;
Buscar(tree->der, valor);
Buscar(tree->izq,valor);
}
int Eliminaroot ()
{
int encontrado = 0;
struct arbol *aux = raiz;
struct arbol *buscador = raiz->der;
for(; buscador->der != NULL ; buscador = buscador->der)
{
if(buscador->izq != NULL)
{
encontrado = 1;
for(; buscador->izq->izq != NULL ; buscador = buscador->izq)
{
}
break;
}//if
}
if(encontrado == 0)
{
if(raiz->der == NULL)
{
raiz = aux->izq;
raiz->izq = aux->izq->izq;
raiz->der = aux->izq->der;
}
else
{
raiz = aux->der;
raiz->izq = aux->izq;
raiz->der = aux->der->der;
free(aux);
}
}
else
{
raiz = buscador->izq;
raiz->der = aux->der;
raiz->izq = aux->izq;
buscador->izq = NULL;
free(aux);
}
return 1;
}
void Eliminar (struct arbol *tree, int valor)
{
if(tree->izq->numero == valor)
{
eliminador = tree;
left = 1;
}
puts("AAAA");
if(tree->der->numero == valor)
{
eliminador = tree;
right = 1;
}
if(!tree)
return;
Eliminar(tree->der, valor);
Eliminar(tree->izq, valor);
}
int Eliminarright(struct arbol *localizador)
{
return 1;
}
int Eliminarleft(struct arbol *localizador)
{
return 1;
}*
As Nick suggested, you should check that tree is valid at the beginning of Eliminar. However, if the first if statement executes fine, tree can't be NULL. tree->der can, though - you should check that too before dereferencing it. And of course, the same for tree->izq in the first if - just because it isn't NULL the very first time you call this function, don't assume it never will.
A few further notes: you are searching for the node having the value valor in Eliminar (which is thus a bad name - you aren't eliminating the node there, only marking it for later removal).
If you find it, there is no point continuing the search, so you can return right away from both if branches.
Moreover, you handle separately the cases when you find valor in the left or right subtree, by setting the left or right flags, and calling Eliminarleft or Eliminarright accordingly. It would be much simpler to store directly the left or right subtree to be removed, so then you can drop the two flags and the two removal methods:
void Eliminar (struct arbol *tree, int valor)
{
if(!tree)
return;
if(tree->izq && tree->izq->numero == valor)
{
eliminador = tree->izq;
return;
}
puts("AAAA");
if(tree->der && tree->der->numero == valor)
{
eliminador = tree->der;
return;
}
Eliminar(tree->der, valor);
Eliminar(tree->izq, valor);
}
...
Eliminar(raiz,numero);
if(!eliminador)
{
puts("No se encontro el numero");
}
else
{
Eliminar(eliminador);
}
This is cleaner, but we can go even further. Notice that you are checking the left and right subtrees in Eliminar, then recursing on the same. It suffices instead to check only tree itself, then recurse:
void Eliminar (struct arbol *tree, int valor)
{
if(!tree)
return;
if(tree->numero == valor)
{
eliminador = tree;
return;
}
puts("AAAA");
Eliminar(tree->der, valor);
Eliminar(tree->izq, valor);
}
You're not checking the tree pointer at the top of your function, so could be causing an access violation on a null pointer. Move your if (!tree) return; check to the top of the function.
#PéterTörök's answer gets you part of the way there. It looks to me like you have a standard binary tree setup with "value less than" on the left and "value greater than" on the right (or perhaps >= if you allow duplicates).
It would be awfully good to get rid of the global variables, though (Eliminar sets eliminador and also a left/right flag), which you can do by using pointers-to-pointers. Instead of having Eliminar take a tree node, it can take a pointer to a tree node, and update it when removing a node. Furthermore, once a node has been removed, you can stop:
int Eliminar(struct arbol **tree_p, int valor)
{
struct arbol *tree = *tree_p;
if (!tree)
return 0; /* nothing to remove */
if (tree->numero == valor) {
/* this is the node to remove */
*tree_p = rewrite(tree); /* rewrite subtree from here down, and update */
return 1; /* indicate that we're done */
}
/* didn't find the node to remove ... use left or right subtree for next attempt */
tree_p = tree->numero > valor ? &tree->der : &tree->izq;
return Eliminar(tree_p, valor);
}
(not sure if I got left/right correct above; I leave that for you to work on :-) ).
It's easy now to turn the recursion into iteration. The hard part is rewrite(), because you can have both left and right sub-trees of tree. If you have only one, it's easy, but if you have both, it's not so easy anymore. Again, I leave that as an exercise... :-)
You can have Eliminar return the actual removed tree node (or NULL if valor is not in the tree); that can be useful in some cases. In either case, you just do: result = Eliminar(&root, valor); to update the root node and get a success/fail indicator.

Resources