this code has a strange behavior in the "check_connected" procedure.
The parameter is converted to char [30] before use the strncmp function, if not, the result is "stack overflow". The problem arises in the result of the compare of two strings,
"Le solteria rige el corason.." --> this is the parameter
"La solteria rige el corazon..." --> this is stored in the list
The result is 0. I understand that the strncmp compare all the character of the strings and by common sense the result should not by zero.
#include <string.h>
#include <stdio.h>
#define LONGITUD_USUARIO 30
//estructuras de socorro
typedef struct nodo_list{
char id_usuario[LONGITUD_USUARIO];
struct nodo_list *siguiente;
} nodo;
//definiciones
#define TRUE 1
#define FALSE 0
//variables
nodo *headlist;
int size_var;
//declaracion de metodos
void initialize_list();
int add_connected(char *id_usuario);
int check_connected(char *id_usuario);
int disconnect(char *id_usuario);
int isEmpty();
int size();
//implementacion de metodos
/*
Dado un id usuario lo incorpora al principio de la lista
*/
int add_connected(char *id_usuario){
nodo nuevoNodo;
strcpy(nuevoNodo.id_usuario, id_usuario);
nuevoNodo.siguiente = headlist;
headlist = &nuevoNodo;
size_var++;
return TRUE;
}
int check_connected(char *id_usuario){
nodo *cursor = headlist;
char id_user[LONGITUD_USUARIO];
sprintf(id_user,"%s",id_usuario);
printf(" ----> %d \n",strncmp(cursor->id_usuario, id_user,LONGITUD_USUARIO));
if(!isEmpty()){
while(cursor != NULL && (strncmp(cursor->id_usuario, id_user,LONGITUD_USUARIO) != 0)){
printf(" ----> %d \n",strncmp(cursor->id_usuario, id_user,LONGITUD_USUARIO));
cursor = cursor->siguiente;
}}
return cursor != NULL ;
}
int disconnect(char *id_usuario){
nodo *cursor = headlist, *anterior = NULL;
char id_user[LONGITUD_USUARIO];
sprintf(id_user,"%s",id_usuario);
if(!isEmpty()){
while(cursor != NULL && strncmp(cursor->id_usuario, id_user, LONGITUD_USUARIO) != 0){
anterior = cursor;
cursor = cursor->siguiente;
}
if(anterior == NULL){ // es el primero
headlist = cursor->siguiente;
size_var--;
return TRUE;
}
else
if(cursor != NULL){
anterior->siguiente = cursor->siguiente;
size_var--;
return TRUE;
}
}
return FALSE;
}
void initialize_list(){
headlist = NULL;
size_var = 0;
}
int size(){
return size_var;
}
int isEmpty(){
return size() == 0;
}
void tester_list(){
initialize_list();
printf("Inicializo\n");
if(add_connected("Betina la corbina"))
printf("Agrego a Betina\n");
if(add_connected("CREO EN LA REENCARNACIÓN...(LA UÑA)"))
printf("Agrego a la uña\n");
if(add_connected("La solteria rige el corazon..."))
printf("Agrego a la solteria\n");
printf("ZISE --> %d \n",size());
if(check_connected("Le solteria rige el corason.."))
printf("Cualquiera se mando\n");
if(check_connected("La solteria rige el corazon..."))
printf("verifico correctamente solteria\n");
if(disconnect("La solteria rige el corazon..."))
printf("verifico correctamente solteria\n");
printf("ZISE --> %d \n",size());
if(add_connected("Todos los perros van al cielo..."))
printf("Agrego a perros\n");
printf("ZISE --> %d \n",size());
}
void main(){
tester_list();
}
add_connected sets the global variable headlist to point to the local, automatic variable nuevoNodo. This goes out of scope when the function returns, meaning that behaviour in check_connected and all other functions which access headlist is undefined.
I'm not sure I understand your question but would guess that you're creating a list whose elements all point to the same stack location (used for nuevoNodo in add_connected). If this is happening, note that this behaviour isn't guaranteed.
You want nodes created inside add_connected to remain valid after the function returns so need to allocate memory dynamically:
int add_connected(char *id_usuario){
nodo* nuevoNodo = malloc(sizeof(*nuevoNodo));
if (nuevoNodo == NULL) {
printf("Error - out of memory\n");
return FALSE;
}
strcpy(nuevoNodo->id_usuario, id_usuario);
nuevoNodo->siguiente = headlist;
headlist = nuevoNodo;
size_var++;
return TRUE;
}
At the end of your program, you'll now need to call a new function which calls free for each node in your list.
Related
good morning, I am making a calculator with a "Stack" of 10 positions in the "C" lenguage. What I have to do is, for example, I write the number "50", I press ENTER and that "50" must go to the first position "01". Then I write another number, for example "20" + ENTER and 20 should go to position "01", "50" goes up to "02" and so on, always after pressing ENTER. I am using the Gotoxy for this.
I can manage to print the first number in position "01" but after that I don't know how to proceed.
I'm new to programming so excuse me if I don't realize obvious things, I'm trying to learn so if you can give me a hand I would appreciate it. Here I leave the code in case you want to try it and get an idea of what I'm trying to do, thanks
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
void gotoxy(int x, int y);
void PilaPush();
void ImprimirPila();
int main() {
printf(" ____________________________________________________\n");
printf("|10:_________________________________________________|\r\n");
printf("|09:_________________________________________________|\r\n");
printf("|08:_________________________________________________|\r\n");
printf("|07:_________________________________________________|\r\n");
printf("|06:_________________________________________________|\r\n");
printf("|05:_________________________________________________|\r\n");
printf("|04:_________________________________________________|\r\n");
printf("|03:_________________________________________________|\r\n");
printf("|02:_________________________________________________|\r\n");
printf("|01:_________________________________________________|\r\n");
printf("| |\r\n");
printf("| |\r\n");
printf("|____________________________________________________|\r\n");
printf("|_____1_____|_____2_____|_____3_____|__+__|__DROP[P]_|\r\n");
printf("|_____4_____|_____5_____|_____6_____|__-__|__SWAP[S]_|\r\n");
printf("|_____7_____|_____8_____|_____9_____|__*__|__DEL[D]__|\r\n");
printf("|_____,_____|_____0_____|____EXE____|__/__|__NUM[N]__|\r\n");
printf("|_____'_____|_ARRIBA[W]_|__ABAJO[Z]_|_____|_SWAP1[Q]_|\r\n");
gotoxy(3, 12);
PilaPush();
ImprimirPila();
getch();
return 0;
}
void gotoxy(int x, int y) {
HANDLE Ventana;
Ventana = GetStdHandle(STD_OUTPUT_HANDLE);
COORD Coordenadas;
Coordenadas.X = x;
Coordenadas.Y = y;
SetConsoleCursorPosition(Ventana, Coordenadas);
}
typedef struct Nodo {
int elemento;
struct Nodo *siguiente;
} Nodo;
// funciones para utilizar un manejador global
Nodo *primero = NULL;
// Insertar un nuevo nodo a la pila
void PilaPush() {
Nodo *nuevo;
// crear el nuevo Nodo.
nuevo = (Nodo *)malloc(sizeof(Nodo)); // Asignar de forma dinamica un espacio de memoria al Nodo
printf(" ");
scanf("%d", &nuevo->elemento);
// Agregar el nodo al principio de la Pila
nuevo->siguiente = primero; // El nuevo dato ahora es primero, que apunta a (NULL)
primero = nuevo; // Primero (NULL) ahora es el nuevo dato
}
// sacar un elemento de una pila
void ImprimirPila() {
Nodo *actual = (Nodo *)malloc(sizeof(Nodo));
actual = primero;
if (primero != NULL) {
while (actual != NULL) {
gotoxy(9, 10);
printf("%d", actual->elemento);
actual = actual->siguiente;
gotoxy(3, 12);
printf(" ");
gotoxy(3, 12);
}
} else {
printf("No hay ningun dato ");
}
}
I have this program (school exercise) that simulates a software for managing tests and exercises. Everything works fine... until it doesn't. The second time, in the menu of the program, I want to add an exercise (calling so the function called inserisciEsercizio, "addExercise" in English), the malloc (esercizioPtr newEsercizio = (esercizioPtr)malloc(sizeof (esercizio));) "triggers a breakpoint". I attach the function and where the structs are declared.
What does that mean? How can I resolve it?
Thank you.
I tried looking it up, but I couldn't find anything that could help me understand.
The variables are written in Italian (half in Italian, half in English to be honest). Hope it's not too much of a problem.
struct ListaEsercizi
{
esercizioPtr esercizio;
struct ListaEsercizi *nextListaEsercizi;
};
typedef struct ListaEsercizi listaEsercizi;
typedef listaEsercizi *listaEserciziPtr;
struct Esercizio
{
char titolo[20];
char domanda[40];
char risposte[3][50];
int difficolta;
struct Esercizio *nextEsercizio;
};
typedef struct Esercizio esercizio;
typedef esercizio *esercizioPtr;
void inserisciEsercizio(esercizioPtr *firstEsercizio, autorePtr Autore)
{
listaEserciziPtr newLista = (listaEserciziPtr)malloc(sizeof (listaEsercizi));
esercizioPtr newEsercizio = (esercizioPtr)malloc(sizeof (esercizio)); // <--- here!
//se ne stabiliscono i parametri
if (newEsercizio != NULL)
{
newEsercizio->nextEsercizio = NULL;
printf("Inserisci titolo esercizio ");
scanf_s("%s", newEsercizio->titolo, 20);
printf("Inserisci domanda esercizio: ");
scanf_s("%s", newEsercizio->domanda, 30);
printf("Inserisci difficolta esercizio: ");
scanf_s("%d", &(newEsercizio->difficolta));
for (int i = 0; i < 3; i++)
{
printf(" Scrivere la risposta:\n");
scanf_s("%s", newEsercizio->risposte[i], 100);
}
if (*firstEsercizio == NULL) //caso in cui creo il primo oggetto
{
*firstEsercizio = newEsercizio;
}
else //se non il primo lo inserisco all'interno della lista oggetti
{
newEsercizio->nextEsercizio = *firstEsercizio;
*firstEsercizio = newEsercizio;
}
//mettere malloc
if (newLista != NULL)
{
newLista->nextListaEsercizi = NULL;
newLista->esercizio = newEsercizio;
if (Autore->esercizi == NULL) //caso in cui creo il primo oggetto
{
Autore->esercizi = newLista;
}
else //se non il primo lo inserisco all'interno della lista oggetti
{
newLista->nextListaEsercizi = Autore->esercizi;
Autore->esercizi = newLista;
}
}
else
{
//nel caso malloc restituisca NULL
printf("Memoria non disponibile \n");
}
}
else
{
//nel caso malloc restituisca NULL
printf("Memoria non disponibile \n");
}
}
In you declarations you have:
char risposte[3][50];
And later in the code you have:
scanf_s("%s", newEsercizio->risposte[i], 100);
It allows a 100 chars in a 50 chars array, which probaly leads to memory corruption in the first call to inserisciEsercizio. Using sizeof instead of a constant with scanf_s is usually a good idea:
scanf_s("%s", newEsercizio->risposte[i], sizeof(newEsercizio->risposte[i]));
I have to do create a tree to register some passengers in it (from a plane flight) and then i will search them by their first letter.
My issue is that insert and print function work very well, but the search function do well for first time but when I want to do some other thing after in the main, it doesn't run the other function or things
(I tried to ask the user a letter, then use the function on research (works well here) but then for a second time to ask an other letter to user, and it prints "first letter of the person you are looking for" but i can't write the letter and it does not launch the function after this. so it stop the program there
int i;
char c;
typedef struct Passager
{
char nom[20];
char prenom[20];
int age;
int num_siege;
} Passager;
Passager liste_passagers[30]; //30 = nombre de passagers
typedef struct Arbre
{
Passager value;
struct Arbre *fils_gauche;
struct Arbre *fils_droit;
struct Arbre *racine;
} Arbre;
Arbre *const empty = NULL;
Arbre *passengers = empty; //passengers = arbre des passagers
/*--------------------------------------------*/
void liste_lettre_nom(Arbre *tree, char a)
{
Arbre *temp;
temp = tree;
if (!temp)
{
return;
}
else
{
if (a < temp->value.nom[0])
{
liste_lettre_nom(temp->fils_gauche, a);
}
if (a > temp->value.nom[0])
{
liste_lettre_nom(temp->fils_droit, a);
}
if (a == temp->value.nom[0])
{
printf("passager : \n");
print_passager(temp->value);
liste_lettre_nom(temp->fils_gauche, a);
liste_lettre_nom(temp->fils_droit, a);
}
}
}
/*--------------------------------------------*/
int main()
{
FILE* fichier = NULL;
fichier = fopen("/Users/Patoch/Desktop/Patoch /UNI/Informatique/info sem 2/Structure de données/Labo/TP3/Passager2.txt", "r");
if (fichier == NULL)
{ //test de la bonne ouverture du fichiers
printf("Impossible d'ouvrir le fichier Passagers.docx");
exit(EXIT_FAILURE);
}
for (i=0; i<(sizeof(liste_passagers)/sizeof(liste_passagers[0])); i++)
{
fscanf(fichier, "%s %s %d %d", liste_passagers[i].nom, liste_passagers[i].prenom, &liste_passagers[i].age, &liste_passagers[i].num_siege);
}
passengers = insertion(passengers, liste_passagers[1]);
passengers = insertion(passengers, liste_passagers[2]);
passengers = insertion(passengers, liste_passagers[0]);
passengers = insertion(passengers, liste_passagers[5]);
passengers = insertion(passengers, liste_passagers[26]);
print_arbre(passengers);
printf("-----------------------------\n");
printf("1ere lettre du nom de la personne recherchée: \n");
scanf("%c", &c);
liste_lettre_nom(passengers, c);
printf("-----------------------------\n");
printf("1ere lettre du nom de la personne recherchée: \n");
scanf(" %c", &c);
liste_lettre_nom(passengers, c);
destroy(passengers);
fclose(fichier);
return 0;
}
I have this code and I don't know why after, I ask if you want to introduce another student and I say 1 or 0 the program ends and said segmentation fault (core dumped).
I ask to introduce another student in _nodo *insertaEnLista
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct actividades
{
char tipoDeActividad[22];
char diaDeLaSemana[12];
char horaDeIncio[8];
char horaDeFin[8];
};
struct materias
{
char nombre[30];
char profesor[30];
char tipoDeMateria[20];
struct actividades *actividad;
};
struct alumnos
{
char nombre[30];
int cedula;
int telefono;
struct materias *materia;
struct alumnos *siguiente;
};
typedef struct alumnos _nodo;
_nodo *crearLista(_nodo *apuntador);
bool listaVacia(_nodo *apuntador);
_nodo *insetarEnLista(char nombre[], long cedula, long telefono, _nodo *apuntador);
void imprimirLista (_nodo *apuntador);
_nodo *crearNodo(char nombre[], long int cedula, long int telefono);
//AQUI SE CREA LISTA Y SE PONE PARA QUE APUNTE A NULL
_nodo *crearLista(_nodo *apuntador)
{
return (apuntador = NULL);
}
//ESTA FUNCION VERIFICA SI LA LISTA ESTA VACIA
bool listaVacia(_nodo *apuntador)
{
if (apuntador == NULL)
return (true);
else
return (false);
}
//AQUI SE CREA EL NUEVO NODO DE LA LISTA
_nodo *crearNodo(char nombre[], long cedula, long telefono)
{
_nodo *registroNuevo;
registroNuevo = (_nodo *) malloc(sizeof(_nodo));
printf("\n----NUEVO ELEMENTO----\n");
printf("NOMBRE: ");
fflush(stdin);
scanf("%s",nombre);
printf("CEDULA: ");
fflush(stdin);
scanf("%ld", &cedula);
printf("TELEFONO: ");
fflush(stdin);
scanf("%ld", &telefono);
fflush(stdin);
strcpy(registroNuevo->nombre, nombre);
registroNuevo->cedula = cedula;
registroNuevo->telefono = telefono;
registroNuevo->siguiente = NULL;
return registroNuevo;
}
//AQUI SE INSERTA EL NODO EN LA LISTA LUGEO DE SER CREADO POR LA FUNCION crearNodo
_nodo *insetarEnLista(char nombre[], long cedula, long telefono, _nodo *apuntador)
{
_nodo *registroNuevo, *apuntadorAuxiliar;
char respuesta,ch;
do
{
registroNuevo=crearNodo(nombre, cedula, telefono);
if (listaVacia(apuntador)) apuntador = registroNuevo;
else
{
apuntadorAuxiliar = apuntador;
while (apuntadorAuxiliar->siguiente != NULL)
apuntadorAuxiliar = apuntadorAuxiliar->siguiente;
apuntadorAuxiliar->siguiente = registroNuevo;
}
printf("\nPARA INGRESAR A OTRO ALUMNO MARQUE... 1");
printf("\nPARA SALIR MARQUE... '0'\n");
while((ch = getchar()) != EOF && ch != '\n');
scanf("%c", &respuesta);
fflush(stdin);
printf("RESPUESTA = %c", respuesta);
}while (strcmp(&respuesta, "1")==0);
return apuntador;
}
//IMPRIMIR LOS NODOS DE LA LISTA
void imprimirLista (_nodo *apuntador)
{
_nodo *apuntadorAuxiliar;
apuntadorAuxiliar = apuntador;
if (apuntador == NULL)
printf("NO HAY ELEMENTOS EN LA LISTA \n");
else
{
while(apuntador != NULL)
{
printf(" \n------------NODO-------------- ");
printf("\nNOMBRE: %s \n\n", apuntadorAuxiliar->nombre);
printf("\n\nCEDULA: %d \n", apuntadorAuxiliar->cedula);
printf("\nTELEFONO: %d \n", apuntadorAuxiliar->telefono);
apuntadorAuxiliar = apuntadorAuxiliar->siguiente;
}
}
return;
}
int main()
{
/*printf("INTRODUZCA LOS NUMEROS DE CEDULA QUE DESEA IMPRIMIR \n");*/
_nodo *inicioLista;
int cedula;
int telefono;
char nombre[20];
inicioLista = crearLista(inicioLista);
inicioLista = insetarEnLista(nombre, cedula, telefono, inicioLista);
imprimirLista(inicioLista);
return 0;
}
How can I do to fix the problem.
You should step through the code in a debugger and look at the variables at each step to determine the line of code that is causing the issue.
Here is one issue, there may be others.
In this line
}while (strcmp(&respuesta, "1")==0);
you are using strcmp with a variable (respuesta) that contains a single character. strcmp is expecting a null terminated string (an array of characters with a zero byte at the end). As you may not have a zero byte after the variable, this may cause strcmp to read memory that it shouldn't (this is a buffer overrun)
Much simpler to just use:
}while (respuesta == '1');
I'm coding a Bison-Flex calculator following the Bison documentation example. When I try to assign a value to a variable it works properly when the value doesn't include other variables. For example, the calculator assigns to the variable a the correct value after this operation: a = 2 + 3 + 5 . However, if then I try to assign the value of a to another variable b, like b = a + 1, the calculator stores the value of a+1 in the variable a. If I try to print the name of $1 in my assignment rule in the Bison code, I get that in last example, the program is getting the variable a as $1, not b. I also tried enabling the debug option and it looks like Bison is applying the rules and the reductions properly.
The Bison file, calculadora_bison.y:
%{
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "TablaSimbolos.h"
int yylex (void);
int yyerror (char *s);
%}
%union {
float valor;
NodoArbol * tptr;
};
%token <valor> NUM
%token <tptr> VAR FNCT
%type <valor> exp
%right '='
%left '-' '+'
%left '*' '/'
%left NEG
%right '^'
%%
input: /* vac´ıo */
| input line
;
line: '\n'
| exp '\n' { printf ("\t%.10g\n", $1); }
| exp ';' '\n' { }
| error '\n' { yyerrok; }
;
exp: NUM { $$ = $1;}
| VAR { $$ = $1->valor.val;}
| VAR '=' exp { $$ = $3; ActualizaNodoFloat($1->nombre, $3);}
| FNCT '(' exp ')' { $$ = (*($1->valor.fnctptr))($3);}
| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 - $3; }
| exp '*' exp { $$ = $1 * $3; }
| exp '/' exp { $$ = $1 / $3; }
| '-' exp %prec NEG { $$ = -$2; }
| exp '^' exp { $$ = pow ($1, $3); }
| '(' exp ')' { $$ = $2; }
;
%%
struct init{
char *fname;
double (*fnct)();
};
struct init arith_fncts[] =
{
{ "atan", atan },
{ "cos", cos },
{ "exp", exp },
{ "ln", log },
{ "sin", sin },
{ "sqrt", sqrt },
{ 0, 0 },
};
int init_table(){
int i;
CrearArbol();
for (i = 0; arith_fncts[i].fname != 0; i++){
InsertarNodoFuncion(FNCT, arith_fncts[i].fname, arith_fncts[i].fnct);
}
return 0;
}
int main (){
init_table ();
yyparse ();
return 0;
}
int yyerror (char *s){
printf ("%s\n", s);
return 0;
}
My Flex code, calculadora_flex.l:
%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "TablaSimbolos.h"
#include "calculadora_bison.tab.h"
%}
ALNUM [a-zA-Z][a-zA-Z0-9]*
DIGITO [0-9]*
FLOAT {DIGITO}*\.{DIGITO}*
OPERADORES [-+()=*^/\n;]
%%
{ALNUM} {
NodoArbol s;
s = buscaTS(yytext);
yylval.tptr = &s;
return s.tipo;
}
{FLOAT} {
yylval.valor = atof(yytext);
return NUM;
}
{DIGITO} {
yylval.valor = atoi(yytext);
return NUM;
}
{OPERADORES} {
return (int)yytext[0];
}
. { };
%%
For the symbol table, I'm using a BST in C. The header file is this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct NodoArbolType{
int tipo; //Componente léxico
char * nombre; // Lexema
union {
float val;
double (*fnctptr)();
} valor;
struct NodoArbolType *izda; //Nodos hijo
struct NodoArbolType *dcha;
}NodoArbol;
void ActualizaNodoFloat(char * nombrenodo, float valor);
void CrearArbol();
NodoArbol BuscarArbol(char * nombre);
NodoArbol buscaTS(char * nombre);
int InsertarNodoEntero(NodoArbol *newNode);
NodoArbol InsertarNodo(int Key, char * cA);
int InsertarNodoFloat(int Key, char * cA, float val);
int InsertarNodoFuncion(int Key, char * cA, double (*fnct)());
void EliminarArbol();
void ImprimirArbol90grados();
void ImprimirArbolConValores();
int EliminarNodo(char * nombre);
The .c file:
#include "TablaSimbolos.h"
#include "calculadora_bison.tab.h"
//Declaramos el nodo como estático para que solo pueda ser accedido desde aquí
static NodoArbol *raiz;
/**
* Función que limpia recursivamente a partir de un nodo
*/
static void LimpiarArbol(NodoArbol *T){
if(T==NULL) return;
if(T->izda != NULL) LimpiarArbol(T->izda); //Si sus hijos no son NULL, también
//se limpian
if(T->dcha != NULL) LimpiarArbol(T->dcha);
free(T); //Libera la memoria del puntero al nodo
return;
}
/*
* Función que crea un árbol a partir del nodo raíz
*/
void CrearArbol(){
LimpiarArbol(raiz); //Primero libera el nodo raíz por si existía un árbol previo
raiz = NULL;
return;
}
/**
* Función que determina si un árbol no tiene ningún nodo
*/
int esVacio(){
return(raiz==NULL);
}
/*
* Función que busca en un árbol un nodo a partir de un string que correspondería
* al campo nombre de los nodos
*/
NodoArbol BuscarArbol(char * nombre){
NodoArbol *temp;
temp = raiz; //Puntero auxiliar
//Mientras temp no sea NULL (haya llegado al final del árbol) o no se
//encuentre el string nombre
while((temp != NULL) && (strcmp(nombre, temp->nombre)!=0)){
if(strcmp(nombre, temp->nombre)<0) //Si el string es "menor" que el
//nombre del nodo a examinar (por ejemplo
// function<while), sigue examinando por
//el nodo hijo izquierdo
temp = temp->izda;
else if(strcmp(nombre, temp->nombre)>0) //Análogamente al caso anterior
//pero cuando sea mayor
temp = temp->dcha;
}
if(temp == NULL){ //Si el nombre no se ha encontrado, devuelve error
temp = (NodoArbol *)malloc(sizeof(NodoArbol));
temp->tipo = -1;
}
return(*temp);
}
/**
* Función que inserta un NodoArbol en el árbol
*/
int InsertarNodoEntero(NodoArbol *nuevoNodo){
NodoArbol *temp;
NodoArbol *anterior;
temp = raiz;
anterior = NULL;
//Busca la posición en la que se insertará el nodo
while((temp != NULL) && (strcmp(nuevoNodo->nombre, temp->nombre)!=0)){
anterior = temp;
if(strcmp(nuevoNodo->nombre, temp->nombre)<0)
temp = temp->izda;
else if(strcmp(nuevoNodo->nombre, temp->nombre)>0)
temp = temp->dcha;
}
//Añadimos el nodo al árbol
if(anterior == NULL) //Si anterior==NULL, el nodo es el primero en introducirse
raiz = nuevoNodo;
else {
//Si el nombre de nuevoNodo < anterior->nombre, lo introducimos a la izquierda
if(strcmp(nuevoNodo->nombre, anterior->nombre)<0)
anterior->izda = nuevoNodo;
//En el caso contrario, lo introducimos a la izquierda
else if(strcmp(nuevoNodo->nombre, anterior->nombre)>0)
anterior->dcha = nuevoNodo;
}
return(nuevoNodo->tipo);
}
/**
* Función que inserta un nodo en el árbol a partir de su valor y su nombre
*/
NodoArbol InsertarNodo(int valor, char *cA){
NodoArbol *nuevoNodo;
nuevoNodo = (NodoArbol *)malloc(sizeof(NodoArbol));
nuevoNodo->tipo = valor;
nuevoNodo->nombre = (char*)malloc(sizeof(char) * strlen(cA));
strcpy(nuevoNodo->nombre, cA);
nuevoNodo->valor.val=0;
nuevoNodo->izda = nuevoNodo->dcha = NULL;
InsertarNodoEntero(nuevoNodo);
return(*nuevoNodo);
}
int InsertarNodoFloat(int Key, char * cA, float val){
NodoArbol *nuevoNodo;
nuevoNodo = (NodoArbol *)malloc(sizeof(NodoArbol));
nuevoNodo->tipo = Key;
nuevoNodo->valor.val = val;
nuevoNodo->nombre = (char*)malloc(sizeof(char) * strlen(cA));
strcpy(nuevoNodo->nombre, cA);
nuevoNodo->izda = nuevoNodo->dcha = NULL;
return(InsertarNodoEntero(nuevoNodo));
}
int InsertarNodoFuncion(int Key, char * cA, double (*fnct)()){
NodoArbol *nuevoNodo;
nuevoNodo = (NodoArbol *)malloc(sizeof(NodoArbol));
nuevoNodo->tipo = Key;
nuevoNodo->valor.fnctptr = fnct;
nuevoNodo->nombre = (char*)malloc(sizeof(char) * strlen(cA));
strcpy(nuevoNodo->nombre, cA);
nuevoNodo->izda = nuevoNodo->dcha = NULL;
return(InsertarNodoEntero(nuevoNodo));
}
/*
* Función que busca un nodo a partir del nombre y devuelve su valor. Si no lo
* encuentra, inserta el nodo y devuelve el valor del nuevo nodo.
*/
NodoArbol buscaTS(char * nombre){
NodoArbol id;
id=BuscarArbol(nombre);
if(id.tipo==-1){
id=InsertarNodo(VAR, nombre);
}
return id;
}
void ActualizaNodoFloat(char * nombreNodo, float valor){
//printf("en actualizarNodoFloat, nombreNodo = %s \n", nombreNodo);
EliminarNodo(nombreNodo);
InsertarNodoFloat(VAR, nombreNodo, valor);
//NodoArbol nodo = BuscarArbol(nombreNodo);
//printf("en buscar dentro de actualizaNodo%f", nodo.valor.val);
}
/*
* Función que elimina un árbol desde la raíz, liberando la memoria ocupada por él
*/
void EliminarArbol(){
LimpiarArbol(raiz);
}
void ImprimirNodoConValores(NodoArbol * nodo){
if(nodo->izda!=NULL){
ImprimirNodoConValores(nodo->izda);
}
printf("%d - %s", nodo->tipo, nodo->nombre);
if(nodo->tipo==VAR){
printf(" --> %f \n", nodo->valor.val);
}else{
printf("\n");
}
if(nodo->dcha!=NULL){
ImprimirNodoConValores(nodo->dcha);
}
}
void ImprimirArbolConValores(){
ImprimirNodoConValores(raiz);
}
int EliminarNodo(char * nombre){
NodoArbol * anterior;
NodoArbol *temp;
NodoArbol *delParent; // Parent of node to delete
NodoArbol *delNode; // Node to delete
temp = raiz;
anterior = NULL;
//Encontramos el nodo a eliminar
while((temp != NULL) && (strcmp(temp->nombre, nombre)!=0)){
anterior = temp;
if(strcmp(nombre, temp->nombre)<0)
temp = temp->izda;
else if(strcmp(nombre, temp->nombre)>0)
temp = temp->dcha;
}
if(temp == NULL){ // No se encontró el nodo
printf("Key not found. Nothing deleted. El nombre es %s\n", nombre);
return 0;
}else{
if(temp == raiz){ //Eliminamos la raíz
delNode = raiz;
delParent = NULL;
}else{
delNode = temp;
delParent = anterior;
}
}
// Case 1: Deleting node with no children or one child
if(delNode->dcha == NULL){
if(delParent == NULL) // If deleting the root
{
raiz = delNode->izda;
free(delNode);
return 1;
}
else
{
if(delParent->izda == delNode)
delParent->izda = delNode->izda;
else
delParent->dcha = delNode->izda;
free(delNode);
return 1;
}
}
else // There is at least one child
{
if(delNode->izda == NULL) // Only 1 child and it is on the right
{
if(delParent == NULL) // If deleting the root
{
raiz = delNode->dcha;
free(delNode);
return 1;
}
else
{
if(delParent->izda == delNode)
delParent->izda = delNode->dcha;
else
delParent->dcha = delNode->dcha;
free(delNode);
return 1;
}
}
else // Case 2: Deleting node with two children
{
temp = delNode->izda;
anterior = delNode;
while(temp->dcha != NULL)
{
anterior = temp;
temp = temp->dcha;
}
// Copy the replacement values into the node to be deleted
delNode->tipo = temp->tipo;
strcpy(delNode->nombre, temp->nombre);
// Remove the replacement node from the tree
if(anterior == delNode)
anterior->izda = temp->izda;
else
anterior->dcha = temp->izda;
free(temp);
return 1;
}
}
}
This really has very little to do with bison or flex.
The final problem is here, in your flex action for {ALNUM}; specifically the highlighted line:
{ALNUM} {
NodoArbol s;
s = buscaTS(yytext);
yylval.tptr = &s;
return s.tipo;
}
At that point, s is a local variable (local to the code block), which means that its lifetime ends with the return statement. Consequently, the address assigned to yylval.tptr is a dangling pointer, and what it points to is completely unpredictable. (This is undefined behaviour, so the consequences could be even more dramatic.)
But, really, it is a little weird that buscaTS returns a copy of the entire NodoArbol. Normally, a binary tree lookup would return a pointer to the tree node, since there is no reason for binary search tree nodes to move around.
Unfortunately, in your design the nodes do move around because when you modify the value associated with a symbol, you delete the symbol's node and then recreate it, rather than just changing the associated value. IMO, that's completely unnecessary and highly inefficient, and it also makes the symbol table design more difficult. If you change that, then you can just return the address of a node from BuscarArbol (and consequently from BuscaTS), and then you can use the returned pointer to update the value of the symbol in cases where that is necessary.
A couple of other things I noticed looking around your code:
When BuscarArbol fails to find a symbol, it mallocs a new node and then returns a copy of that node. The newly allocated node is never entered into the tree, and is never freed. If you change BuscarArbol to return a pointer, it could return the pointer to the newly-allocated node, leaving the caller the responsibility of inserting the node into the tree or freeing it. Or it could just return NULL instead of faking a node with type -1. (That would be my preference, FWIW.)
There is a lot of code duplication in the various ways of inserting a new node. I would suggest having a single routine which takes a name and inserts a new node with that name, and returns the pointer to the new node. The caller can then just fix the symbol type and value.
Also, when you do create a new node with a name, you copy the name like this:
nuevoNodo->nombre = (char*)malloc(sizeof(char) * strlen(cA));
strcpy(nuevoNodo->nombre, cA);
That's a buffer overrun, because character strings in C are NUL-terminated and consequently require one more byte than the string length. So strcpy will overwrite the byte after the end of the allocation, which is undefined behaviour.
That's just what I noticed. I didn't examine the code in detail.