Newsgroup: it.comp.lang.c++
Titolo: Come si accede ai valori delle stringhe?

Sto imparando il C++, so programmare in Fortran ed in Basic....
Non ho capito una cosa del C++.....se scrivo
int a=1,b=1;
if (a == b) {cout << "a uguale a b";}
mi sembra sia corretto. Diversamente non posso scrivere
char[8] stringa;
stringa="aaa";
if (stringa=="aaa") {cout << " stringa=aaa ";}
ma devo fare
if (strcmp(stringa,"aaa")==0) {cout << " stringa=aaa ";}
Perche' esiste questa differenza ? Ho capito bene o sto sbagliando 
qualcosa?
e poi.....
Come si fa a puntare al valore di una variabile e non al suo indirizzo ?
Grazie e scusate le domande da newbie...
Maurizio

 Come si fa a puntare al valore di una variabile e non al suo indirizzo ?
La domanda non e` molto chiara.  Un puntatore, che immagino
sia quello che intendi usando il verbo "puntare", e` appunto una
astrazione del concetto di "indirizzo"; non e` che "punti ad un
indirizzo", ma _contiene_ (in forma, sia pure, 'astratta') proprio
un indirizzo.
"Puntare ad un indirizzo" immagino significherebbe "puntare ad
un puntatore" (cioe`, due livelli di indirettezza)?
Se ho capito bene il problema cui vuoi riferirti...:
Puoi normalmente ottenere una _copia_ del valore attuale di
una variabile (non per tutti i tipi; dipende da chi scrive la
implementazione del tipo, se voglia permettere la copia)
con un costrutto come:
    Tipo xxx;
    // ... varia roba
    Tipo* p = new Tipo(xxx);
Ora p punta ad una copia del valore che in quel momento
aveva xxx, quindi nessun problema se xxx viene poi
ulteriormente modificato (in realta` i problemi possono
esserci, per strutture complicate, fra "shallow" e "deep"
copy, ma di questo parleremo un'altra volta... comunque
dipende tutto da come e` implementato "Tipo").
Se scrivi cosi` hai pero` poi la responsabilita` di liberare
esplicitamente la copia quando non ti serve piu`,
scrivendo
    delete p;
a qualche punto.  Spesso puoi risparmiarti questo usando,
#include <memory>
using std::auto_ptr;
e sostituendo il "Tipo* p" con:
    auto_ptr<Tipo> p = new Tipo(xxx);
