Newsgroup: it.comp.lang.c
Titolo: Invertire una stringa

 }
Allora, per passare una stringa per parametro dovresti scrivere un
prototipo cosě:
void revert_string(char *str) {
in quanto quello che avevi scritto era un puntatore ad un array di
stringhe.
Ci sono altri 2 errori nel tuo codice:
- Non puoi creare un vettore con una dimensione specificata a run - time
(ovvero quando esegui il programma), ma la dimensione deve essere
conosciuta a compile - time (ovvero deve essere una costante o
un'espressione valutabile direttamente durante la compilazione, come 3 *
2, 5, sizeof (char) * 10 eccetera. Per fare ciň devi usare la funzione
malloc dichiarata se non sbaglio in <stdlib.h>
- Non puoi copiare una stringa con l'operatore di copia, in quanto
sarebbe come assegnare un vettore ad un altro vettore, e questo non č
permesso per nessun tipo di dato, tantomeno per i char (e quindi per le
stringhe). Per fare ciň devi usare la funzione strcpy dichiarata (se non
sbaglio) in <string.h>
Conclusioni: eccoti le correzioni da fare:
void revert_string(char* str)
{
    /* Alloco un vettore di caratteri "grande" strlen(str) */
    char* str_tmp = malloc(sizeof (char) * strlen(str));
    /* Qui devi invertire: te lo lascio fare da solo ;-) */
    /* Copio da str_tmp a str */
    strcpy(str, str_tmp);
    /* Ogni vettore allocato con malloc va *assolutamente* liberato con
free */
    free (str_tmp);
}
Anche se ti faccio notare che potresti direttamente lavorare con str.
Comunque l'algoritmo sta a te inventarlo ;-) Ciao!

Comunque l'algoritmo sta a te inventarlo ;-) Ciao!
#ifdef TEST_REVERT_STRING_
 #include <stdlib.h>
 #include <stdio.h>
#endif
#include <string.h>
void revert_string(char* input, char* output)
{
	char* tmp;
	tmp=input+strlen(input)-1; /*pointing to last char*/
	for(;tmp!=input-1;tmp--,output++)
		*output=*tmp;
	*output=0;
}
#ifdef TEST_REVERT_STRING_
void* b_malloc(size_t size)
{
	char* pret;
	pret=(char*)malloc(size);
	if(!pret)
	{
		fprintf(stderr,"Can't malloc\n");
		exit(EXIT_FAILURE);
	}
	return pret;
}
int main(int a,char**argv)
{
	char* output;
	if(a!=2)
	{
		fprintf(stderr,"usage blahblah.. \n");
		exit(EXIT_FAILURE);
	}
	output=(char*)b_malloc(strlen(argv[1])+1);
	revert_string(argv[1],output);
	printf("%s\n",output);
	free(output);
	exit(EXIT_SUCCESS);	
}
#endif

ritorni una stringa invertita piuttosto che stamparla.
IMO la stringa dovrebbe essere invertita direttamente, cioè non
invertirne una copia.
-- 
Marco Barisione (ICQ 84277092)

 /*mancava anche il controllo per verificare che malloc sia riuscita*/
oppss...  il C++ è troppo comodo... ;-) (vedi std::string e new che
lancia eccezioni se fallisce)



 motivi?
	veloctià?
	risorse?



 :) qualcuno definirebbe le eccezioni "a pain in the butt".
 scrivere codice con sicurezza forte dalle eccezioni è il lavoro di un
 paranoico frustrato :D
 altri direbbero la stessa cosa dei puntatori.
 Le operazioni sui puntatori non sollevano eccezioni e questo chiude
 il cerchio :) che però viene riaperto dagli auto_ptr..
 in sostanza... lasciamo divisi C e C++ che è meglio.. entrmbi hanno
 "comodità" e "paranoie" che vanno dosate con diligenza.
-- 
Roberto Ferranti
http://unboffable.hn.org/blind.c

	risorse?
Non so, allocare all'interno di una funzione e poi ritornare il valore
allocato non mi piace, o meglio lo uso spesso ma non in questi casi in
qui è facile dimenticari. Farlo con una variabile locale da stampare
su stdout è una cavolata. Le alternative più comode sono secondo me
avere una funzione "void inverti(const char * src, char * dest)" o
quella che ho detto io "void inverti(char* str)", onestamente non so
perché ho scelto quest'ultima, forse per abitudine (in Python il
metodo reverse delle liste non crea una nuova lista, come anche per il
C++), sicuramente non per velocità o risorse visto che mi sembra tanto
un compito scolastico o simili.




