Newsgroup: it.comp.lang.c
Titolo: Problema funzione con struttura ad albero

salve a tutti...
è la prima volta che partecipo a questo gruppo, spero di riuscire a
trovare qualcuno che mi aiuti.
premetto che non sono un programmatore.
Ho passato tutto il pomeriggio a cercare di scrivere un programma che
implementi una sorta di conta-punteggi...la visualizzazione dei campi
avviene tramite 2 classifiche ordinate per punteggio e  ordine
alfabetico.
I problemi sorgono nel momento in cui si inseriscono 2 volte lo stesso
identificativo, se ad esempio inserisco "mario 5" dapprima e "mario 9"
poi, dovrei visualizzare "mario 14", per fare questo, ho deciso di
cancellare il record in questione (mario 5) e reinserirlo aggiornando
il punteggio...
tuttavia questo riesce solo in parte...e non capisco perchè...
provate nel codice seguente a inserire le seguenti coppie e
visualizzare le 2 classifiche
-mario 4
-franco 5
-mario 4 (e fin qui dovrebbe funzionare->mario 8)
-alberto 2
-alberto 8 (perchè ora il campo è duplicato nella classifica
punteggi?)
vi ringrazio per qualsiasi osservazione anticipatamente
ECCO IL CODICE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
#define MAXSIZEN 30
/*struttura in cui memorizzo i dati*/
typedef struct rank{
        char nome[MAXSIZEN];
        int punt;
        }ranking;
/*struttura di un elemento dell'albero*/
typedef struct elenco{
        ranking *elem;
        struct elenco *left;
        struct elenco *right;
        }player;
/*radici di due alberi di puntatori alla struttura dati*/
        player *root1=NULL;
        player *root2=NULL;
/*variabile globale ausiliaria*/
        int auxp;