Se usi questo "puntatore automatico", la cancellazione
della copia che hai fatto con la new sara` pure automatizzata 
(avvenendo nel _distruttore_ di p).
Alex


Il C++, non supporta direttamente un tipo di variabile stringa, come del
resto avrai capito. Infatti per dichiarare una stringa scrivi:
char *Stringa;
Questo significa che per il compilatore, quella che tu chiami stringa, non è
altro che un'array di char, in cui l'elemento finale deve avere valore ASCII
0.
Dunque essendo una stringa una matrice (array), non puoi eseguire il
confronto diretto, ma deve usare, o devi sviluppare, una funzione che sia
adatta allo scopo.
Per accedere agli elementi della stringa è sufficiente deferenziare la
variabile, o meglio ancora considerarla come un'array. Ad esempio se tu
volessi conoscere l'elemento 5 di una stringa di 10 (ad esempio la stringa
"0123456789") elementi dovresti scrivere una cosa del genere:
Ch = Str[4];
Come avrai notato ho scritto 4 e non 5 perché gli array in C++ (come in C)
partono da 0.
Tuttavia se vuoi semplificare tutto utilizza la classe CString presente
nelle MFC di Microsoft Visual Studio.
Dichiarando una stringa CString protrai eseguire il confronto tra stringhe
come se si trattasse di un altro tipo di dati, e potrai eseguire tutta
un'altra serie di funzioni.
Quindi il tuo programma diverrebbe:
#include <afxwin.h>
CString A,B;
A = "aaaa";
B = "bbbb";
if (A == B)
{    cout << "Uguale"; }
else
{    cout << "Diverso"; }
ICE MAN

Salve! Uso il C++ da pochi mesi e mi sono concentrato + che altro sulla
struttura del linguaggio stesso. Adesso mi ritrovo a voler realizzare
codici un po' + complicati e ho cominciato a sentire il bisogno di saperne
di piu' sulle librerie. Ad esempio in quale libreria posso trovare
controlli sul testo tipo le istruzioni BASIC Locate, right$, mid$ o
clrscr? Dove posso trovare documentazione su librerie, sopratutto grafiche
(vorrei solo disegnare il grafico di una funzione... perche' devo imparare
ad usare le OpenGL?) e sopratutto esiste qualcosa di cartaceo? A leggere
sul monitor o a stamparmi 20Mb (o +) mi viene uggia... Grazie di tutto e a
buon rendere

Grazie e scusate le domande da newbie...
Puntare al valore di una variabile?E' una cosa senza senso.Un
puntatore può puntare ad una locazione di memoria(nel senso che
contiene l'indirizzo di una certa locazione di memoria),non ad un
valore.
Il Ghenio

Come spiega Alex Martelli in un altro messaggio di questo thread, il C++
supporta eccome un tipo stringa, ovvero std::string.
Ciao,
Nicola

 qualcosa?
No, hai capito bene. La differenza è che int è un solo elemento mentre
char[8] sono otto elementi e quindi mi sembra accettabile che
l'operatore == si comporti in modo diverso. Precisando, nel secondo caso
l'operatore continua a funzionare egregiamente ma confronta non tutti
gli otto elementi contemporaneamente ma l'indirizzo di inizio dei due
membri di sinistra e di destra, valori nei quali decadono i nomi degli
array ed anche gli string literal. Quindi
se a e b sono due int:
a == b confronta il valore di a con il valore di b;
se a e b sono array:
a == b confronta l'indirizzo di inizio di a con quello di b e il
risultato è senz'altro falso se i due array sono diversi anche se
contengono gli stessi valori.
EMG

 (avvenendo nel _distruttore_ di p).
Compilando il seguente esempio
#include <iostream>
#include <memory>
using namespace std;
class A
{
    public:
        A() { cout << "Ctor" << endl; }
        ~A() { cout << "Dtor" << endl; }
};
int main()
{
    auto_ptr < A > a = new A;
}
con il DJGPP ottengo il seguente messaggio di errore:
prova.cc: In function `int main()':
prova.cc:18: conversion from `A *' to non-scalar type `auto_ptr<A>'
requested
E' un bug del DJGPP o sbaglio qualcosa io?
EMG

 ad usare le OpenGL?) e sopratutto esiste qualcosa di cartaceo? A leggere
Me lo domando anche io: perchč devi usare le OpenGL per visualizzare
grafici?
Mi pare di capire che usi Windows, e lě non mancano di certo le primitive
grafiche (API di WIN32) per la grafica.
--
Alessandro Monti

 E' un bug del DJGPP o sbaglio qualcosa io?
Sbagli qualcosa tu.  Un auto_ptr, a norma di standard, NON PUO' essere
inizializzato con un assignment; devi usare il ctor, con:
auto_ptr<A> a( new A );
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it

 auto_ptr<A> a( new A );
