Newsgroup: it.comp.lang.c
Titolo: Re: Dubbio su liste

     list=paux;
Non ci siamo: stai aggiornando la copia del puntatore sullo stack.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* dupstr(const char *s) {
     char *r=calloc(strlen(s)+1,1);
     return (r?strcpy(r,s):0);
}
typedef struct node_tag {
        char *nome;
        char *buf;
        struct node_tag *next;
} node_t, *pnode_t;
pnode_t node_new(const char *nome, const char *buf) {
        pnode_t i=malloc(sizeof *i);
        if (i) {
           i->next=0;
           i->nome=dupstr(nome);
           i->buf=dupstr(buf);    
        }
        return i;
}
pnode_t node_delete(pnode_t self) {
        if (self) {
           if (self->nome) free(self->nome);       
           if (self->buf) free(self->buf);           
           free(self);
        }
}
void list_insert(pnode_t *phead, pnode_t node) {
     if (!*phead) 
       *phead = node;
     else
       list_insert(&(*phead)->next, node);
}
void list_delete(pnode_t head) {
     if (head) {
        list_delete(head->next);
        node_delete(head);
     }
}
void list_print(pnode_t head) {
     if (head) {
        printf("node=\"%s\" buf=\"%s\" next=%p\n", 
           head->nome,
           head->buf,
           head->next);           
        list_print(head->next);        
     }
}
int main(int argc, char *argv[])
{
    pnode_t head=0;
 
    list_insert(&head, node_new("andrea", "buf0"));
    list_insert(&head, node_new("filippo", "buf1"));
    list_insert(&head, node_new("giovanni", "buf2"));
 
    list_print(head);
 
    list_delete(head);        
    return 0;
}

 Non ci siamo: stai aggiornando la copia del puntatore sullo stack.
E allora? Non causa alcun problema.
"nuova" viene poi aggiornato nel main con il valore di ritorno della
funzione.
Comunque come dicevo nel mio precedente post le 2 istruzioni " list=paux;"
non servono a niente e possono essere tolte.
Marco

 qui invece se non lo metto mi perdo probabilmente la nuova testa della
lista...
Idem come sopra.
Prova a commentare le 2 righe e sono sicuro che tutto funziona ancora.
Marco

 E allora? Non causa alcun problema.
L'OP ha chiesto se nel suo programma ci sono errori ed io ho segnalato una
cosa che non va bene, a prescindere dal fatto che sia o meno l'errore che
vorrebbe scovare.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 ecc...
Ritorna fuori la tua drasticita'
Hai usato il condizionale ed hai fatto bene, *non si dovrebbe"
questo perchè *in certi casi* anche una strcpy è sicura.
infatti in quel codice viene passato un buffer di 12 byte che se è
null-terminato al byte 10 o 11  (dovrebbe esserlo dopo itoa() ma non
ho la manpage) non puo' causare nessunissimo problema di buffer overflow
ad esempio
char* p=strdup("esempio");
char text[12];
strcpy(text,p);	<- è sicura al pari di strncpy
anche qui, nessun rischio di buffer overflow, come ben sai.
Quindi, la strcpy non è il demonio, se usata come si deve è una funzione
come le altre

 anche qui, nessun rischio di buffer overflow, come ben sai.
C'è eccome.


 vorrebbe scovare.
Si può discutere sul fatto che non vada bene. Cosa intendi con "non va
bene"?

 bene"?
Con che pretesa si vuol scrivere codice corretto se si inserisce del
codice inutile ?  Nulla di cui discutere.


 codice inutile ?  Nulla di cui discutere.
OK, aveto capito un'altra cosa.

 post.
E difatti io vedo una tua risposta al *mio* post.


 perché è quella che serve e ti vengono fuori i demoni dal naso.
Vero, il mio non era un esempio dei piu' felici, ma nel caso di atoi
invece? Li la strcpy ci sta tutta. E ci sono moltissimi casi in cui usare
una strcpy è safe, strano che tu non te ne renda conto, uno bravo come
te, che aiuta sempre tutti.. (cit) 

 perché è quella che serve e ti vengono fuori i demoni dal naso.
