Newsgroup: it.comp.lang.c
Titolo: Dov'è l'errore? Aiuto!

Salve a tutti ragazzi!
vorrei sottoporvi le mie difficoltà a gestire le stringhe. in particolare
non capisco la differenza tra i due programmi, i cui output sono ben
diversi:
eccovi il primo.
#include <string.h>
#include <stdio.h>
int main(void) {
  char uno[]="uno",due[]="due";
  strcat(uno,due);
  printf("%s\n",uno);
  exit(0);
}
Il cui output è, correttamente, "unodue".
Veniamo ora al secondo:
#include <string.h>
#include <stdio.h>
int main(void) {
  char *uno,*due;
  uno="uno";
  due="due";
  strcat(uno,due);
  printf("%s\n",uno);
  exit(0);
}
Questo invece dà per tutta risposta "segmentation fault" (sto usando linux).
Perchè?
Ho problemi analoghi anche a gestire funzioni tipo la sprintf, che uso per
convertire un numero intero nella corrispondente stringa: funziona tutto con
i char[], salta sempre se usi char*.
Qual'è l'errore concettuale che evidentemente sto facendo?
Grazie mille a chiunque vorrà aiutarmi.
Ciao
TeoK


  Commetti un errore in entrambi i casi:
char uno[] ="uno"    -> stai inizializzando un array di 4 char { u,n,o,0 }.
con strcat(uno,due) aggiungi all' array uno (che ha capienza solo per 4 bytes )
l'array due,mandando in out of range l'array.
Il fatto che non ti dia errore e' perche' non hai compromesso aree di memoria
vitali come evidentemente accade nel secondo caso.
Ivan Molella

 vitali come evidentemente accade nel secondo caso.
Comunque il secondo programma va in segmentation fault *sempre*...
Quindi vuoi dire che non posso usare la strcat con le stringhe di tipo
char*, ma solo con char[X] (con X=dim della stringa), dopo accertandomi che
nell'array ci sia spazio sufficiente per la concatenazione delle stringhe.
Ho capito bene?
Ciao
TeoK

OOps, errore terribile di italiano: riscrivo...
 Comunque il secondo programma va in segmentation fault *sempre*...
 Quindi vuoi dire che non posso usare la strcat con le stringhe di tipo
 char*, ma solo con char[X] (con X=dim della stringa), accertandomi che


Il fatto è che, come ho detto nella risposta precedente, array[]="casa" e
*array="casa" non sono proprio la stessa cosa.
Puoi usare strcat con un puntatore, ma devi assicurarti che il puntatore
punti a qualcosa di preciso
Ad esempio, puoi allocare una quantità di memoria da usare come stringa, a
cui far puntare un puntatore:
char *p;
.....
p=malloc(N_CARATTERI*sizeof(char));
a questo punto puoi usare questo spazio come una qualsiasi stringa/array:
strcpy(p,"Strin1");
strcat(p, "Strin2");
printf("%d\n", strlen(p));
printf("%s\n", p);
Ciao
Marco Iannaccone

Il problema è che, nel secondo caso, con:
    char *uno,*due;
hai allocato solo lo spazio per due puntatori a char, ma non lo spazio per
la stringa, quindi non puoi poi fare:
  uno="uno";
  due="due";
inizializzando le stringhe in questo mod, invece:
char *uno="uno", *due="due";
ottieni un risultato simile a quello del primo esempio, ovvero:
riservi spazio per due stringhe ognuna di quattro caratteri( compreso il
terminatore) e, andando a concatenare la seconda stringa alla prima commetti
un errore, dato che lo spazio allocato per  la prima stringa non è
abbastanza lunga da contenerle entrambe. "Sembra" funzionare, perchè la
stringa viene concatenata dopo lo spazio allocato per la stringa uno (il
compilatore non fa controlli sui limiti degli array). Il fatto è che se in
quella zona ci fossero altre variabili, queste verrebbero modificate.
Comunque, una differenza tra quata versione e quella del primo esempio, è
che li vengono dichiarati due array veri e proprio. Qui vengono allocati gli
spazi per due stringhe di 4 elementi, e in più gli spazi per i due
puntatori.
Comunque, un assegnamento come: array[]="Parola" o *array="Parola" si può
fare solo nella dichiarazione
Per farlo all'interno del programma, usa strcpy(array,"Parola").
Ciao
Marco Iannaccone

 }
Non funziona. L'array uno ha 4 elementi ('u', 'n', 'o', '\0') e non è in
grado di ospitarne altri 4. Discorso analogo per il secondo programma.
EMG

   due="due";
in che senso "non lo posso fare"?
Cioè, qual'è la differenza tra
char *uno;
...
uno="uno";
printf("%s",uno);
(che mi sebra di poter benissimo fare: è giustamente "uno")
e invece
char *uno="uno"
printf("%s",uno)
(che dà lo stesso output)?
Grazie e ciao
TeoK

 (che dà lo stesso output)?
