Eliminate node function from tree doesn't work in C - 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.

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).

Binary Search Tree, recursive function Exsists throw "core dumped" in comparation strings

I have the following the following structures to define an Binary Search Tree:
typedef struct Equipo {
char nombre[50];
char marcaMoto[30];
int puntuaciones;
struct Piloto pilotos[18];
struct nodo* izquierdo;
struct nodo* derecho;
} Equipo;
typedef Equipo Arbol;
the search in the tree will be performed by the string nombre, a char [50]. For create tree and insert data I use the functions:
Equipo* CrearEquipo(Equipo* e) {
Equipo* n = (Equipo *) malloc(sizeof(Equipo));
strncpy(n->nombre, e->nombre, 50);
strncpy(n->marcaMoto, e->marcaMoto, 30);
n->puntuaciones = 0;
n->derecho = n->izquierdo = NULL;
return n;
}
void InsertarEquipo(Equipo** arbol, Equipo* e) {
if (*arbol == NULL) {
Equipo* n = CrearEquipo(e);
*arbol = n;
} else {
int comparado = strncmp(e->nombre, (*arbol)->nombre, 50);
if (comparado > 0) {
InsertarEquipo(&(*arbol)->izquierdo, e);
} else {
InsertarEquipo(&(*arbol)->derecho, e);
}
}
}
And in main i use this functions to create test elements:
Equipo* equipo = (Equipo *) malloc(sizeof(Equipo));
strcpy(equipo->nombre, "C");
strcpy(equipo->marcaMoto, "B");
Arbol *arbol = CrearEquipo(equipo);
strcpy(equipo->nombre, "B");
strcpy(equipo->marcaMoto, "B");
InsertarEquipo(&arbol, equipo);
strcpy(equipo->nombre, "A");
strcpy(equipo->marcaMoto, "B");
InsertarEquipo(&arbol, equipo);
strcpy(equipo->nombre, "E");
strcpy(equipo->marcaMoto, "B");
InsertarEquipo(&arbol, equipo);
Later, I create the recursive function for comprobate if exists in the tree:
int ExisteEquipo(Equipo* arbol, char nombre[]) {
int comparado = strncmp(arbol->nombre, nombre, 50);
if (!arbol) {
return 0;
} else if (comparado > 0) {
printf("Menor ");
return ExisteEquipo(arbol->izquierdo, nombre);
} else if (comparado < 0) {
printf("Mayor ");
return ExisteEquipo(arbol->derecho, nombre);
} else {
printf("Igual ");
return 1;
}
}
(The printf's are for test). When I call the exists function with:
void DeterminarExistencia(Equipo* arbol, char nombre[50]) {
if (ExisteEquipo(arbol, nombre)) {
printf("El nodo %s existe. \n", nombre);
} else {
printf("El nodo %s no existe. \n", nombre);
}
}
DeterminarExistencia(arbol, "E");
DeterminarExistencia(arbol, "C");
DeterminarExistencia(arbol, "H");
DeterminarExistencia(arbol, "B");
but I always get the error: Violación de segmento (core dumped) [Núcleo vaciado a un archivo]
I think the problem is here:
int comparado = strncmp(arbol->nombre, nombre, 50);
You are asking if arbol is null after operating with it with the line above, so if it is null you are accessing a wrong memory address and that is causing the error.
Put it like this:
if (!arbol) {
return 0;
int comparado = strncmp(arbol->nombre, nombre, 50);
Spanish:
Básicamente cambia el orden de lo que te he dicho arriba y deberia funcionar.

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;
};

How to insert a number before each node on a list (C)?

Basically, I'm on a list and I have to insert the number 999 before each node (only when the node is even).
I could do it with the first one.
I also could insert the number after it.
But I don't know how to insert the number before the node.
I will probably have to modify the function void insertar2 because at the moment, it's inserting the new number after the node (not before as I expect).
#include <stdio.h>
#include <stdlib.h>
#include<time.h>
#define CANTIDAD_NUMEROS 10
#define DESDE 1
#define HASTA 10
typedef struct lista{
int num;
struct lista *sig;
}nodo;
void crear (nodo *pt, int);
void mostrar(nodo *pt);
nodo* insertar1(nodo* );
nodo* eliminar1(nodo* );
void insertar2 (nodo* );
void eliminar2(nodo* );
int main()
{
int i=0;
nodo *prin;
srand(time(NULL)); //Inicio la semilla para generar numeros aleatorios - una sola vez en el main
prin=(nodo*)malloc(sizeof(nodo));
crear(prin,i);
//mostrar (prin);
prin = insertar1(prin);
insertar2(prin);
mostrar (prin);
return 0;
}
void crear (nodo *registro,int cont)
{
registro->num = rand () % (HASTA-DESDE+1) + DESDE;
if (cont==CANTIDAD_NUMEROS) //si cambia se convierte en 1
registro->sig=NULL;
else
{
registro->sig=(nodo*)malloc(sizeof(nodo));
cont++;
crear (registro->sig,cont);
}
return;
}
void mostrar (nodo *registro)
{
if (registro->sig !=NULL)
{
printf ("%d\n",registro->num);
mostrar (registro->sig);
}
return;
}
//modelos a utilizar... modificarlos segun el ejercicio.
nodo* insertar1(nodo *p)
{
nodo *aux;
if(p->num%2==0)
{
aux=(nodo *)malloc(sizeof(nodo));
aux->num=999;//valor a insertar
aux->sig=p;
p=aux;
}
return p;
}
void insertar2 (nodo *p)
{nodo *aux;
while(p->sig!=NULL)
{
if(p->num%2==0) //condicion de insercion
{
aux=(nodo *)malloc(sizeof(nodo));
aux->num=999;//valor a insertar
aux->sig=p->sig;
p->sig=aux;
}
p=p->sig;
}
}
Sorry if the Spanish names of the functions/variables are confusing.
suggest changing;
nodo* insertar1(nodo *p)
{
nodo *aux;
if(p->num%2==0)
{
aux = malloc(sizeof(nodo));
aux->num = 999;//valor a insertar
aux->sig = p;
p=aux;
}
return p;
}
to insert a new node before the entry pointed to by p.
nodo* insertar1(nodo *p)
{
nodo *aux = malloc(sizeof(nodo));
aux->sig = p;
aux->num = p->num+1;
if(p->num%2==0)
{
p->num = 999;
}
return aux;
}
which still needs error checking on the value returned from malloc()

Error ! null list

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.

Resources