Su questo sono d'accordo.
Meglio sempre scrivere del software che sia "immune" da eventuali modifiche
di questo tipo.

 puň essere che non si possa usare la versione "strncpy"
La mia regola si applica al caso generale.  Se ci sono cause di forza
maggiore, č ovvio che bisogna scendere a compromessi.  E' anche per questo
che ho scritto "dovrebbe".  Da qui, perň, a dedurre che usare strcpy() non
č poi cosě male, come ha scioccamente fatto qualcuno (non tu, ovviamente),
ce ne passa.


E ci sono moltissimi casi in cui usare una strcpy è safe,
Irrilevante.  Anche tenersi aggrappati a una jeep aiuta a non cadere e ci
sono moltissimi casi in cui si riesce a stare aggrappati, ma se devo
consigliare a qualcuno come fare un viaggio sicuro, gli consiglio una
berlina, chiusa e protetta.


 Non è neanche una novità.
Vabbè, non c'e' peggior sordo di chi non vuol sentire

 Vabbè, non c'e' peggior sordo di chi non vuol sentire
..cerca un buon otorino che possa curarti.


 ecc...
Andrea, hai ragione. Ma strncpy()/strncat() vanno utilizzate in modo 
particolare... perche' non c'e' mai la certezza che chiudano il buffer 
con uno '\0' finale.
Meglio utilizzare snprintf() che, a grande richiesta :), e' entrata 
nello standard C99. Oppure farsi delle proprie funzioni che rispettino 
strettamente la lunghezza del buffer (se dopo ho piu' tempo provo a 
postare due banali esempi).
Ciao
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

 con uno '
-- 



Non c'e` peggior maestro di chi ha letto il manuale ma non ha mai 
scritto un programma.
Ciao
Giovanni
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   Registered Linux user #337974  < 
http://giovanni.homelinux.net/
 >

 max. se il programma girasse su sistemi con 'int' a 64 bit? mi sembra 20)
Si è vero, proprio 20, anzi 21 se consideri anche il segno meno per i numeri
negativi.
E' che scrivo firmware e quindi ho sempre lavorato su architetture dove gli
int sono a 16 bit, qualche volta a 32 bit.
Quindi per me è quasi automatico quando leggo "int" pensare a 65535 (16
bit).
I 64 bit sono un qualcosa di impensabile per me... ;-)
Marco

Taci idiota.


 I 64 bit sono un qualcosa di impensabile per me... ;-)
Lo erano per molti fino a qualche tempo fa.  Personalmente, tutte le
ultime architetture su cui ho lavorato in C/C++ (e Unix) erano a 64 bit.


 
Ti manca proprio la fantasia ;-)


 Ti manca proprio la fantasia ;-)
Ti manca proprio la competenza.


 
Se tu avessi un po' di umilta', saresti (quasi) perfetto. ;-)
Ciao
Giovanni


 Se tu avessi un po' di umilta', saresti (quasi) perfetto. ;-)
Se tu fossi intelligente...


 negativi.
...macche', sono sempre 20 (signed e unsigned) :)
da -9223372036854775808 a +9223372036854775807
unsigned: 18446744073709551615
ps: comunque, non e' detto che macchine dichiarate a 64 bit abbiano 
anche gli 'int' a 64 bit.


 Se tu fossi intelligente...
Non sarebbe il caso di chiudere qui?
I vostri scambi di opinioni personali non sono di interesse per questo ng.
Potete farlo in privato.
Mi sembrate due bambini che entrambi vogliono essere l'ultimo ad aver
parlato.
Grazie per la collaborazione

 anche gli 'int' a 64 bit.
Si ovvio. E' legato anche al compilatore C che si usa.
Come esempio io ho lavorato su un microprocessore a 32 bit usando 2
compilatori C diversi. Uno aveva gli "int" a 16 bit, l'altro a 32 bit.
In questi casi per la portabilità del codice sarebbe sempre meglio definirsi
in un header file i propri tipi di dati in modo che non si hanno problemi se
cambiando il compilatore o l'architettura su cui gira il SW cambiano le
rappresentazioni dei tipi di dati.
Esempio
typedef U_INT_8    unsigned char
typedef S_INT_8     signed char
typedef U_INT_16   unsigned int
typedef S_INT_16    signed int
...
Inoltre è probabile che in un compilatore C per una macchina a 64 bit gli
"int" siano a 32 bit e i "long" a 64 bit.

 Non sarebbe il caso di chiudere qui?
