Newsgroup: it.comp.lang.c
Titolo: Inspiegabile ciclo infinito.

Ciao a tutti.
Un semplice programma, di cui posterò il codice in coda al messaggio, 
stabilisce se una stringa è palindroma oppure no, ignorando gli spazi e 
non facendo distinzione tra lettere maiuscole e minuscole. 
Per realizzarlo ho utilizzato la funzione toupper, la quale, però, 
sembra generare un ciclo infinito. Infatti, eseguendo il programma 
un'isttuzione alla volta (tasto f7 con Borland C++ Builder), dopo la 
riga contenente la chiamata della funzione toupper, il controllo torna 
inspiegabilmente  all'inizio del programma (linea int main(void)).
Sapreste spiegarmi il perchè di un simile comportamento?
Ringraziandovi in anticipo, incollo qui il codice, facendo precedere la 
riga incriminata da tre caratteri cancelletto. 
Bizio.
***
/*Riceve in input una stringa e dice se è palindroma oppure no.
Usa i puntatori e non i vettori.*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTRING 100
int palindroma(char *s);
int main(void)
{
 char *s;
 s = malloc(MAXSTRING * sizeof(char));
 printf("Inserisci la stringa: ");
 scanf("%s", s);
 if (palindroma(s))
  printf("\n%s è palindroma.\n", s);
 else
  printf("\n%s non è palindroma.\n", s);
 return 0;
}
int palindroma(char *s)
//Verifica se la stringa s è palindroma.
//Ignora gli spazi e non distingue tra maiuscole e minuscole.
{
 int i, j;
 for (i = 0, j = strlen(s) - 1; i < j; ++i, --j) {
  while  (isspace(*(s + i)))
   ++i;
  while (isspace(*(s + j)))
   --j;
###  if (toupper(*(s + i)) != toupper(*(s + j)))
   break;
 }
 if (i >= j)
  return 1;
 else
  return 0;
}

 scanf("%s", s);
La scanf tronca il tuo input al primo spazio. Usa:
gets (s);

 gets (s);
Questo è vero, ed ho risolto il problema con un while ((c = getchar()) !
= EOF)...
Tuttavia, nonostante ora mi vengano accettate anche stringhe contenenti 
spazi, il ciclo infinito permane.
Avete suggerimenti per me?
Grazie mille.
Bizio.

 }
Io la scriverei piu' semplicemente cosi' (codice non completamente testato):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define LINEBF_SZ 1024
static int palindroma(char *s);
int main(void)
{
	char s[LINEBF_SZ];
	printf("Inserisci la stringa: ");
	fflush(stdout);
	if(fgets(s, sizeof(s), stdin))
		s[strcspn(s, "\n")] = '\0';
	else	s[0] = '\0';
	if (palindroma(s))
		printf("\n\"%s\" e' palindroma.\n", s);
	else	printf("\n\"%s\" non e' palindroma.\n", s);
	return EXIT_SUCCESS;
}
static int palindroma(char *s)
{
	int i = 0, j = strlen(s)-1;
	while(i < j)
	{	if(!isalnum(s[i]))
		{	i++;
			continue;
                 }
                 if(!isalnum(s[j]))
                 {	j--;
			continue;
                 }
		if (toupper(s[i]) != toupper(s[j]))
			break;
		i++; j--;
	}
	return (i >= j);
}
Ciao
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

 testato):
.....eccoti anche, al volo, una versione ricorsiva (e' un classico :) )
Provaci anche qui un po' di frasi palindrome:
http://it.wikipedia.org/wiki/Palindromo
che non abbiano caratteri ascii > 127 (eg. senza lettere accentate)
=========
/* codice non del tutto testato */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define LINEBF_SZ 1024
static int r_palindroma(char *s);
int main(void)
{
	char s[LINEBF_SZ];
	printf("Inserisci la stringa: ");
	fflush(stdout);
	if(fgets(s, sizeof(s), stdin))
		s[strcspn(s, "\n")] = '\0';
	else	s[0] = '\0';
	if (r_palindroma(s))
		printf("\n\"%s\" e' palindroma.\n", s);
	else	printf("\n\"%s\" non e' palindroma.\n", s);
	return EXIT_SUCCESS;
}
static int r_pal_(char *p, int i, int j)
{
	int bRet = 0;
	for(; i < j && !isalnum(p[i]); i++)
		;
	for(; i < j && !isalnum(p[j]); j--)
		;
	if(i >= j)
		bRet = 1;
	else if(toupper(p[i]) == toupper(p[j]))
		bRet = r_pal_(p, i+1, j-1);
	return bRet;
}
static int r_palindroma(char *s)
{
	return r_pal_(s, 0, strlen(s)-1);


 Io la scriverei piu' semplicemente cosi' (codice non completamente testato):
[snip]
Il tuo codice sembra funzionare perfettamente (non avevo dubbi!:-))). 
Tuttavia mi rimane il dubbio principale, che poi aveva generato questo 
thread. 
Perché, nella mia versione della funzione, dopo la chiamata a toupper, 
il flusso del controllo  ritorna all'inizio del main? 
Forse è un problema legato al mio compilatore? 
Un saluto e grazie mille!
Bizio.

 .....eccoti anche, al volo, una versione ricorsiva (e' un classico :) )
Ok, vista. 
Una domanda: perché utilizzi la funzione r_palindroma che a sua volta 
chiama r_pal? 
Non facevi prima ad inserire nell'if del main la chiamata a r_pal e far 
fare tutto a lei?
Grazie mille e un saluto.
Bizio.  

 Potresti spiegarmi meglio anche questo punto?
Mi permetto di rispondere anche se la domanda non č rivolta a me.
Ti faccio un esempio semplice.
for (i = 0; i < 10; i++)
{
    // qua dentro sarebbe bene non andare a modificare mai la variabile i,
ma eventualmente usarne solo il valore
}
i č la variabile che regola il for, se la modifichi dentro al for č facile o
comunque possibile fare errori (creare situazioni di loop infinito da cui
non si esce mai, non eseguire il ciclo il numero di volte desiderato, ...).
E' bene che le modifiche e i controlli sulla variabile i stiano tutti nella
riga iniziale del for.
Inoltre modificando il valore di i all'interno del for il codice č di piů
difficile comprensione.
Stessa cosa se c'č un while al posto del for.

Forse è un problema legato al mio compilatore? 
Correggendo la scanf, il tuo codice viene compilato dal mio VC6 e
gira senza problemi.

 Forse è un problema legato al mio compilatore? 
hai fatto tutte le correzioni che ti ho scritto nel tuo codice? Il problema 
si presenta ugualmente?


Fabrizio Marini ha scritto:

perche' avrei dovuto fornire all'utente - per l'utilizzo finale - una 
funzione r_pal() con tre parametri (di cui gli ultimi 2 sempre, 
rispettivamente, a "0" e "strlen()-1"), quando potevo fornirne una migliore 
(per sicurezza ed usabilita') con un solo parametro?
Quale logica ti ha spinto a farmi questa domanda? :)
Ciao


 Quale logica ti ha spinto a farmi questa domanda? :)
