Newsgroup: it.comp.lang.c
Titolo: domanda!!

devo scrivere una funzione che riceve come argomenti una stringa e due
interi (n e c per dargli un nome..)La funzione mi ritorna la stessa stringa
i cui caratteri sono stati fatti circolare di n posizioni a destra o
sinistra(in funzione di c se è 0 o 1).
qualcuno mi può consigliare ??
Grazie a tutti

 devo 
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 Bho!!.. forse no ho capito io..
Ahem, temo di si...
deve scrivere un funzione che data per esempo
la stringa "CAVOLO"  ritorna
per c=0
----------------
n=1 : "AVOLOC"
n=2 : "VOLOCA"
n=3 : "OLOCAV"
n=4 : "LOCAVO"
n=5 : "OCAVOL"
n=6 : "CAVOLO" etc.etc.
per c=1
---------------
n=1 : "OCAVOL"
n=2 : "LOCAVO"
n=3 : "OLOCAV"
etc.etc.
Ovviamente non e' necessario che ci sia una utilita', visto
che questo e' sicuramente un esercizio.
Siccome e' un esercizio (e la risposta richiede poche righe di codice)
mi quardo bene dallo scrivere qui il codice (sorry, bisogna che uno
usi un po' anche i suoi neuroni).
Posso solo dargli qualche suggerimento.
1) intanto se fai qualche prova con carta e penna dovresti
accorgerti che puoi ridurti a far circolare sempre
i caratteri verso destra o verso sinistra. Basta che noti
che far circolare verso destra di K caratteri una stringa lunga N
corrisponde a farla circolare di ?? caratteri verso sinistra.
2) Una volta che ti sei ridotto ad un solo caso (per esempio circolare
verso sinistra) fatti 2 piccoli esempi, uno con una parola di 7 lettere
ed uno con una parola di 5 lettere e scriviti, per vari valori di 
spostamento in quali posizioni della stringa i caratteri migrano,
in funzione della posizione di partenza, di c e di n.
3) riassumi il tutto in una espressione generale: suggerimento: come in
quasi tutte le cose che "circolano" c'e' di mezzo il modulo (% in
linguaggio C).
ciao,
g.

Giovanni Resta wrote:
grazie per la spiegazione.. adesso mi diverto a fare l'esercizio :)
humm.. ho già qualche idea.. dato che è un array di char mi posso muovere
così: array[n+1] oppure potrei utilizzare la strchr..
Sono sulla buona strada? :))
Ciao,
SoloOcchi 


 Sono sulla buona strada? :))
La strchr (che serve a localizzare un carattere dentro un array di
caratteri) sinceramente non serve a nulla in questo caso.
Le possibilita' piu' semplici sono 2
1) usare un array ausiliario nel quale generare la versione shiftata
della stringa e poi ricopiarlo nella posizione originale.
Quindi qualcosa tipo (L=strlen(array);)
for (i=0; i<L; i++) temp[i]=array[(una funzione di i, c ed n)]; etc.etc.
2) far circolare la stringa un carattere alla volta (ripetere questa 
operazione il numero di volte richiesto).
poi c'e' una possibilita' lievemente piu complicata, in una passata
sola, che consiste in una specie di swap a catena tra le posizioni
vecchie e nuove dei caratteri.
ciao,
g.

 wrote