No, io rispondo finquando continuo ad essere provocato da un'idiota.
Ignora il thread.


 "int" siano a 32 bit e i "long" a 64 bit.
E' comunissimo, tra le architetture a 64 bit, che sia così, infatti.


 Ignora il thread.
Se tutti facessero cosě, tutti i ng sarebbero riempiti di centinaia di
messaggi di questo tipo ogni volta che scoppia una discussione, e ce ne sono
tante...
Inoltre ti faccio presente che nel thread "Conversion from 'void*' to
pointer to non-'void' requires an explicit cast" tu scrivevi:
- Qui si parla di C.
- Ripeto: qui si parla di C.
- L'ho letto e confermo: sei OT.
Anche tu non stai parlando di C e anzi sei molto piů OT di quello a cui tu
dicevi di esserlo.
Ribadisco infine il mio concetto che si tratta di un comportamento
infantile, comunque non posso costringerti a non continuare e quindi buona
continuazione...confidando nel buon senso di Giovanni!!!!

 infantile
Grazie papà.


 Grazie papà.
Prego
Chiudo qui e non replicherò ulteriormente perchè come ho spiegato queste
discussioni non hanno nessun senso in un ng dove si deve parlare di altro.
Ciao

 Chiudo qui e non replicherò ulteriormente
Si sperava che lo facessi già.


 Si sperava che lo facessi già.
come fai a non renderti conto di essere pessimo?
Almeno non rompere il cazzo agli altri dicendogli che sono OT quando tu
per primo trascini una polemica all'infinito della serie sono un ragazzino 
infantile
e devo avere l'ultima parola.
Aspetto la tua risposta in maniera trepidante 

> con uno '
ti ha dato ragione, vuoi uno zuccherino? 

 
Forse nel prossimo standard.  Per ora i long sono 32 bit.
ISO/IEC 9899:1999 - Seconda edizione Pag. 35
5.2.4.2.1 Sizes of integer types <limits.h>


 Esiste già la limits.h, non reinventate la ruota.