Mah... penso che un programma con una funzione in meno, se la funzione 
tolta non fa altro che chiamare una funzione già presente, sia più 
facile da comprendere per chi legge il codice. 
Ma magari sbaglio... 
Ciao 
Bizio.

 si presenta ugualmente?
Sě, tranne l'utilizzo di fgets. 
In quel caso, ho sostituito scanf con while ((c = getchar()) != EOF), 
per evitare di utilizzare funzioni che a questo punto dei miei studi non 
conosco ancora. 
Il libro, infatti, chiede di fare questo esercizio non avendo ancora 
affrontato tutti gli argomenti relativi all'i/o, ed ho voluto evitare di 
falsare l'esercizio inserendo nozioni non note a questo punto del libro. 
Penso comunque che il problema sia dovuto al mio compilatore.
Grazie mille e a presto!
Bizio.

 facile da comprendere per chi legge il codice. 
...manco per idea :-)


 ancora studiato il capitolo del libro dedicato all'i/o. 
...sono tutte cose che trovi su un manuale o ricercando su google (prova a 
ricercare: "man stdio", "man fflush" e "man setvbuf"). Prova anche a cercare 
su google il doc. dello standard C99 con la parola chiave "n1124.pdf", e 
quindi leggere le specifiche di queste funzioni e della stdio in generale...
Se trovo del tempo (scusami ma sono incasinato di lavoro) poi provo a 
risponderti anch'io...


 risponderti anch'io...
No, non preoccuparti. Mi bastano le indicazioni che mi hai fornito. 
Se ciň che mi serve č scritto lě, non c'č alcuna ragione per cui io 
debba fartelo riscrivere. 
Ok anche per l'alktro messaggio sullo stesso thread.
Ciao e grazie di tutto. 
bizio.