La seconda versione, alloca lo spazio per 4 char, li riempie con 'u', 'n',
'o', '\0', alloca lo spazio per il puntatore, e lo inizializza con
l'indirizzo di base della stringa, ed è corretta.
La prima, invece, alloca lo spazio per il puntatore, che non viene
inizializzato, e quindi può puntare un punto non precisato della memoria.
Assegnandogli poi una stringa, questa viene memorizzata dall'indirizzo a cui
punta il puntatore. Il problema è che lo spazio dove viene memorizzata la
stringa, non è stato allocato per quello scopo, potrebbe essere anche usato
da qualche altra variabile, e in tal caso, ne cambierseti il valore.
Tra l'altro, se fai:
char *p="Stringa";
...
printf("%s %p\n",p,p);
p="Casa";
printf("%s %p\n",p,p);
noterai che stampa correttamente le due stringe, ma l'indirizzo di base è
diverso...
Se invece provi a fare:
char array[]="Stringa1"; (o anche solo char array[20];)
e poi
array="Stringa2";
ti verrà segnalato l'errore di "tipi incompatibili in assegnamento", o giù
di lì...
Ciao!
Marco Iannaccone

 da qualche altra variabile, e in tal caso, ne cambierseti il valore.
Ma dove lo hai letto? :)
Non sara' forse che dato:    char *uno
Se faccio uno = "uno","uno" viene allocato dal compilatore tra i dati costanti.
Quindi assegnando ad uno la stringa "uno" non faccio altro che assegnargli un
puntatore di tipo const,(in quanto l'array "uno" nell'assegnazione decade a
puntatore a char ),e quindi lo spazio per la stringa e' allocato
automaticamente,senza compromettere nessun altro dato.
Quando hai dei dubbi dai una debbuggata ai programmi  prima di affermare con
certezza cose non vere.
Ivan Molella

  Ho capito bene?
In parte. Puoi utilizzare la strcat() anche con array di caratteri
allocati dinamicamente (char *). L'importante è che comunque ci sia
sempre spazio a sufficienza e che ogni stringa sia terminata con un
'\0'.
EMG

certezza cose non vere
Semplicemente NON avevo dubbi, mi sembrava una conclusione ovvia, date le
due stranezze di cui sopra...
Grazie per la correzione e (spero) per l'eventuale spiegazione... :)
Marco Iannaccone

 puntare ad una zona allocata come costante, o no?
Si, può puntarci ugualmente. Ma se vai a modificare una stringa costante
mi sembra che il comportamento sia indefinito (undefined behavior).
EMG

Comunque, in questo caso, la stringa viene memorizzata in un'area
completamente diversa da dove vengono invece memorizzati i vettori const,
no?
Guardando dove puntavano gli indirizzi, ho notato che, per una stringa
allocata assegnandola direttamente ad un puntatore, gli indirizzi sono molto
bassi, sia per l'inizializzazione nella dichiarazione che in quella
successiva, quindi questi due dovrebbero essere equivalenti, no?
Invece, gli array partono da indirizzi molto più alti, dello stesso ordine
di quelli delle varibili costanti e non.
Essattamente, quindi, dove vengono memorizzate la stringhe costanti allocate
assegnandole ad un puntatore? Da quanto ne so le costanti numeriche fanno
parte del programma verò e proprio, anche le prime?
Grazie!
Marco

 parte del programma verò e proprio, anche le prime?
Non saprei. Penso siano tutte cose lasciate alla discrezione del
compilatore.
EMG

 parte del programma verò e proprio, anche le prime?
Esistono diverse aree dove vengono allocati i dati in c.
Esiste un area dedicata ai dati statici(variabili globali,statiche e dati satici
come "Prova") inizializzati;
Un'area dedicata ai dati statici non inizializzati nel programma,ma
inizializzati automaticamente in fase di esecuzione del programma.
Memoria  heap,gestita dal programmatore in run-time.
E variabili automatiche allocate nello stack.
Ora quello che hai notato tu credo sia un'allocazione del tipo char *p = "Prova"
con
p = 0x00aa,in quanto "Prova" allocato nell'area dei dati statici inizializzati.
e un array del tipo array[5] dichiarato nel main o in qualche funzione con
indirizzo array = 0xfff0,che ha un indirizzo cosi' alto in quanto allocato a
partire dallo stack pointer poiche' trattasi di  variabile automatica.
Vedrai che se l'array lo dichiari globale avra' un indirizzo molto piu' basso.
Ivan Molella

Grazie!!!!!
Marco Iannaccone

da qualche altra variabile, e in tal caso, ne cambierseti il valore.
Le due espressioni sono assolutamente equivalenti.
Cio' che dici non e' vero.
La variabile puntatore __punta__ in entrambi i casi alla memoria in
cui e' presenta il literal stringa { 'u', 'n', 'o', '\0' }
Andrea Laforgia (andrea_...@XXXbigfoot.com)
------------------------------------------------
Il mio indirizzo di posta elettronica è inattivo 
per il momento.