Scusa se faccio un followup a me stesso, ma mi accorgo di non essere
stato chiaro.  La differenza e' che a(new A) usa una conversione
implicita, mentre a=new A e' una conversione esplicita; il costruttore
degli auto_ptr deve infatti essere definito in <memory> come:
namespace std {
  template<typename T> class auto_ptr {
    public:
      ...
      explicit auto_ptr( T * ptr = 0 ) throw();
      ^^^^^^^^


 implicita, mentre a=new A e' una conversione esplicita; il costruttore
Oops, sorry -- avevo appunto cercato di chiarire questo punto in
replica al tuo post precedente (e` un mio errore che sta alla
radice di questo... EMG stava solo provando la forma che avevo
suggerito io).
Secondo me` e` il contrario, cioe`:
    tipodix x(qualcosa);
e` una conversione esplicita da qualcosa a tipo, mentre
    tipodix x = qualcosa;
e` una richiesta di conversione implicita, e quindi fallira`
se l'overload applicabile del costruttore tipodix::tipodix e`
stato dichiarato explicit.
Comunque, al di la` del problema terminologico, hai certamente
ragione sia sulla forma che si deve usare, sia sulla vera ragione
per usarla.  Si puo` scrivere anche, mi pare:
    auto_ptr<A> a = auto_ptr<A>(new A);
ma non mi sembra che sia preferibile (non sono neppure
sicuro al 100% che si possa, visto che fra le sue anomalie
il copy ctor di auto_ptr ha quella di volere un parametro
per reference non-const... ma _credo_ che 20.4.5.3 e
la classe auto_ptr_ref esistano specificamente allo scopo
di permettere questo specifico idioma).
Alex

 ad usare le OpenGL?) e sopratutto esiste qualcosa di cartaceo? A leggere
Anche queste dipendono totalmente dalla piattaforma che vuoi
usare, e vi sono vari ottimi framework, anche multi-piattaforma.
Sul problema specifico del grafico di una funzione (senza OpenGl:-)
su Win32 (NT o 95, in modo nativo, cioe` con le API) vedi ad esempio
il mio tutorial in italiano a 
http://aleax.supereva.it/
; esso usa il C
(con due cose tipiche invece del C++, i commenti con "//" e la
possibilita` di dichiarare le cose solo quando devi proprio usarle),
ma e` sostanzialmente lo stesso insieme di cose che dovresti fare
sulla stessa piattaforma in C++ se non usassi qualche framework
per rivestire le API stesse.
Spiacente, ma non ce n'e` una versione cartacea -- e` un "lavoro
in corso" (la parte sul grafico di funzione e` completa, e se
QUALCUNO delle migliaia di persone che stanno apparentemente
scaricando il tutorial si degnasse di darmi un poco di feedback
preciso, potrei rimediare a suoi eventuali difetti!-) e non andra`
di sicuro su carta _almeno_ sinche` non considero finita questa
versione (forse neanche dopo, dipende dall'interesse in merito
degli eventuali editori:-).
Alex

 E' un bug del DJGPP o sbaglio qualcosa io?
Me lo chiedo anch'io... il costruttore di auto_ptr<T> da T* e`
dichiarato explicit, ma questo mi sembrava appunto un uso
esplicito del costruttore stesso.  E invece lo standard C++,
a 12.3.1 sub 2, da` un esempio (gli esempi non sono
normativi, ma...) che pare contraddire il mio "sembra".
E il VC++6 si comporta esattamente come il tuo DJGPP.
Quindi, penso che la mia riga sopra citata sia errata, e
vada, a scelta, sostituita con:
    auto_ptr<Tipo> p(new Tipo(xxx));    // ctor MOLTO esplicito
o
    auto_ptr<Tipo> p = auto_ptr<Tipo>(new Tipo(xxx));
La seconda forma, oltre ad essere goffa, tecnicamente
implica l'uso di un copy ctor, che non si puo` essere
certi che il compilatore sappia/possa ottimizzare; quindi,
suggerirei la prima, anche se in generale preferirei
evitarla (la trovo un po' meno leggibile, e a volte ci
si confonde fra l'esplicita costruzione e la dichiarazione
di una _funzione_...!!!-).
Scusate dell'indicazione (probabilmente) errata!
Alex

 auto_ptr<A> a( new A );
Verissimo che un auto_ptr non puo` essere inizializzato con
un assignment (eccetto che da un altro auto_ptr), ma questo,
qui, non c'entra, in quanto questo non e` un assignment
bensi` un ctor.
Il problema e` che quello che io avevo suggerito, e EMG
stava provando, e` considerato un ctor _non esplicito_,
a norma di standard (pare!), in quanto:
    -- a viene inizializzato col suo copy ctor, ma esso
        accetta solo un auto_ptr, quindi,
    -- a destra del segno di "=" di questo copy ctor
        occorre un auto_ptr (anonimo) che potrebbe
        essere costruito solo esplicitamente, non in
        modo implicito come qui occorrerebbe.
Il tutto dipende dalla presenza della keyword "explicit"
nella dichiarazione standard del costruttore di auto_ptr<A>
a partire da A*, e non dalla definizione dell'operator= di
auto_ptr<>, che in questa linea non entra in gioco in
alcun modo.
Ripeto le mie scuse al gruppo per aver dapprima creduto
che la forma da me suggerita fosse un ctor sufficientemente
esplicito per la bisogna -- apparentemente, non lo e`, lo
standard fa` anche un esempietto relativo a questo, che,
benche` non-normativo, e` sicuramente legato all'intenzione
degli estensori dello standard stesso -- ma e` importante
anche tenere presente la distinzione fra due diversi usi
dello stesso glifo "="...:
    tipo nomevar = qualcosa;    // e` un copy ctor
    nomevar = qualcosaltro;     // e` un assignment
Solo il secondo e` un assignment (controllato dunque
dalla dichiarazione di un qualche opportuno overload
di tipo::operator=), il primo e` invece un copy ctor 
(controllato dunque dalla dichiarazione di un qualche
opportuno overload di tipo::tipo).
Alex