/*prototipi*/
void add(char name[MAXSIZEN], int punteggio);
void stampa(void);
void stampaA(void);
void menu(void);
void stampa_dati(player *r);
player insert_nome(player **pr,ranking *p);
player insert_punt(player **pr,ranking *p);
player *cerca(player *r,char user[MAXSIZEN]);
int cancella(player **pr,char user[MAXSIZEN]);
/*void re(player **pr);*/
main()
{
  menu();
}
/* interfaccia utente */
void menu(void)
{
int fine=0;
char scelta;
char giocatore[MAXSIZEN];
int punteg;
clrscr();
while(!fine){
             printf("\n---------------------------");
             printf("\n          Menu             ");
             printf("\n---------------------------");
             printf("\n1: Inserisci               ");
             printf("\n2: Stampa classifica       ");
             printf("\n3: Elenco alfabetico       ");
             printf("\n0: Fine                    ");
             printf("\n---------------------------\n");
             printf("=>");
             fflush(stdin);
             auxp=0;
             scelta=getchar();
             switch(scelta){
                            case '1':
                            	 /*clrscr();*/
                                 printf("\nInserisci nome del
giocatore:\n=>");
                                 scanf("%s",giocatore);
                                 printf("\nInserisci punteggio:\n=>");
                                 scanf("%d",&punteg);
                                 add(giocatore,punteg);
                                 /*clrscr();*/
                                 break;
                            case '2':
                            	 /*clrscr();*/
                                 stampa();
                                 break;
                            case '3':
                            	 /*clrscr();*/
                                 stampaA();
                                 break;
                            case '0':
                                 fine=1;
                                 break;
                            default:
                                 printf("scelta non valida");
                                 break;
                            }
             }
}
/* aggiungi giocatore-punteggio */
void add(char name[MAXSIZEN], int punteggio)
{
     ranking *p,*s;
     p=(ranking*)malloc(sizeof(ranking));
     strcpy(p->nome,name);
     p->punt=punteggio;
     s=cerca(root1,name);
     if (s==NULL)
     {
	 printf("\nnuovo");
     insert_nome(&root1,p);
     insert_punt(&root2,p);
     }
     else
     {
	 printf("\ngia esiste");
     cancella(&root1,name);
     cancella(&root2,name);
     add(name,punteggio+auxp);
     }
}
/*inserisco un nodo nell'albero giocatori (root1)*/
player insert_nome(player **pr,ranking *p)
{
if(*pr!=NULL){
              if(strcmp((*pr)->elem->nome,p->nome)>0)
              return insert_nome(&(*pr)->left,p);
              else if(strcmp((*pr)->elem->nome,p->nome)<0)
              return insert_nome(&(*pr)->right,p);
              }
else          {
              *pr=(player*)malloc(sizeof(player));
              (*pr)->elem=p;
              (*pr)->right=(*pr)->left=NULL;
              }
}
/*visita inorder*/
void stampa_dati(player *r)
{
if(r!=NULL){
            stampa_dati(r->left);
            printf("\n%s\t%d",r->elem->nome,r->elem->punt);
            stampa_dati(r->right);
            }
}
/*idem come sopra ma per punteggi*/
player insert_punt(player **pr,ranking *p)
{
if(*pr!=NULL){
              if((*pr)->elem->punt < p->punt)
              return insert_punt(&(*pr)->left,p);
              else
              return insert_punt(&(*pr)->right,p);
              }
else          {
              *pr=(player*)malloc(sizeof(player));
              (*pr)->elem=p;
              (*pr)->right=(*pr)->left=NULL;
              }
}
/*cerca nell'albero e restituisce il puntatore al nodo o NULL se il
nome non esiste*/
player *cerca(player *r,char user[MAXSIZEN])
{
if(r!=NULL){
            if(strcmp(r->elem->nome,user)>0)
            return cerca(r->left,user);
            else if(strcmp(r->elem->nome,user)<0)
            return cerca(r->right,user);
            else
            return r;
            }
else
            return NULL;
}
/*cancella dall'albero e e memorizza auxp*/
int cancella(player **pr,char user[MAXSIZEN])
{
    player **q, *r;
    if(*pr!=NULL)
    	if(strcmp((*pr)->elem->nome,user)>0)
    		return cancella(&(*pr)->left,user);
    	else if(strcmp((*pr)->elem->nome,user)<0)
    		return cancella(&(*pr)->right,user);
    	else{
	    	auxp=(*pr)->elem->punt;
	    	if((*pr)->left==NULL){
                               r=*pr;
                               *pr=(*pr)->right;
                               free(r);
                               }
         	else if((*pr)->right==NULL){
                               r=*pr;
                               *pr=(*pr)->left;
                               free(r);
                               }
         	else{
	         	printf("\nesistono entrambi");
	         	for(q=&(*pr)->left;(*q)->right!=NULL;q=&(*pr)->right);
              	r=*q;
              	*q=(*q)->left;
              	r->left=(*pr)->left;
              	r->right=(*pr)->right;
              	free(*pr);
              	*pr=r;
              	}
              	return 1;
         	}
         else
         	return 0;
}
/**/
void stampa(void)
{
 printf("\n\t\tClassifica:\n");
 stampa_dati(root2);
 printf("\n\n\n");
}
/**/
void stampaA(void)
{
 printf("\n\t\tElenco alfabetico giocatori:\n");
 stampa_dati(root1);
 printf("\n\n\n");
}

     p=(ranking*)malloc(sizeof(ranking));
Via i cast dai valori di ritorno di malloc(): in C, al contrario che
in C++, non servono.
<snip su tutto il resto: non riesco a leggerlo :-)... te lo riscrivo,
faccio prima ;-)>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef strdup
char *strdup(const char *s) {
     char *r;
     return (r=calloc(strlen(s)+1,1))?strcpy(r,s):0;
}
#endif
void flushkb(void) { while (getchar()!='\n') ; }
char *read_str(char *s, int max) {
     char *r=fgets(s, max, stdin);
     if (r) {
        int len=strlen(s);
        if (s[len-1]=='\n')
           s[len-1]='\0';
     }
     return r;
}
int read_int(void) {
    int i;
    scanf("%d", &i);
    flushkb();
    return i;
}
typedef int (*unary_operation_t)(const void *p);
typedef int (*binary_operation_t)(const void *p1, const void *p2);
typedef struct node_tag {
        char *name;
        int score;
        struct node_tag *next;
} node_t, *pnode_t;
pnode_t node_new(const char *n, const int s) {
        pnode_t i=malloc(sizeof *i);
        if (i) {
           i->next=0;
           i->name=strdup(n);
           i->score=s;
        }
        return i;
}
void node_free(pnode_t self) {
     if (self) {
        if (self->name) free(self->name);
        free(self);       
     }
}
void list_print(pnode_t head, unary_operation_t print) {
     if (head) {               
        if (print) print(head);
        printf("\n");
        list_print(head->next, print);
     }
     else printf("(end of the list)\n");
}
void list_free(pnode_t head) {
     if (head) {
        list_free(head->next);       
        node_free(head);       
     }
}
int name_compare(const void *p1, const void *p2) {
    return strcmp(((pnode_t)p2)->name, (*((pnode_t*)p1))->name);
}
int score_compare(const void *p1, const void *p2) {
    int r;
    if (!name_compare(p1,p2)) 
      r=0;
    else
      r=((*((pnode_t*)p1))->score-((pnode_t)p2)->score);
    return r;
}
int name_handle_eq(const void *p1, const void *p2) {
    (*((pnode_t*)p1))->score += ((pnode_t)p2)->score;
    node_free((pnode_t)p2);
    return 1;
}
int score_handle_eq(const void *p1, const void *p2) {
    if (!name_compare(p1, p2)) {
       printf("DEBUG nomi uguali!!!!\n");                   
       (*((pnode_t*)p1))->score += ((pnode_t)p2)->score;     }
    node_free(p2);                          
    return 1;
}
int name_print(const void *p) {
    printf("\"%s\": %d", 
     ((pnode_t)p)->name, ((pnode_t)p)->score);
    return 1;
}
int score_print(const void *p) {
    printf("%d: \"%s\"", 
           ((pnode_t)p)->score, ((pnode_t)p)->name);
    return 1;
}
void list_add(pnode_t *phead, pnode_t new_node, 
              binary_operation_t compare,
              binary_operation_t handle_eq) {
     if (*phead) {
        if (compare) {         
           int cmp_res = compare(phead, new_node);
           if (cmp_res<0) {
              pnode_t temp=*phead;
              *phead=new_node;
              (*phead)->next=temp;
           }
           else
           if (cmp_res>0)
              list_add(&(*phead)->next, new_node, compare, handle_eq);
else
           if (handle_eq) handle_eq(phead, new_node);
        }
     }
     else {
       *phead = new_node;
     }
}
void ask_player(char *n, int max, int *s) {
     printf("giocatore: "); read_str(n, max);
     printf("punteggio: "); *s=read_int();
}
int main()
{
    int end_cycle=0;
    pnode_t p_head=0;     
    pnode_t s_head=0;
    while (!end_cycle) {
      printf("menu: \n"\
             "1) inserisci\n"\
             "2) classifica\n"\
             "3) elenco alfabetico\n"\
             "4) esci\n"\
             "==> ");
      switch (read_int()) {
         case 1: {
            char name[32]={0};
            int score=0;
            ask_player(name, sizeof name, &score);
            list_add(&p_head, node_new(name, score), name_compare,
name_handle_eq);
            list_add(&s_head, node_new(name, score), score_compare,
score_handle_eq);
            break;
         }
         case 2: list_print(s_head, score_print); break;
         case 3: list_print(p_head, name_print); break;
         case 4: end_cycle=1; break;
      }    
    }
    list_free(p_head);     
    list_free(s_head);     
    return 0;
}

 int main()