Con limits.h non hai nessun modo per mantenere inalterata la
rappresentazione di un tipo al variare del compilatore. Se vuoi che una
variabile sia un intero a 16 bit (2 byte) al variare del compilatore,
comunque la dichiari usando i classici "char", "int", "long", ... non hai la
garanzia che sia sempre a 16 bit (limits.h qua non fare niente). Usando il
metodo da me descritto (che non è farina del mio sacco, "la ruota non lo
reinventata" io, vedi dopo) tutte le variabili a 16 bit (2 byte) rimangono a
16 bit (2 byte) cambiando in pochi secondi quanto definito nell'header.
Mantenere inalterata la rappresentazione dei tipi spesso è fondamentale nel
porting da un compilatore all'altro per una serie di motivi.
A seguire alcune motivazioni basate su un esempio dove lo stesso codice
sorgente deve essere compilato con 2 compilatori C diversi di cui il primo
ha "int" a 16 bit e il secondo ha invece "int" a 32 bit (e non ci sono
opzioni di compilazione per forzare "int" a essere a 16 bit). Tutte le
variabili di tipo "int" (intendendo variabili globali, variabili locali,
argomenti di funzione, valori di ritorno di funzione, ...) cambiano di
dimensione (da 2 a 4 byte).
Questo provoca:
- nel caso di passaggio da 16 bit a 32 bit, un aumento della memoria
necessaria (allocazione variabili statiche, stack più grandi, ...) (in certi
ambiti la cosa è completamente inaccettabile in quanto non si ha memoria a
sufficienza)
- nel caso di passaggio da 16 bit a 32 bit, aumento dei tempi di
elaborazione (operare su variabili a 32 bit richiede più tempo che operare
con variabili a 16 bit) (in certi ambiti la cosa è completamente
inaccettabile in quanto non si ha potenza di elaborazione a sufficienza)
- alcuni parti del codice possono comportarsi in modo errato (ad esempio se
un variabile che contiene un contatore che può superare il valore di 65535
passa da 32 bit a 16 bit) (questo è il punto forse più importante in quanto
il software può non funzionare più)
- ecc...
Analoghi discorsi si possono fare per le variabili floating point ("float",
"double").
Quindi il metodo indicato consente di mantenere la rappresentazione dei tipi
al variare del compilatore (con lo scopo di avere portabilità del codice).
Limits.h non può farci niente.
Questo metodo (il ridefinire dei propri tipi in un header) l'ho trovato nel
codice sorgente C di tutti i sistemi operativi per sistemi embedded che ho
usato per lavoro (e parlo di alcuni tra i più famosi) e nel codice sorgente
C delle funzioni di libreria di un SW per la generazione automatica di
codice C che implementa delle macchine a stati disegnate in modo visuale.
Quindi tutti i progettisti che hanno sviluppato questi sistemi hanno tutti
avuto questa idea di "reinventare la ruota" e non hanno pensato ad usare
limits.h (anche perchè non può risolvere la problematica descritta).
Qui
http://www.necel.com/nesdis/image/U18272EU1V0AN00.pdf
si può vedere un esempio a pag. 52 (è la prima cosa che ho trovato, ci
saranno molti altri esempi) (codice scritto da NEC Electronic, altro esempio
di progettisti che hanno "reinventato la ruota").
Ciao
Marco

Aspetto la tua risposta in maniera trepidante 
Fai male.  Faresti bene a stare zitto "fiocco" e impara a firmarti
nome e cognome.  Imbecille.

Forse nel prossimo standard.  Per ora i long sono 32 bit.
Ritenta.  Sarai piů fortunato.
"Their implementation-defined values shall be equal or greater in
magnitude (absolute value) to those shown, with the same sign."
Un'architettura con long a a 64 bit č assolutamente conforme, cosě
come č perfettamente conforme che esistano architetture con int e long
della stessa dimensione, cosě come č perfettamente conforme che
esistano architetture con char, short, int e long della stessa
dimensione.

limits.h (anche perchè non può risolvere la problematica descritta).
Quando parlo di "reinventare la ruota" intendo ridefinire la
dimensione dei tipi fondamentali.  Se non è quello che stai facendo,
allora non stiamo parlando della stessa cosa.
Se vuoi mantenere da una piattaforma all'altra un numero inalterato di
byte per un determinato tipo, allora fai bene a definirlo esattamente
e a portartelo dietro.
In ogni caso, la *portabilità*, proprio perché *portabilità*, impone
che non si faccia affidamento su una determinata lunghezza in bit per
un particolare tipo.  Quella che tu richiedi non è la portabilità del
codice, ma la portabilità di un tipo, è un concetto diverso di
"portabilità".

ti ha dato ragione, vuoi uno zuccherino? 
Silenzio, zanzara.

"Andrea Laforgia" <a.laf...@andrealaforgia.it.invalid> ha scritto nel 
messaggio news:a8mvi2l2ia5dqh5q3...@4ax.com...

Bene, visto che passiamo agli insulti aspetto che tu mi mandi la tua _vera_
email per poterti mandare i miei dati personali
Chissa' che cazzo ci dovrai mai fare, coglione. 

email per poterti mandare i miei dati personali
...ROTFL...

 "portabilità".
Riporto una definizione "di portabilità" che ho preso in internet:
"In informatica, la portabilità di un componente software è un adattamento o
una modifica del componente, volto a consentirne l'uso in un ambiente di
esecuzione diverso da quello originale."
Altra definizione:
"Un componente software è portabile se eseguirne il porting è semplice (e
quindi poco costoso)."
Su questo spero non avrai da obiettare.
Se ho un SW inizialmente scritto per un microprocessore 1 (si è quindi usato
il compilatore 1) e devo modificarlo per portarlo su un microprocessore 2
(si deve quindi usare il compilatore 2), questo è un esempio di "porting".
Anche su questo spero non avrai da obiettare.
Ora è fondamentale in certe applicazioni mantenere inalterata la
rappresentazione dei tipi (es. se ho usato una variabile intera da 16 bit,
ho necessità che sia ancora da 16 bit). Vedi il mio precedente post per le
motivazioni.
Quindi se scrivo un software utilizzando il metodo che ho indicato (header
file cone definizione dei tipi), per quel che riguarda questa problematica
di porting (mantenere inalterata la rappresentazione dei tipi), ho la
garanzia assoluta che posso spostare il SW da un "ambiente" ad un QUALSIASI
altro "ambiente" con un intervento di POCHI SECONDI (modifica dell'header
file dove sono definiti i tipi) rispondendo così nel modo miglior possibile
alla definzione che abbiamo visto prima ("Un componente software è portabile
se eseguirne il porting è SEMPLICE (e quindi poco costoso)").
    Pochi secondi di lavoro ---> SEMPLICE
Quindi un software scritto in quel modo, per quanto riguarda quella
problematica di porting, ha la massima portabilità possibile.
La portabilità del SW è una cosa generale che riguarda numerosi aspetti del
software (variabili, commenti, tipi, funzioni, ...e anche risorse di memoria
utilizzate, altre risorse HW utilizzate, tempi di esecuzione, ...).

esecuzione diverso da quello originale."
Non è questo che si intende per "portabilità" nel contesto specifico
di un linguaggio di programmazione.  La portabilità assoluta è quella
che non prevede modifiche o adattamenti, altrimenti TUTTO diventa
portabile, a meno di correzioni adeguate legate alla piattaforma, così
come TUTTO diventa sicuro, a meno di precauzioni adeguate.
Ricordati, in secondo luogo, che "L'ho reperito su internet" non è
necessariamente sinonimo di correttezza.

 come TUTTO diventa sicuro, a meno di precauzioni adeguate.
E quindi? un codice è portabile quando con pochi costi (o zero costi nel
caso ottimo) esso gira su differenti macchine
Ed è un software ad essere portabile, non un linguaggio.
 

 rappresentazioni dei tipi di dati.
Se serve che la dimensione del tipo sia sempre uguale è consigliabile
usare i typedef intXX_t/uintXX_t (C99) che sono presenti su tutte le
architetture "sane" ;)
Luca
-- 
Home: 
http://kronoz.cjb.net
Non capisco tutta questa eccitazione per il Multitasking: 
io sono anni che leggo in bagno.

 architetture "sane" ;)