 di permettere questo specifico idioma).
Puoi farlo, ma non ha molto senso ne' molta efficienza.  Il RHS
costruisce un auto_ptr<A> temporaneo; l'assignment tra due auto_ptr<A>
trasferisce sia il pointer che l'ownership dell'oggetto puntato dal
RHS al LHS; per cui, quando il temporaneo viene distrutto, non succede
nulla.
Il comportamento degli auto_ptr e' in un certo senso inusuale, perche'
assegnando un oggetto, ad es. con lo statement "a=b;", e' sottinteso
che "b" non venga modificato da "operator ="; per gli auto_ptr no,
anche il RHS cambia (perde l'ownership).
A meno che non sia un CONST auto_ptr ad essere assegnato...  in quel
caso l'ownership non viene trasferita.
Per questo motivo, data members di classi che siano auto_ptr vanno
sempre dichiarati const, altrimenti copy constructor ed assignment
operator farebbero quello che non devono fare: trasferire l'ownership
dall'oggetto primario al loro target.
Grazie delle precisazioni!  (Ma non siamo andato un po' OT rispetto al
soggetto del thread? :-)


 
Anch'io preferisco, e di molto la seconda notazione, al punto che tendo
ad usare la prima solo nelle liste di inizializzazione. Mi sembrava di
aver letto tempo addietro, forse su una qualche edizione di "The C++
Programming Language" di B.S., che le due notazioni sono equivalenti. E'
cambiato qualcosa con l'introduzione dello standard o sono io che mi
sono sognato tutto?
Ciao,
Nicola

 auto_ptr<A> a( new A );
Ecco! Grazie.
EMG

 implicita, mentre a=new A e' una conversione esplicita;
Grazie della precisazione. Infatti
auto_ptr < A > a = static_cast < auto_ptr < A > >( new A() );
funziona perfettamente. Chiaramente la versione ctor è molto più
leggibile.
EMG

 Scusate dell'indicazione (probabilmente) errata!
Beh, beccare un errore (anche se solo probabile) dell'Alex Martelli non
è cosa di tutti i giorni. :-)))
EMG

 sono sognato tutto?
Non sono equivalenti, la seconda deve fallire se il tipo non
ha un copy ctor accessibile.  Questa e' l'unica differenza
(qualunque compilatore e` ovviamente in grado di ottimizzare
via il copy ctor in questo caso, per cui l'efficienza dovrebbe
essere identica).
Alex

 wrote in message news:3857AAB2...@flashnet.it...

auto_ptr < A > a = auto_ptr < A > ( new A() );
funziona altrettanto bene, e con leggibilita` intermedia:-).
Alex

inglese; non conosco buoni testi, attuali, in italiano).
Conosci qualche sito internet nel quale se ne parli?Non importa se in
inglese o in italiano.
Il Ghenio