Questo va bene ma ancora piů "corretto" č:
int main(void)
{
    /* ... */
}
oppure
int main(int argc,char *argv[])
{
    /* ... */
}
o equivalenti, citati dallo standard.
Naturalmente se stiamo parlando di un ambiente
freestanding allora l'entry point č dipendente dall'implementazione.
--
Giorgio Silvestri
DSP/Embedded/Real Time OS   Software Engineer

Questo va bene ma ancora piů "corretto"[...]
Da quando s'č letto lo standard del linguaggio, non ce lo togliamo piů
di dosso :-) ihih

"Andrea Laforgia" <a.laf...@andrealaforgia.it.invalid> ha scritto nel
messaggio news:gm9lf2pasoaqt8168...@4ax.com...

Vero :-)


Vero :-)
Fai bene ;-)
Aspetta che me lo rilegga io e da qui non viene fuori vivi più
nessuno! ihih :-)

che dire...
innanzitutto GRAZIE...
ho capito che il mio modo di programmare è veramente...pessimo...
ti ringrazio per il codice postato...funziona perfettamente, è molto
diverso rispetto al mio....e proprio questo è il problema...dovrei
cercare di modificare il mio in meno possibile in quanto quello è il
codice che ho scritto a mano durante un esame...
per questo cerco di essere piu preciso...mi sembra di aver capito che
l'errore sta nella funzione "cancella" che in alcuni casi non fa il suo
dovere..in pratica
cerco se un nome esiste in uno dei 2 alberi (root1e root2)
s=cerca(root1,name);
dopodichè...se non esiste...lo inserisco normalmente...
if (s==NULL)
     {
     insert_nome(&root1,p);
     insert_punt(&root2,p);
     }