non ho allocato all'interno di una funzione se hai letto quello che ho
scritto ed anche commentato tra l'altro. cmq noterai che ci sono
funzioni ANSI che lo fanno (strdup() ) per quanto io lo trovi non un
ottimo stile.
il punto non era questo cmq.
la tua obiezione è stata sul fatto che la stringa stessa debba essere
reversata. trovo l'idea poco "sana".
non so se per deformazione ma trovo il problema assimilabile
all'idioma copy&swap del C++ che risolve molti problemi.
per quanto riguardi il tuo commento su ciò che fa il C++ su una lista
che venga reversata... beh.. sappi che l'idioma copy&swap viene usato
molto spesso all'interno della lib e non mi meraviglierei di trovarla
anche all'interno di molte implementazioni di una metodo reverse di
una stringa.
usare qualcosa come void inverti(char* str); è secondo me un pessimo
stile di programmazione. tale funzione non è affatto generica e NON fa
quello che ci si aspetterebbe. E' vero che può essere considerato solo
un compito scolastico, ma se non si insegna a fare un buon design di
quello che si scrive cosa si insegna?
Una funzione che svolge due compiti _distinti_ è frutto generalmente
di un aborto di design.
Visto che citi il C++ ti sei mai chiesto perché il metodo 
void pop_back ();
che accomuna molti container non ritorni un pointer alla oggetto
poppato e perché la funzione che ritorni l'oggetto in coda sia un
altra?
sono problemi di design. dividere le funzioni e fare in modo che
queste svolgano il loro compito in modo generico rende il tutto
riutilizzabile.
naturalmente non va considerato in questo caso il fatto che in C++ una
eventuale pop_back che ritorni l'oggetto poppato avrebbe un più grande
problema di design. una eventuale eccezione sollevata nella funzione
sarebbe impossibile da gestire in quanto non si saprebbe in quale dei
due compiti che deve svolgere abbia sollevato l'eccezione.

quello che ci si aspetterebbe.
Non riesco proprio a capire il perché.


 Non riesco proprio a capire il perché.
Sono d'accordo con sbirish.
La stringa su cui lavori non e' necessariamente scrivibile.
Immagina di avere:
    char *p = "pippo";
    func(p);
Non e' affatto detto che p sia modificabile da func().
Restituire una copia modificata dei dati originali e' sempre
la via migliore, a mio avviso, e si adatta bene alla programmazione
orientata agli oggetti, in cui potrebbero esserci metodi che
restituiscono puntatori a dati costanti.
Esempio:
#include <iostream>
void func(char *s)
{
     if (s) s[0] = '*';
}
int main()
{
    std::string s = "pippo";
    func(s.c_str()); // <<--- errore
    return 0;
}
Scrivendo, invece:
#include <iostream>
#include <cstdio>
char* func(const char *s)
{
      char *t = (char*)malloc(strlen(s)+1);
      if (t)
      {
         strcpy(t, s);
         t[0] = 'a';
      }
      return t;
}
int main()
{
    std::string s = "pippo";
    func(s.c_str());
    return 0;
}
non si hanno problemi.
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

Non sono più i tempi di una volta. Un tempo ti avrei risposto di 
invertire tutto sul posto usando un byte per storage intermedio e ti 
avrei anche chiesto che bisogno c'è di usare il C quando si può fare 
comodamentte in poche righe di ASM.? (l'unico problema è se la lunghezza 
della stringa è pari o dispari).
Oggi il mondo è più complicato. Se la stringa, più che un char*, è una 
sequenza di caratteri UTF-8 o 16 o se ci sono const e altri problemi di 
buona educazione nella dereferenziazione di pointer, meglio fare una copia.

non si hanno problemi.
Perché usare per forza malloc? C'è il rischio di dimenticarsi di
deallocare la stringa. Perché non:
char * inverti(const char src[], char dest[]){
     ... inverti ...
     return dest; /* o la funzione potrebbe benissimo non ritornare 
                  niente. */
}
?


 deallocare la stringa. Perché non:
<snip>
Si', va bene.  Teoricamente non ci dovrebbe essere la preoccupazione
di deallocare la stringa, in quanto il sistema dovrebbe deallocare in
automatico, all'uscita.  Le alternative sono utilizzare del codice
come il tuo riscriversi le proprie malloc()/free() come nell'esempio
seguente (scritto al volo):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct alloc_node_t {
               void *p;
               size_t size;
               int freed;
               struct alloc_node_t* next;
} alloc_node, *alloc_node_ptr;
static alloc_node_ptr head = 0;
void put_in_list(alloc_node_ptr* proot,
                 void *newp,
                 size_t size)
{
     if (!*proot)
     {
        *proot = malloc(sizeof **proot);
        if (*proot)
        {
           (*proot)->next = 0;
           (*proot)->p = newp;
           (*proot)->size = size;
           (*proot)->freed = 0;
        }
     }
     else
       put_in_list(&(*proot)->next, newp, size);
}
void *my_malloc(size_t size)
{
     void *newp = malloc(size);
     if (newp)
       put_in_list(&head, newp, size);
     return newp;
}
void my_free(void *p)
{
     alloc_node_ptr cursor = head;
     for (; cursor; cursor = cursor->next)
     {
         if ((cursor->p == p) &&
             (!cursor->freed))
         {
            free(cursor->p);
            cursor->freed = 1;
         }
     }
}
void write_memory_status(void)
{
     alloc_node_ptr cursor = head;
     printf("Stato allocazioni:\n");
     if (!head)
     {
        printf("Nessuna allocazione.\n");
     }
     else
     for (; cursor; cursor = cursor->next)
     {
         printf("PTR = %08x  DIM = %8lu  LIBERATO = %c\n",
                cursor->p,
                cursor->size,
                "NS"[cursor->freed]);
     }
     printf("--- --- --- \n\n");
}
char *invert_string(const char *s)
{
     int i, j, len=strlen(s);
     char *t = my_malloc(len+1);
     memset(t, 0, len+1);
     for (i=len-1, j=0; i >= 0; i--, j++)
     {
         t[j] = s[i];
     }
     return t;
}
int main()
{
    char *s, *t;
    int i, j, len;
    write_memory_status();
    s = my_malloc(100);
    write_memory_status();
    strcpy(s, "andrea");
    t = invert_string(s);
    write_memory_status();
    printf("prima = \"%s\";  dopo = \"%s\"\n",
           s, t);
    // liberiamo tutta la memoria
    my_free(s);
    write_memory_status();
    my_free(t);
    write_memory_status();
    getchar();
    return 0;


 che inverte una stringa:
Io invee ne propongo una + lunga ma non ricorsiva
void exchangech(char *stringtoc){
	int times, length, i;
	length=strlen(stringtoc);
	if(length%2)
		times=length/2;
	else
		times=((length-1)/2)+1;
 
	for(i = 0;i<times;i++){
	stringtoc[i] = stringtoc[i] ^ stringtoc[length-i-1];	
	stringtoc[length-i-1] = stringtoc[i] ^ stringtoc[length-i-1];
	stringtoc[i] = stringtoc[i] ^ stringtoc[length-i-1];
	printf("%s\n",stringtoc);
	getch();
	}
	return;
}
Probabilmente si migliora ma era giusto cosě per farvi conoscere la 
procedura di scambio senza appoggio a variabili esterne (x chi ancora 
non la conosce)
ciao

 che inverte una stringa:
io invece la propongo non ricorsiva
void exchangech(char *stringtoc){
	int times, length, i;
	length=strlen(stringtoc);
	if(length%2)
		times=length/2;
	else
		times=((length-1)/2)+1;
 
	for(i = 0;i<times;i++){
	stringtoc[i] = stringtoc[i] ^ stringtoc[length-i-1];	
	stringtoc[length-i-1] = stringtoc[i] ^ stringtoc[length-i-1];
	stringtoc[i] = stringtoc[i] ^ stringtoc[length-i-1];
	}
	return;
}
magari e' migliorabile ho usato qualche arificio perche' non avevo 
voglia di pensare ma mi premeva farvi vedere il metodo che ho usato x 
scambiare i dati che non si appoggia a nessuna variabile esterna ciao
	VisiK7

Domenico Delle Side wrote:
 > oltre ai  suggerimenti gia` dati,  ti propongo una  funzione ricorsiva
 > che inverte una stringa:
io invece la propongo non ricorsiva
void exchangech(char *stringtoc){
	int times, length, i;
	length=strlen(stringtoc);
	if(length%2)
		times=length/2;
	else
		times=((length-1)/2)+1;
 
	for(i = 0;i<times;i++){
	stringtoc[i] = stringtoc[i] ^ stringtoc[length-i-1];	
	stringtoc[length-i-1] = stringtoc[i] ^ stringtoc[length-i-1];
	stringtoc[i] = stringtoc[i] ^ stringtoc[length-i-1];
	}
	return;
}
magari e' migliorabile ho usato qualche arificio perche' non avevo
voglia di pensare ma mi premeva farvi vedere il metodo che ho usato x
scambiare i dati che non si appoggia a nessuna variabile esterna x chi 
ancora non lo conscesse.
ciao
	VisiK7