clrscr?
Per pulire lo schermo trovi l'istruzione clrscr(), sempre nei
compilatori Borland ovviamente,e sempre nella libreria conio.h. Il
problema é che si tratta di istruzioni non standard, che quindi se
cambi compilatore non funzionano.Bye!
Il Ghenio

 funziona altrettanto bene, e con leggibilita` intermedia:-).
La leggibilita' e' negli occhi e nella mente di chi legge; costrutti
criptici per il principiante sono immediatamente leggibili da un
esperto, come while (*p1++ = *p2++); per copiare una c-string.
Perche' eseguire due costruttori ed un distruttore di auto_ptr?
Dapprime si costruisce un temporaneo che contiene un indirizzo e
detiene la proprieta' dell'oggetto puntato; l'indirizzo viene
immediatamente copiato nel secondo oggetto, e la proprieta' anch'essa
immediatamente trasferita a questo secondo oggetto; ed infine il primo
oggetto viene distrutto.
Per me e' semplicemente cattivo stile.
Scriveresti mai "int a = int(42);" ?


 Scriveresti mai "int a = int(42);" ?
No, ma sono convinto che la stragrande maggioranza di chi programma in
C++, soprattutto se arriva dal C non scrive nemmeno
int(42);
Che in C++ sarebbe la sintassi preferibile. Essendo quindi abituati ad
una sintassi di inizializzazione della forma
<tipo> <variabile> = <valore_iniziale>;
L'espressione proposta da Alex puo' risultare piu' vicina alle proprie
abitudini di quella teoricamente ottimale.
Ciao,
Nicola

 abitudini di quella teoricamente ottimale.
Ma se ci pensi bene, Alex ha scritto l'equivalente di int a = int(42); ...
Perche' ti va bene quando lo scrive Alex e ti va male quando lo scrivo io
8^) ?


 8^) ?
Perche' e' piu' simpatico? :-)
No, seriamente, perche' con i tipi nativi ed i costruttori impliciti
posso
effettivamente scrivere
int a = 42;
mentre non posso scrivere
auto_ptr<int *> a = new int;
La sintassi di Alex non e' tanto la migliore quanto quella che piu' si
avvicina a quella cui sono abituato.
Ciao,
Nicola
P.S. Se non ti scoccia una nota personale, con chi lavori al CERN? Ho
li' un paio di amici...

 Scriveresti mai "int a = int(42);" ?
No, perche` 42 e` gia` un int, quindi "int(42)" e` una
forma curiosa, ridondante, e sospetta.
Il problema non e` questo (non vi e` nessun simile
"cast no-operation" in nessuna delle due forme che
stiamo discutendo) bensi` se sia preferibile:
    int a(42);      // il ctor con parentesi che tu preferisci
oppure
    int a = 42;    // il ctor con '=' che preferisco io
Per i tipi built-in, la forma con '=' e` cosi` tradizionale
e abituale che penso che a pochi verrebbe in mente di
usare la forma con '()' al suo posto (eccetto, come
qualcuno ha gia` fatto notare su questo thread, in un
ctor-initializer-list, dove '()' e` obbligata).
Per i tipi definiti dall'utente, prima dell'invenzione di
"explicit", non vi era egualmente nessuna differenza
[salvo copy ctor non accessibile] fra le forme
    Tipo z = argomentoqualsiasi;
e
    Tipo z(argomentoqualsiasi);
e quindi ovviamente la prima predominava, se non
altro per analogia con l'uso per i tipi built-in.
Con 'explicit' (ottima idea, d'altra parte) si ha l'effetto
imprevisto (almeno da me:-) che la prima forma,
quella abituale, e` considerata "non esplicita" (?-) a
sufficienza per soddisfare 'explicit', e da questo sorge
la necessita` di esprimere explicit-amente (la x e`
qui deliberata:-) "Tipo(...)" a destra dell'"=".  I
trade-off fra questa scocciatura, e quella (secondo
me peggiore) dei problemi con la forma "()" (le
varie ambiguita` suddette) non mi sembrano cosi`
ovvi come tu invece pari considerarli.
A favore della tua tesi, per amor di verita`, va
portato l'_erroraccio_ diffusissimo di considerare
    Tipo x = whatever;
una *ASSEGNAZIONE* ad x mentre e` invece una
*COSTRUZIONE* di x (con copy ctor); se si
evita questa forma, si risparmia il tempo di spiegare
ai lettori impreparati, durante le code-inspection,
perche` e percome assegnazione e copy-ctor sono
cose cosi` drasticamente diverse, eccetera.
D'altra parte, se non glie lo si spiega, non lo
impareranno mai...:-)
Alex

 wrote in message news:XVRZON+OEzCZEL...@4ax.com...

Datata, ma non male:
http://www.cs.rpi.edu/~musser/stl.html
Un reference aggiornato:
http://www.dinkumware.com/htm_cpl/
Un buon articolo:
http://web.ftech.net/~honeyg/articles/eff_stl.htm
Specificamente sugli iteratori:
http://www.camelot.de/~langer/Articles/IteratorsInStdlib/cppr9612_kreft.html
Riassunto generale di cose importanti del C++ standard:
http://www.freshsources.com/newcpp.html
Alex

 Ma se ci pensi bene, Alex ha scritto l'equivalente di int a = int(42); ...
Quando mai?!  Non ho mai scritto un costruttore vacuo, in quanto
applicato ad un valore che e` GIA` del tipo che si asserisce di stare
costruendo.
Se mai, la forma che ho usato puo` essere considerata simile a:
    long l = long(12);
con due cruciali differenze:
-- in questo caso, la sintassi "12L" coprirebbe perfettamente
    le nostre esigenze, mentre nel caso di auto_ptr non esiste
    alcun equivalente;
-- la conversione int->long non richiede "esplicitezza" e quindi
    l'uso di forme del genere e` non richiesto, e quindi non
    idiomatico; invece, la conversione puntatore->auto_ptr,
    essendo il ctor dichiarato explicit, lo richiede eccome.
Alex

 abitudini di quella teoricamente ottimale.
Quel che non capisco e` la teoria sulla "ottimalita`" della forma
con parentesi; visto che lo standard ha fatto tanta fatica per
garantire l'equipollenza delle due forme, sembra scortese non
trarre poi beneficio da tutto il relativo lavoro del comitato:-).
Alex

 }