altrimenti...cancello il record dai 2 alberi e la
reinserisco-aggiornandola
else
     {
     cancella(&root1,name);
     cancella(&root2,name);
     add(name,punteggio+auxp);
     }
sono quasi 2 giorni che cerco di capire dov è l errore di questa
funzione, riceve in ingresso l'user da cancellare in un albero:
int cancella(player **pr,char user[MAXSIZEN])
{
    player **q, *r;
    if(*pr!=NULL)
    	if(strcmp((*pr)->elem->nome,user)>0)
    		{printf("\nl");
    		return cancella(&(*pr)->left,user);
			}
    	else if(strcmp((*pr)->elem->nome,user)<0)
    		{printf("\nr");
    		return cancella(&(*pr)->right,user);
			}
    	else{
	    	printf("\nforse l ho trovato");
	    	auxp=(*pr)->elem->punt;
	    	if((*pr)->left==NULL){printf("\nright");
                               r=*pr;
                               *pr=(*pr)->right;
                               free(r);
                               }
         	else if((*pr)->right==NULL){printf("\nleft");
                               r=*pr;
                               *pr=(*pr)->left;
                               free(r);
                               }
         	else{
	         	printf("\nesistono entrambi i figli");
	         	for(q=&(*pr)->left;(*q)->right!=NULL;q=&(*pr)->right);
              	r=*q;
              	*q=(*q)->left;
              	r->left=(*pr)->left;
              	r->right=(*pr)->right;
              	free(*pr);
              	*pr=r;
              	}
              	return 1;
         	}
         else
         	return 0;
}
Il problema si pone perchè è necessario aggiornare un campo presente
in un albero...magari è sbagliato proprio il mio approccio...voi come
fareste???

Ho risolto...
grazie

 Le variabili globali č bene non usarle mai.
...perchč?

 ...perchč?
...eventualmente te lo spieghera' qualcun'altro piu' volenteroso di me :-)
Ciao
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

