Newsgroup: it.comp.lang.c
Titolo: Un problema di stringhe da sciogliere...

Salve
Ho da poco ripreso ad imparare i primi rudimenti del C, sono su una 
piattaforma linux (slackware 12) e uso il gcc 4.1.2 .
In un esercizio del Kernighan & Ritchie si richiede la scrittura di un 
programma con una funzione reverse che scriva al contrario una stringa 
data. Ora questo è il codice che ho prodotto:
_____________________________________________________________
#include <stdio.h>
#include <string.h>
char rev[1000];
void reverse(char s[],int i);
int main ()
{
   char  stringa[1000];
   int i,c;
   extern char rev[];
   for (i=0; i<999 && (c=getchar()) != EOF && c!= '\n'; ++i)
     stringa[i]=c;
   reverse(stringa,i);
}
void reverse(char s[],int i)
       {
       extern char rev[];
	int j;
	char c;
 
   for (j=0;i>=0;--i,++j)
   rev[j-1]= s[i];
   printf ("%s\n", rev);
       }
______________________________________________________
il programma fa esattamente quello che deve fare, ma l'impazzimento per 
arrivarci... Più che altro per elaborare questa linea:
rev[j-1]= s[i];
al posto di
rev[j]=s[i];
come avevo posto inizialmente. L'ho sostituita perchè l'output del 
programma mi anteponeva alla stringa scritta al contrario un carattere 
arbitrario (ma non casuale) che non faceva parte degli elementi del 
vettore. Perchè secondo voi? E' un fatto di bash o che altro?
grazie per l'attenzione
-- 
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 ° Toccalenuvole °
         Linux "Slackware" Registered User #341092
 
http://www.toccalenuvole.splinder.com/
   C'ero soltanto. C'ero. Intorno mi cadeva la neve.
				  (K. Issa)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Io riscriverei:
void reverse(char* pIn,char* pOut,  int i)
{
    int j;
   // i= lunghezza stringa , meno il catarrete terminatore (0)
    pOut[i]=0;    // Preimposta il terminatore stringa !!!!
#if 1
    for(j=0; j< i; j++){
            pOut[(i-(j+1))]=pIn[j];
    }
#else
// Oppure:
    j=0;
    while(i--)   // primo indice: i-1
    {
           pOut[j++]=pIn[i];
    }
#endif
//////////////////////////////////////////////////////////////////////////
    printf ("%s\n", rev);
}
 int main (void)
{
     char  stringa[1000];
     char  reverse[1000];
     int i,c;
    i=0;
    while(((c=getchar()) != EOF) && (i<99) )
    {
        if((c >= ' ') && (c < 0x7F))
        {
            stringa[i++]=c; /* Carattere printabile */
        }
    }
    stringa[i]=0;  // Terminatore, giusto in caso serva usare una strlen ;-)
    reverse(stringa, reverse, i);
   return(0); // non necessario in C99 ;-)
}
brix

		rev(&v[1]);
Una funzione ricorsiva, oltre a non rispondere propriamente
all'esercizio (si vuol insegnare a gestire l'array di caratteri), è
altamente inefficiente.

   for (i=0; i<999 && (c=getchar()) != EOF && c!= '\n'; ++i)
Usa fgets(). Ti scrivo uno spunto un po' più elaborato:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *getString(size_t sz) {
     char *result = malloc(sz+1);     
     if (result) {
        size_t len;
        fgets(result, sz+1, stdin);
        len=strlen(result);
        if (result[len-1]=='\n')
          result[len-1]='\0';
     }
     return result;
}
char *getReversedString(const char *s) {
     size_t slen = strlen(s);
     char *result = calloc(slen+1, 1);
     if (result) {
        size_t i=0;         
        for (;s[i]; i++)
          result[slen-i-1] = s[i];
     }
     return result;
}
int main()
{
    char *s, *r;
    printf("insert a string: ");
    s = getString(50); 
    r = getReversedString(s);
    printf("your string ............: \"%s\"\n", s);
    printf("your reversed string ...: \"%s\"\n", r);
    free(s);
    free(r);
    return 0;
}

 Bah, che cosa brutta e oltretutto non necessaria.
sicuramente ci sono cose non necessarie e variabili che possono 
trasferirsi in locale cambiando il codice, puntatori e quant'altro, ma 
io sono a pagina 30 del primo capitolo del mio primo libro di C e tutte 
queste cose ancora non le conosco :)
Ciò non significa che non voglia conoscerle, per carità a tempo debito 
ci arriverò e vi ringrazio per le anticipazioni di cui prendo nota, ma 
ora la mia domanda era differente...


 mia domanda era differente...