Nota: per sinistra uso -1, per destra 1. Mi piace di piu' cosi ;-)
Ti ho scritto una versione PIGRA di tale problema.
Pigra nel senso che faccio uso quasi improprio di strcpy e strncpy, ma in
questo modo posso mostrarti come risolvere il problme in 2 righe di codice e
poi tu lo implementerai come meglio ritieni:
strcpy(new_string,str+(length-real_amount));
strncpy(new_string+real_amount,str,length-real_amount);
dove real_amount e'
real_amount=(amount%length);
if(direction==-1)real_amount=length-real_amount;
Il secondo pezzo trasforma uno spostamento a sinistra in uno a destra.
Il primo pezzo e' quindi pronto per scorrere (sempre a destra) la stringa.
Invece di scorrere scambio i due pezzi della stringa. Ad esempio:
ABCDEF se la scorro di 2 a destra:
EFABCD puo' essere vista come:
EF | ABCD in pratica la "strcpy" copia EF all'interno della nuova stringa,
mentre poi la "strncpy" copia ABCD all'interno del secondo pezzo della nuova
stringa.
E' IMPORTANTE CHE TU LEGGA LE NOTE IN FONDO!
Ecco un programma esempio ed il suo output:
<CODE>
#include<stdio.h>
#include<string.h>
#include<assert.h>
const char* RotateString(const char *str,int amount,int direction);
int main()
{
    char my_string[30]="ABCDEFGHI";
    int i;
    printf("This is the string: %s\n\n",my_string);
    // Proviamo in direzione rotate-right:
    for(i=0;i<20;++i){
        printf("right %2d -> %s\n",
            i,RotateString(my_string,i,1));
    }
    printf("\n\n");
    // Proviamo in direzione rotate-left:
    for(i=0;i<20;++i){
        printf("left %2d -> %s\n",
            i,RotateString(my_string,i,-1));
    }
    return 0;
}
const char* RotateString(const char *str,int amount,int direction)
{
    int real_amount;
    int length;
    static char new_string[30]={0};
    // Le righe seguenti evitano bad-input:
    assert(strlen(str)<29);
    assert(strlen(str)>0);
    assert((direction==-1)||(direction==1));
    assert(amount>=0);
    // calcoliamo...
    length=strlen(str);
    real_amount=(amount%length);
    if(direction==-1)real_amount=length-real_amount;
    // eseguiamo:
    strcpy(new_string,str+(length-real_amount));
    strncpy(new_string+real_amount,str,length-real_amount);
    return new_string;
}
</CODE>
<OUTPUT>
This is the string: ABCDEFGHI
right  0 -> ABCDEFGHI
right  1 -> IABCDEFGH
right  2 -> HIABCDEFG
right  3 -> GHIABCDEF
right  4 -> FGHIABCDE
right  5 -> EFGHIABCD
right  6 -> DEFGHIABC
right  7 -> CDEFGHIAB
right  8 -> BCDEFGHIA
right  9 -> ABCDEFGHI
right 10 -> IABCDEFGH
right 11 -> HIABCDEFG
right 12 -> GHIABCDEF
right 13 -> FGHIABCDE
right 14 -> EFGHIABCD
right 15 -> DEFGHIABC
right 16 -> CDEFGHIAB
right 17 -> BCDEFGHIA
right 18 -> ABCDEFGHI
right 19 -> IABCDEFGH
left  0 -> ABCDEFGHI
left  1 -> BCDEFGHIA
left  2 -> CDEFGHIAB
left  3 -> DEFGHIABC
left  4 -> EFGHIABCD
left  5 -> FGHIABCDE
left  6 -> GHIABCDEF
left  7 -> HIABCDEFG
left  8 -> IABCDEFGH
left  9 -> ABCDEFGHI
left 10 -> BCDEFGHIA
left 11 -> CDEFGHIAB
left 12 -> DEFGHIABC
left 13 -> EFGHIABCD
left 14 -> FGHIABCDE
left 15 -> GHIABCDEF
left 16 -> HIABCDEFG
left 17 -> IABCDEFGH
left 18 -> ABCDEFGHI
left 19 -> BCDEFGHIA
</OUTPUT>
*NOTE:
La funzione usa un array statico! Questo ha il vantaggio di non dover essere
deallocato da chi richiede la stringa, ma ha il grosso svantaggio di gestire
solo una stringa per volta. Una successiva chiamata alla funzione
sovrascrive la stringa precedente.
In pratica se tu hai:
char *s; e vuoi fare s=RotateString(my_string,i,1); questa cosa NON va per
nulla bene!!! La sucessiva chiamata a RotateString() cambierebbe la stringa
a cui punta s. In pratica per conservare la stringa prodotta devi copiarla
(strcpy) in una nuova stringa!
Se hai una stringa di 7 caratter il programma di consente di ruotarla di 14
elementi..... 14%7=0 e quindi corrisponde ad rotate 0, e 15 ad un rotate 1.
Non e' possibile passare stringhe vuote, direzioni diverse da -1 o 1, e
degli amount minori di 0.
Il programma abusa di strcpy e strncpy e non mi piace, ma l'ho fatto per
darti un suggerimento. Credo in questo modo ti sia piu' comprensibile quale
sia la logica.
Sempre per essere PIGRI ho usato un semplice : static char new_string[30];
fare cio' e brutto e poco flessibile. 30 rappresentea un limite e static un
limite di un altro genere. Ad esempio si potrebbe allocare la stringa con
malloc ed allocarla della dimensione richiesta.
Anche il resto non e' che sia un ottimo esempio di programmazione, ma
prendilo con le pinze e guardalo per capire la logica.
L'ho fatto in fretta per metterci poco tempo, ma ora mi accorgo che se te lo
facevo meglio risparmiavo poi tempo a scrivere documentazione ed a dirti
quanto faccia schifo ;-)
Tommy