interpretazioni. Io la cambierei con un "semplice":
No, non è per niente categorica.  E' bene non usare MAI le variabili
globali, per una serie di motivi triti e ritriti.  Non scendo troppo
nei dettagli, perché di questo argomenti si è straparlato ovunque, ma
in generale si può dire che è bene dichiarare le variabili il più
possibile vicino al contesto in cui vengono utilizzate.  Il motivo è
che si evita di poter modificare variabili utilizzate da più parti (è
una spiegazione banale, ma in rete c'è molta doc a proposito).

 possibile vicino al contesto in cui vengono utilizzate.
Per prima cosa, volevo chiarire che il mio post di risposta era semi-serio.
Quindi tenevo pure a precisare, per chi non avesse capito, che si sta 
affermando (in pratica) lo stesso concetto.
La differenza e' che, dicendo:
"Le variabili globali è bene non *usarle* mai."
...la frase e' male interpretabile. Puo' venire fuori spontaneo un 
"perche'?" da qualche neofita o altro: eg. "ma la 'errno' la devo usare 
per forza... uso una libreria di funzioni dove ce ne sono e devo 
usarle... ecc.".


 eg. "ma la 'errno' la devo usare per forza...
Non a caso 'errno' non è più una semplice variabile globale, almeno non nei 
contesti in cui è possibile il multithreding.
Max

"perche'?"
Chiedersi perché non significa male interpretare, ma non comprendere
il significato.  E non capisco, ancora, che differenza ci sia tra
quello che dici tu e quello che dico io...
p.s.: l'argomento non è OT.

>> No, non č per niente categorica.  E' bene non usare MAI le variabili
un doc in rete che spiega i motivi per cui č male usare var globali?
A parte in un contesto multithreading in cui l'accesso deve essere regolato 
da meccanismi di mutua esclusione e tutti i vari problemi di concorrenza non 
capisco
che danno possano fare.. forse si perde in efficienza?
Grazie 

 un doc in rete che spiega i motivi per cui č male usare var globali?
esempio piu' scemo del mondo:
int i; //variabile globale
int main() {
  i=5;
  int j=quadrato_di_i();
}
ora... come funziona internamente quadrato_di_i()?
ad esempio guarda queste 2 implementazioni
int quadrato_di_i() {
  return i*i;
}
int quadrato_di_i() {
  i*=i;
  return i;
}
la differenza e' minima, ed in questo esempio e' ancora banale... ma che
succede se
1) il codice non l'hai scritto tu
2) il codice e' molto piu' incasinato (uso di variabili locali, globali e
parametri passati alla funzione)
3) il codice e' buggato
e poi vediamo se le variabili globali non sono il male...
-- 
Under construction

un doc in rete che spiega i motivi per cui č male usare var globali?
http://www.google.it/search?hl=it&q=%22do%20not%20use%20global%20variables%22&qt_s=Ricerca&sa=N&tab=gw
Ai motivi avevo succintamente accennato.


poi leggero' bene.. in effetti l'avevo gia' sentita questa cosa delle 
globali..
d'altronde io sto facendo un progetto abbastanza grosso per l'universita'
ed ho main.c e molti altri file sorgente con molte funzioni..
nel mio progetto ho messo una manciata di var globali, potrei farne a meno 
certo,
ma significherebbe passare quelle var attraverso molte funzioni che di 
parametri ne hanno gia' tanti e a meno che non inizio a passare strutture a 
iosa da una funzione all'altra mi conviene lasciare qualche globale per 
evitare di appesantire il codice..
č un ragionamento sbagliato?
e sopratutto, il mio prof si incazza se vede le var globali??? :) 

e sopratutto, il mio prof si incazza se vede le var globali??? :) 
Se io fossi il tuo prof, ti boccerei :-)
Fai tu :-)

 Fai tu :-)
Bastardo!! :)
Se mi boccia per due var globali su un progetto di 4000 righe lo castro 
seduta stante 

 parametri ne hanno gia' tanti