Vero ;-)
Il tuo problema sono gli indici dei vettori che usi:
void reverse(char s[],int i)
{
       extern char rev[];
       int j;
      char c;
      for (j=0; i >=0;--i,++j)
          rev[j-1]= s[i];          --> Invece di: rev[j]=s[i];
   printf ("%s\n", rev);
}
Tenendo conto che  --i e ++j sono valutati *dopo* l' esecuzione del ciclo,
per cui     rev[j-1]= s[i]  ---> rev[0-1]= s[10] (supponendo che i=10)
Qui c'e' un errore perche' (0-1) sicuramente non e' un indice di un elemento
valido del vettore: o c'e' un errore di battitura, o il primo carattere 
finisce
chissa' dove  a indirizzo di rev[(-1)].... sfortunatamente non ti viene 
rilevata
una eccezione...tra l'altro questo spiega perche' poi dopo funziona (per 
CASO!)
Oltretutto una striga in C *deve* finire con il carattere 0x00, che manca:
ti va bene perche' usando un vettore statico, questo viene azzerato all'
ingresso del programma (salvo in alcuni ambienti particolari).
Invece il for rev[j] =s[i] non funziona perche' gli indici dei vettori 
partono
da 0, per cui con i = 10, occorre indicizzare i valori da 0 a 9: ovvero
il primo carattere che inserisci in *teoria* dovrebbe essere il terminatore
della string (0), (e se lo fosse, avresti una print nulla!) ma siccome nel 
main
NON hai terminato la stringa, e il tuo vettore è allocato in modo 
automatico,
conterra' dei valori casuali.
      for (j=0; i >=0;--i,++j)
     {
//indice j:    0,  1, 2, 3, 4, 5, 6, 7, 8, 9, 10.....
//indice i:  10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
          rev[j]= s[i];
     }
L' indice i=10 non è corretto e preleva un carattere non valido!!!
Il corretto statement avrebbe dovuto essere:
     int n;  // Uso n per comodita'
      for (j=0, n=(i-1); j < i ; j++, n--)
     {
// indice j:   0, 1, 2, 3, 4, 5, 6, 7, 8, 9
//indice n:   9, 8, 7, 6, 5, 4, 3, 2, 1, 0
          rev[j]= s[n];     ---> indici di i: 9,8,7,6,5,4,3,2,1 e 0 !!!!
      }
Oppure:
      for (j=0; j < i ; j++)
     {
// indice j:   0, 1, 2, 3, 4, 5, 6, 7, 8, 9
//indice i :   9, 8, 7, 6, 5, 4, 3, 2, 1, 0
          rev[j]= s[(i-1)-j];     ---> indici di i: 9,8,7,6,5,4,3,2,1 e 0 
!!!!
      }
brix

 conterra' dei valori casuali.
aaaaaaah, ecco, ora ho capito, grazie molte!


ora la mia domanda era differente...
Peccato che hai tagliato la parte interessante del mio post.
Studia il codice degli altri e capirai dove sbagli.

 </code>
Non capisco
	putchar(s[0])  // chi è s[]?
Dopo che hai "reversificato" &v[1] dovresti shiftarne il contenuto a 
sinistra e mettere v[0] alla fine.
E.

 data. Ora questo è il codice che ho prodotto:
In questo caso è inutile utilizzare un buffer di appoggio. Ti crea 
diversi problemi:
- lo devi dichiarare statico;
- non sai quanto deve essere lungo e sei costretto a mettere un limite 
alla stringa in ingresso (come giustamente hai fatto).
Puoi risolvere il problema invertendo la stringa sul posto, come in:
void reverse(char *s) {
   int i;
   int len;
   len=strlen(s); /* ovvero:  for (len=0;s[len];len++); */
   for (i=0;i<len/2;++i) {
     char c;
     c=s[i];
     s[i]=s[len-1-i];
     s[len-1-i]=c;
   }
}


sicuramente ho molto da imparare, direi quasi tutto, per ora preferisco 
seguire l'approccio del libro che ho comprato dove tra l'altro, nella 
parte iniziale, è scritto esplicitamente che il potenziale del C,al fine 
didattico, non viene sfruttato appieno e gli esempi non sono incisivi ed 
eleganti come potrebbero. Però, aggiungo io, sono sufficienti a farmi 
imparare questi primi rudimenti. Troppa carne al fuoco mi distrarrebbe 
oltremodo :)
grazie comunque degli esempi che mi avete fornito, son tutti stampati e 
conservati per quando avrò le basi per capirli.


 beh, la ricorsione informatica Ã¨ materia di studio universitario...
Non capisco cosa c'entri. La ricorsione sarà pure materia di studio
universitario (e viene usata spesso in programmazione), ma in questo caso
costituisce un inutile, inefficiente appesantimento.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 "inefficienza" in un esercizio didattico che chiama una funzione?
Assolutamente. L'hai detto: didattico. E se si vuol rispondere seguendo la
linea degli esercizi bisogna restare didattici. La didattica impone di non
insegnare procedimenti inefficienti. Il fatto che si stia risolvendo un
esercizio autorizza ad usare soluzioni che nella pratica non si userebbero
mai? Se fosse così, l'esercizio perderebbe la sua reale utilità.
Si fanno gli esercizi per imparare cose che si useranno concretamente.
Una soluzione di quel tipo NON RISOLVE l'esercizio e illustra un modo di
procedere errato (per la serie: se io fossi un insegnante di
programmazione e un allievo mi rispondesse così a un test gli direi che è
un gran "paraculo" e lo boccerei).


per fortuna non sono tuo alunno[...]
Bla, bla, bla, bla. Non c'è peggior sordo di chi non vuol sentire.