Ciao,
Nicola

 trarre poi beneficio da tutto il relativo lavoro del comitato:-).
Beh, ma l'han fatto solo perche Bjarne da qualche parte aveva scritto
che e' la stessa cosa :-) Comunque io mi guardo bene dallo scrivere
orrori come
int a(8);
Ciao,
Nicola

 differenza (in questo caso, c'e`, e vi invito a trovarla:-).
beh il tuo esempio non copia il '\0' terminale, mentre la versione compatta
lo fa.
O c'era qualcos'altro più sottile?
Ciao
-----
Giovanni Bajo
Lead Programmer
Prograph Research S.r.l.
http://www.prograph.it

 Nicola

 posteri non si sono precipitati a fare come lui...
Senza dubbio perche` storicamente al C++ si arrivava dal C,
quindi l'idioma "int a=32;" era gia` ben radicato.
D'altra parte, l'esistenza di un idioma "int a(32);" e` piuttosto
recente nella storia del C++, mi pare.
Se ti interessano queste disquisizioni di linguistica comparata,
ti suggerisco caldamente "Gli indoeuropei e le origini
dell'Europa", di Francisco Vilar, ed. il Mulino.  Testo che
sto trovando davvero appassionante.
Alex

 differenza (in questo caso, c'e`, e vi invito a trovarla:-).
Beh, nel primo caso né l'assegnamento né l'accesso a *p1 avvengono
quando il carattere trovato è nullo mentre nel secondo caso è necessario
valutare comunque l'espressione di condizione di uscita dal while.
Ho sbagliato?
EMG

 sto trovando davvero appassionante.
Sigh, un altro libro sulla pila delle cose da leggere... Come diceva
Troisi "Loro a scrivere sono tanti, io a leggere sono da solo, non
riusciro' mai a mettermi in pari".
Ciao,
Nicola

 riusciro' mai a mettermi in pari".
Ottima citazione.
Alex

 decisero di mettere, e di usare, nel loro nuovo linguaggio.
Mettiamola in un altro modo: dovendo scrivere per se un linguaggio per
implementare sistemi operativi per le macchine dei primi '70,
allontanarsi troppo dall'assembler sarebbe stato uno svantaggio.
Conclusione: in realta' esistono a mio avviso delle vie di mezzo tra
concisione e prolissita' tra le quali gioca pesantemente il fattore
individuale, ovvero le abitudini, la formazione e perche' no, la vista
ed il senso dell'osservazione.
Ciao,
Nicola