Puoi anche dividere in moduli, quindi piu' funzioni che insieme 
assolvono ad un determinato compito.
Con i dovuti criteri, un modulo puo' diventare un qualcosa di molto 
'simile' ad una classe del C++, ovviamente con tutti i limiti di un 
linguaggio non orientato agli oggetti come il C.
Un "oggetto" puo' essere 'emulato' (scusatemi termini e definizioni :)) 
con una struttura C creata dinamicamente ed alcune funzioni che lavorano 
sui dati di questa. Due di queste funzioni si occupano rispettivamente 
di costruire e distruggere l'oggetto (costruttore e distruttore).
Provo a farti un modello di esempio (nulla di originale) di un (quasi) 
oggetto implementato in C:
============= an_object.h =================
/*....... */
typedef struct tagAnObject {
         int nVar;
         char *pOther;
         /* ....... */
         /* var private (_pv_xxx: solo una convenzione mnemonica) */
         char *_pv_pVar;
         int   _pv_nVar;
         /* ....... */
} *P_ANOBJECT;
/* prototipi */
P_ANOBJECT AnObject_Create(int nValInit);
void AnObject_Destroy(P_ANOBJECT *ppInstance);
/* ...... */
============= an_object.c =================
#include "an_object.h"
#include <string.h>
#include <stdlib.h>
/* costruttore */
P_ANOBJECT AnObject_Create(int nValInit)
{       P_ANOBJECT pO;
         if(!(pO = malloc(sizeof(*pO))))
                 return NULL;
         /* inizializza struttura */
         memset(pO, 0, sizeof(*pO));
         pO->nVar = nValInit;
         /*......*/
         return pO;
}
int AnObject_DoSomeThing(P_ANOBJECT pInstance, int nParam1, char *pParam2)
{       int nRet = 0;
         if(!pInstance)
                 return 0;
         /*.. fa qualcosa .. */
         if(pInstance->nVar > 5)
                 pInstance->pOther = pParam2;
         /* ............... */
         return(nRet);
}
char *AnObject_DoOtherThing(P_ANOBJECT pInstance, char *pParam)
{       char *pRet = NULL;
         if(!pInstance)
                 return NULL;
         /*.. fa qualcos'altro .. */
         /* ...... */
         return (pRet);
}
/* si evita sempre di accedere direttamente ai dati della struttura */
int AnObject_GetAVal(P_ANOBJECT pInstance)
{       if(!pInstance)
                 return 0;
         return pInstance->nVar;
}
int AnObject_SetAVal(P_ANOBJECT pInstance, int nSetValue)
{       if(!pInstance)
                 return 0;
         return(pInstance->nVar = nSetValue);
}
/* .............. */
/* distruttore */
void AnObject_Destroy(P_ANOBJECT *ppInstance)
{       if(!ppInstance || !*ppInstance)
                 return;
         free(*ppInstance);
         ppInstance = NULL;
}
============= main.c =================
#include <stdlib.h>
#include <string.h>
#include "an_object.h"
int main(void)
{	/* vago esempio d'uso */
         P_ANOBJECT pAnObj = NULL, pAnOtherObj = NULL;
         char *pParam = NULL, *pParam1 = NULL, *pParam2 = NULL;
         int nParam = 0, nParam1 = 0;
         /* si puo' lavorare con 2 istanze dello stesso oggetto */
         pAnObj = AnObject_Create(5);
         if(!pAnObj)
                 return(-1);
         pAnOtherObj = AnObject_Create(25);
         if(!pAnOtherObj)
         {       AnObject_Destroy(&pAnObj);
                 return(-1);
	}
         AnObject_DoSomeThing(pAnObj, nParam1, pParam2 /*,...*/);
         AnObject_DoOtherThing(pAnObj, pParam /*,...*/);
         AnObject_DoSomeThing(pAnOtherObj, nParam1, pParam2 /*,...*/);
         /* ..... */
         AnObject_Destroy(&pAnOtherObj);
         AnObject_Destroy(&pAnObj);
         return(0);
}
======================
Si potrebbe fare anche qualche esempio di costruzione oggetti derivati 
da AnObject... pero' eviterei :-)
Con una buona scomposizione del problema (quindi tanta analisi - non 
solo top-down ma anche bottom-up) puoi creare moduli (anzi oggetti) che 
potrebbero anche essere riutilizzabili per altri tuoi programmi... inizi 
quindi a crearti una tua libreria che non si limita solo a contenere 
semplici funzioncine di utilita'...


 seduta stante