Io questo esercizio l'ho risolto cosě (funziona, testato su Windows 2000 +
Visual C++):
---------------------------------------------------------------------
#include "stdafx.h"
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <tchar.h>
char *muovi_stringa(int n, char *stringa, int i, int v);
int _tmain(int argc, _TCHAR* argv[])
{
	char stringa[20] = "PROVIAMO";
	int i = (int)strlen("PROVIAMO")-1;
    printf("Stringa: %s\n", stringa);
	char *buffer_sinistra = muovi_stringa(3, stringa, i, 0);
	printf("Muovo la stringa di tre verso sinistra: %s\n", buffer_sinistra);
 
	char *buffer_destra = muovi_stringa(3, stringa, i, 1);
	printf("Muovo la stringa di tre verso destra: %s\n", buffer_destra);
	return 0;
}
char *muovi_stringa(int n, char *stringa, int i, int v)
{
	int conta;
	char appo_magg[256], appo_min[256];
	int jj = 0, ff = 0;
 
	if (v == 0)
	{
		for (conta = 0; conta <= i; conta++)
		{
			if (conta >= n)
			{
				appo_magg[jj++] = stringa[conta]; 
			}
			else
			{
				appo_min[ff++] = stringa[conta];
			}
		}
	}
	else
	{
		for (conta = 0; conta <= i; conta++)
		{
			if ( (i - conta) >= n )
			{
				appo_min[ff++] = stringa[conta];
			}
			else 
			{
				appo_magg[jj++] = stringa[conta];
			}
		}
	}
	appo_magg[jj] = 0;
	appo_min[ff] = 0;
	strcat(appo_magg, appo_min);
	return(appo_magg);
}
-----------------------------------------------------------------------
Che ne pensate? č una soluzione accettabile? Comunque l'ho testato e
funge!!


 
Be', giusto per divertimento (dubito possa essere usato come risposta
all'esercizio) e, Per la serie "Continuiamo cosi', facciamoci del male"
ecco il programma masoch.c
-------------
int main(int argc,char **argv)
{
  printf("%s%.*s\n",&(atoi(argv[1])?atoi(argv[2]):strlen(argv[3])-atoi(argv[2]))[argv[3]],atoi(argv[1])?atoi(argv[2]):strlen(argv[3])-atoi(argv[2]),argv[3]);
}
-------------
ovviamente non c'e' nessun controllo dell'input quindi attenzione, ma 
masoch c n "stringa" 
con c 1/0 per destra/sinistra, n numero di caratteri (minore della
lunghezza della stringa) e una stringa (gli apici necessari solo se e'
composta di piu' parole) sembra funzionare. 
Di sicuro risparmia memoria per le variabili....  :-)
Ciao,
      GianPiero

       GianPiero
ciao,
soloOcchi


 funge!!
Io non ho voluto toccare il modo in cui ritorni la stringa.... ma ricordati
che e' errato!!! Potrebbe non funzionare! (anzi dovrebbe non funzionare!)
Tommy

 scopo :))
Sei in cerca di pareri ?!?!
Tommy

 che e' errato!!! Potrebbe non funzionare! (anzi dovrebbe non funzionare!)