Ho imparato una cosa nuova. C'è sempre da imparare...
Il mio studio del C risale al 1990 più o meno. Quindi la versione C99 non
l'ho mai diciamo studiata.
Non conoscevo l'esistenza di questi typedef intXX_t/uintXX_t.
Sicuramente nei primi compilatori che ho iniziato ad usare anche per
professione non c'erano.
In effetti sono andato a vedere negli header file del compilatore che sto
usando ora per l'archittettura su cui sto lavorando e in types.h ho trovato
ad esempio
    typedef unsigned short u_int16_t;
Quello che dicevo io è la stessa cosa, solo che è una definizione fatta
dall'utente (il risultato finale è ovviamente lo stesso). Alla fine per il
compilatore sono la stessa cosa, a lui non interessa chi abbia scritto
queste definizioni.
Nei codici sorgenti dei sistemi operativi e di altre librerie che sto usando
oggi invece trovo delle definizioni dedicate come quelle di cui parlavo io.
Ad esempio:
typedef char                    INT8;
typedef unsigned char           UINT8;
typedef signed short            INT16;
typedef unsigned short          UINT16;
typedef signed long             INT32;
typedef unsigned long           UINT32;
#define VS_BOOL            unsigned char
#define VS_UCHAR           unsigned char
#define VS_SCHAR           signed char
#define VS_UINT            unsigned int
#define VS_INT             signed int
#define VS_FLOAT           float
#define VS_DOUBLE          double
#define VS_VOID            void
#define VS_VOIDPTR         void*
Marco

 cui parlavo io. 
nel compilatore c/c++ microsoft esistono anche i tipi built-in:
__int8
__int16
__int32
__int64
__int128
definibili come signed o unsigned, che hanno proprio lo scopo di avere 
dei tipi interi di dimensione ben definita. pur vero che si consiglia 
sempre di scrivere codice size-independent, ma spesso non se ne puo fare 
a meno, come nel tuo lavoro :)