Ne avrebbe tutte le ragioni: o 2 o 2000, è il principio che conta...
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

o 2 o 2000, è il principio che conta...
ho contato sono 9800 e passa righe
e cmq se veramente non andassero mai e poi mai usate le globali, che 
esisterebbero a fare?
E nella glibc ci sono anche.. 

 semplici funzioncine di utilita'...
beh per ora sto in fase di debugging, avevo in mente di fare 
l'ottimizzazione del codice piu' in la, quindi se mi serve aiuto non 
scomparire :) 


Secondo me 2 variabili o 2000 non è lo stesso
per un codice di 4000 righe.
Sui vari "dogmi" della programmazione io non direi
cose del tipo:
(a) non usare mai mai mai globali (il nostro caso);
(b) non usare mai mai mai goto;
(c) non usare mai mai mai macro;
(d) non usare mai mai mai questo;
(e) non usare mai mai mai quest'altro;
(f) usare sempre sempre sempre questo;
(g) usare sempre sempre sempre quest'altro ancora;
(h) tutte le funzioni devono sempre sempre sempre
avere un solo punto di ritorno;
...
...
Tutti i consigli che normalmente vengono
dati per programmare bene sono naturalmente validi
e ampiamente condivisibili e sottolineo
validi e condivisibili.
Sopratutto perché vengono fuori da considerazioni
ed esperienza che hanno vissuto migliaia
di programmatori per anni.
Molto deriva anche da considerazioni sul debug.
In certi ambiti dove è richiesta
assoluta sicurezza del codice, i vincoli
imposti sono ancora più forti e restrittivi.
Ad esempio a volte viene richiesto
che la memoria dinamica venga tutta allocata
all'inzio del programma.
Quindi tutte le routine di creazione/distruzione di oggetti
sarebbero "illegali".
Chissà quanto codice da buttare ci sarebbe eh ? :-)
O ancora il vincolo che tutti i loop
devono avere un numero di iterazioni
minimo/massimo noto in compilazione.
Forse buttiamo via il 99% del
codice esistente :-)
Anche questi sono "dogmi"
che contribuiscono alla facilità del
debug e alla comprensione/sicurezza
di quello che si scrive.
Un codice con queste proprietà
ha una maggiore facilità di essere
controllato da sofisticati tools.
Nei contesti in cui è in gioco
la vita di molte persone sono davvero convinto
che bisogna fare così.
Sono ambiti di controllo di processo
dove bisogna dare alcuni comandi nei tempi
richiesti o succede un disastro.
Ovviamente qui NESSUNA precauzione è troppa.
Tornando a noi, intendo dire che è
importante anche l'ambito di programmazione.
Il buon programmatore dovrebbe
avere in mente tutto questo per non usare certi stili.
Ripeto NON consideriamo ambiti troppo
particolari come quelli visti
poco fà.
Altrimenti tutto (o quasi)
il codice postato sarebbe da rivedere.
In conclusione
I buoni/ottimi consigli sono ben accetti, ma
esagerare con il dogmatismo non mi sembra
il massimo.
Viene persa, secondo me, una parte
della ricchezza e peculiarità del
linguaggio stesso.
Vorrei anche fare una considerazione
sull'efficienza di uno stile
invece di un altro in un contesto
particolare.
Dove una globale (o anche static al file) è
particolarmente benefica.
Supponiamo di avere il seguente interrupt
handler, ma potrebbe essere più portabilmente
una signal.
Infatti la parola chiave "interrupt"
non è standard ma si trova spesso a livello
di programmazione a basso livello sui
processori.
/*
 * caso 1: uso globali (o meglio variabile con file-scope)
 *
 * possiamo anche supporre l'accesso alle variabili
 * indivisibile (atomico)
 *
 */
static volatile unsigned int cnt_int_handler;
interrupt void int_handler(void)
{
 *ADDRESS_REGISTER = VALUE_REGISTER;
 ++cnt_int_handler;
}
/*
 * caso 2: non uso globali
 */