Anche io penso sia proprio un errore passare un puntatore ad un
array locale.
Ecco una versione alternativa che non usa un array di sostegno,
ma che e' naturalmente piu' lenta. (in pratica esegue n shift di 1
carattere). ((per semplicita' chiamo shift l'operazione che stiamo
considerando...))
void rota(char *s, int n, int c)
{
   int  L,i,j;
   char t;
   L=strlen(s);              // lunghezza stringa
   if (n<0) {c=1-c; n*=-1;}  // gestisce shift negativi
   n%=L;                     // riporta shift tra 0 e L-1
   if (n==0) return;         // non ho nulla da fare
   if (c!=0) n=L-n;          // gestisce caso c=1
   for (j=0; j<n; j++)       // effettua n shift di 1 car.
   {
     t=s[0];                 // salvo primo carattere
     for (i=0; i<L-1; i++) s[i]=s[i+1];
     s[L-1]=t;               // rimetto a posto
   }
}
poteva venire la tentazione di sostituire il ciclo
for (i=0; i<L-1; i++) s[i]=s[i+1];
con un bel strcpy(s,s+1);
putroppo strcpy non e' garantito funzionare se le
due stringhe si sovrappongono (si potrebbe usare memmove()).
Naturalmente sarebbe piu' bello spostare ogni carattere
una volta sola.
Ma non e' cosi' immediato, senza usare un buffer di sostegno.
ciao,
g.

ecco una versione che non usa vettori di sostegno e sposta ogni
carattere una sola volta.
Volutamente c'e' solo un commento in piu' dell'altra
versione ed e' (lievemente) criptica in modo che se qualcuno
la vuole usare deve almeno capire come funziona... e renderla piu'
leggibile. (Naturalmente la versione con vettore di sostegno sara' piu'
veloce, ma almeno questa si puo' usare per ruotare stringhe di lunghezza
arbitraria, senza allocazioni dinamiche).
ciao,
g.
void rota2(char *s, int n, int c)
{
   int  L,a,z,g;
   char t;
   L=strlen(s);
   if (n<0) {c=1-c; n *=-1;}
   n%=L;
   if (n==0) return;
   if (c!=0) n=L-n;
   // calcolo il MCD di L e n
   g=L; z=n;
   while (z>0)
      {a=g%z; g=z; z=a;}
   // sposto i caratteri
   while (g--)
     {
       t=s[z=g];
       do
       {
           a=z;
	  s[a]=s[z=(a+n)%L];
       }
       while (z!= g);
       s[a]=t;
     }
}

 SEGUIRE, NON SI PROGRAMMA COSI'!)
Vero che piu' vero non si puo'!
Ciao,
 GianPiero

 Tommy
Ciao,
SoloOcchi


 combinando!").
Non ho mai detto che non sia divertente... o meglio non e' quello che volevo
dire. Io volevo solo dire che nella realta' professionale non si programma
cosi'.
Tommy


Ovvio, ma mi sembrava chiaro del tono del mio messaggio che quel codice
era piu' nello spirito dell'IOCCC che in quello del programmatore
professionista. E comunque siamo qui per imparare e credo che un'analisi
dell' orrore che ho scritto faccia capire un paio di cosette su come
"ragiona" il C che altrimenti rimangono sconosciute (OK, forse e' un
bene....) oltre al fatto che scrivere qualcosa del genere NON e' la
maniera per programmare, visto che e' incomprensibile ed estremamente
fragile (basta provare un input non legale).
Ciao,
      GianPiero

 Ovvio, ma mi sembrava chiaro del tono del mio messaggio che
Questa e' una cosa che capita sempre... parlarsi e' diverso....
Con le mail ed i NG non si sente il "tono" e quindi chi legge da il tono che
vuole.
E' capitato a me e capita agli altri. Questo e' uno dei tanti motivi dei
tanti scontri sui NGs.
Il mio "tono" non era quello che hai "letto" tu e mi dispiace per qualsiasi
incomprensione.
Tommy


wrote:

// Borland C++ 5.5
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *rotstr(char *s, int n, int c)
{
     if (s) 
     {
        int i, len = strlen(s);
        char *t = malloc(len+1);
        if (t) 
        {
           if (c == 1) n = -n;
           for (i = 0; i < len; i++) 
           {
               int j = (i+n)%len;
               t[i] = s[(j<0)?(j+len):j]; 
           }
           t[len] = '\0';
           strcpy(s, t);
           free(t);
        }
     }
     return s;
}
int main()
{
    char a[] = "andrea";
 
    printf("<-- 2 = %s\n", rotstr(a, 2, 0));
    rotstr(a, 2, 1);
    printf("--> 2 = %s\n", rotstr(a, 2, 1));
    return 0;
-- 
Andrea Laforgia
www.geocities.com/andrealaforgia
"640kb of memory should be enough for anyone." -- Bill Gates.