interrupt void int_handler(void)
{
 *ADDRESS_REGISTER = VALUE_REGISTER;
 /* cos'altro ? */
 conta_interrupt();
}
Il problema è di contare semplicemente il numero di volte
che si verifica un certo interrupt (che richiede però di
essere eseguito molto rapidamente).
Se provo a chiamare una qualsiasi funzione
dentro la int_handler il compilatore è
COSTRETTO, proprio per la caratteristica degli interrupt
che avvengono in modo asincrono, a salvare tutti i registri
non sapendo cosa viene modificato da conta_interrupt().
In questo caso, abbastanza comune in sistemi embedded,
il codice assembler della prima versione è
clamorosamente migliore della seconda.
A maggior ragione se siamo in presenza di una macchina
con molti registri. Certi DSP ne hanno parecchi.
Anche se conta_interrupt è vuota, la prima versione viene
eseguita MOLTO più velocemente della seconda.
Vorrei precisare che questo accade perchè siamo
in presenza di un interrupt handler e non
di una normale funzione.
In questo secondo caso infatti la compilazione
è diversa.
Questo è un esempio banale in cui credo
una semplice variabile globale, o static al file, possa non dare
molto fastidio, anzi.


esisterebbero a fare?
Anche gli idioti esistono, ma si potrebbe benissimo farne a meno.

il massimo.
Nessuno esagera.
Giorgio, per cortesia, imposta il tuo newsreader perché tagli le righe
ad una colonna abbastanza in là da consentire di leggere i tuoi
messaggi agevolmente ;-)

 Anche gli idioti esistono, ma si potrebbe benissimo farne a meno.
Questa mattina ti sei guardato allo specchio?
Ciao
Giovanni
PS:  inventa qualcosa di nuovo.  "Taci idiota" e` oramai vecchio e 
stantio ;-)
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   Registered Linux user #337974  < 
http://giovanni.homelinux.net/
 >

 programmazione.  Tu quanto codice hai scritto in tutta la tua vita ?
Che è, una gara a chi ce l'ha piu' lungo?
Evita commenti saccenti e presuntuosi, non puoi sapere se sono da bocciatura 
o meno e basarti solo sul fatto che abbia usato var. globali e' stupido e 
superficiale
E non c'entra niente l'esperienza in programmazione ma il buonsenso
..anche perchè non ho mai sentito i miei prof dire "se usate le globali vi 
boccio" quindi..
...e me stai pure a porta' sfiga, tiè tiè :p 

 Nessuno esagera.
Tu esageri :)
cmq il codice sono circa 9000 righe, direi proprio che mi posso tenere le 
mie globali, sento di meritarmelo insomma 

Taci cretino.


 Evita commenti saccenti e presuntuosi[...]
I commenti saccenti e presuntuosi sono quelli di chi ha poca esperienza di
programmazione, conosce poco il linguaggio, le tecniche e lo stile
corretto e nel contempo pretende di saperne piů degli altri.  Indi, il
saccente e presuntuoso sei tu, non io.


 saccente e presuntuoso sei tu, non io.
ok, sei riuscito a darmi del presuntuoso e inesperto, giudizi senza
nessuna base, ma stavo gia notando che tu non ti fai problemi a sputare
sentenze
Ti aspetto al varco ;)

 
Che fantasia ;-)
Ciao
Giovanni


 Ti aspetto al varco ;)
Hai voglia ad aspetta'.


 mie globali, sento di meritarmelo insomma
Bravo, continua così e farai parte di quel mare di incapaci sfornati
dall'università ;-)


 
Cosi` sarai in buona compagnia ;-)


 Cosi` sarai in buona compagnia ;-)
Zitto, scemo.


 base c'è eccome.
chiedere il motivo della tua sentenza
"Le variabili globali è bene non usarle mai"
secondo te ti da il diritto di pompare merda e darmi dell' incompetente?
Sei squallido.
Spero di incontrare tanti tipi come te quando lavorero', cosi' da potermeli 
lavorare io
per bene :)
Senza rancore :)