Newsgroup: it.comp.lang.c
Titolo: Dove sbaglio: verifica vettore ordinato

Premesso che sono un newbie ecco 
il problema dell'esercizio:
"dato un vettore di NMAX interi
dire se questo vettore e' ordinato
in senso crescente"
prendo carta e matita e inizio a scrivermi
il pseudo-codice, come mi hanno insegnato.
In senso crescente per me significa che
anche l'array
{10,20,20,30,40}  
e' ordinato in senso crescente (ma non
strettamente crescente)
Una specie di mio pseudo-codice e' questo:
leggi vettore;
finché k < NMAX:
  se vettore [k+1] < vettore [k]
    stampa "Vettore decrescente"
    esci
  altrimenti {cioè vettore[k+1] >=  k)
    incrementa k
 
{Se il ciclo viene completato allora il vett. e' crescente} 
stampa "Vettore crescente"
fine
che ho provato a codificare nel seguente modo;
il problema e' che stampa sempre "Vettore decrescente"
#include <stdio.h>
#define NMAX 5
int main (char** argv, int argc)
{
    int a[NMAX];
    int j=0,k=0;
 
    for (j=0; j<NMAX; j++)
    {
        printf ("Elemento[%d]: \n", j);
        scanf("%d",a);
    } 
 
    k=0; 
    while (j<NMAX) 
    {
       if (a[j+1] < a[j])
          {
             printf ("Vettore decrescente");
             break;          
          }        
       else   
          j=j+1;        /* passa all'indice successivo */    
          continue;     
    }
    getch();
    return 0;
}
#include <stdio.h>
#define NMAX 5
int main (char** argv, int argc)
{
    int a[NMAX];
    int j=0,k=0;
 
    for (j=0; j<NMAX; j++)
    {
        printf ("Elemento[%d]: \n", j);
        scanf("%d",a);
    } 
 
    k=0; 
    while (j<NMAX) 
    {
       if (a[j+1] < a[j])
          {
             printf ("Vettore decrescente");
             break;          
          }        
       else   
          j=j+1;        /* passa all'indice successivo */    
          continue;     
    }
    getch();
    return 0;
}
 

 }
P.S. k che cosa ci sta a fare?

 decrescente.
Si potrebbe fare una funzione unica (scrivo al volo, senza testare):
typedef enum { crescente, decrescente } ordine_t;
void test_array(int *a, int n, ordine_t o) {
    int i;
    for (i=0; i<n-1; i++)
       if ((o==crescente)?(a[i]>a[i+1]):(a[i]<a[i+1])) return 0;
    return 1;
}

Andrea Laforgia ha scritto:

Si potrebbe ancora generalizzare ulteriormente con una funzione del
genere:
int test_array(void *a, int n, int w, int (*funz)(void *, void *),
ordine_t o) {
    char *arr = (char *) a;
    int i;
    for (i = 0; i < n-1; i++) {
        int ret = (*funz)(arr + i*w, arr + (i+1)*w);
        if (ret > 0 && o == crescente) return 0;
        if (ret < 0 && o == decrescente) return 0;
    }
    return 1;
}
dove la funzione passata come argomento dovrebbe restituire un numero
minore di zero se il primo argomento è minore del secondo argomento,
zero sei i due argomenti sono uguali e un numero maggiore di zero se il
primo argomento è maggiore del secondo argomento.
Si potrebbe usare così:
int funz(void *a, void *b) {
    return *((int *) a) - *((int *) b);
}
int main(int argc, char **argv) {
    int a[NMAX], i;
    for (i = 0; i < NMAX; i++) {
        printf("a[%d] = ", i);
        scanf("%d", &a[i]);
    }
    if (test_array(a, NMAX, sizeof(int), funz, crescente))
        printf("Crescente\n");
    else if (test_array(a, NMAX, sizeof(int), funz, decrescente))
        printf("Decrescente\n");
    else
        printf("Disordinato\n");
    getch();
    return 0;
}
Tuttavia, non mi sembra il caso di arrivare a questi livelli. Penso che
la domanda di frank sia già stata soddisfatta con le primissime
risposte.

 genere:
[...]
No, a mio avviso.  Non ha senso usare un ordine_t se la relazione 
d'ordine è impostata a livello di funzione esterna.  A quel punto, 
basta usare _solo_ la funzione sui due elementi dell'array per 
determinare se finire o andare avanti.

Andrea Laforgia ha scritto:

Per me non è così. Preferisco, a mio avviso, tenere distinte le due
azioni: un conto è confrontare due elementi, un altro è impostare una
funzione affinchè il suo comportamento si adegui alla mia volontà.
Certo, il tuo metodo potrebbe essere valido per risparmiare righe di
codice (forse), ma credo che concettualmente (e per chiarezza del
codice stesso) sia più opportuno tenere separate la funzione passata
come argomento e il tipo di ordinamento che ci aspettiamo dall'array.

 come argomento e il tipo di ordinamento che ci aspettiamo dall'array.
No, è sbagliato e ridondante, a mio avviso.
Concettualmente, se deleghi il compito di stabilire quale sia la 
relazione d'ordine a una funzione, non ha senso considerare un ordine_t 
come quello definito (crescente o decrescente).  Se, ad esempio, io 
voglio testare che in un array gli elementi siano, nell'ordine, l'uno il 
doppio dell'altro, delego il controllo a una funzione che verifica la 
relazione d'ordine.  Se voglio testare che gli elementi, nell'ordine, 
siano l'uno maggiore dell'altro, delego ugualmente il compito a una 
funzione:
#include <stdio.h>
#include <stdlib.h>
typedef int (*rel_ord_fn)(int, int);
int relazione_ordine1(int a, int b) {
     return (b==(2*a));
}
int relazione_ordine2(int a, int b) {
     return (b>a);
}
int test_array(int *a, size_t n, rel_ord_fn f) {
     int i;
     for (i=0; i<n-1; i++)
       /* se non è rispettata la relazione d'ordine... */
       if (!f(a[i], a[i+1])) return 0;
     return 1;
}
int main(int argc, char *argv[])
{
     int a[]={2,4,6};
     size_t asz = sizeof a/sizeof a[0];
     printf("%d %d\n", test_array(a, asz, relazione_ordine1),
                       test_array(a, asz, relazione_ordine2));
     system("PAUSE");	
     return 0;
}

Ringrazio tutti; in effetti non so k come sia capitata
(non era associata a nulla!).
Cosi' sembra che funziona. Pero' ho usato una exit(0)
per uscire; break mi ritornava al main e quindi
mi stampava sia vettore decrescente che crescente.
E' ortodosso l'uso di exit?
Grazie
/****************/
#include <stdio.h>
#define NMAX 5
int main (char** argv, int argc)
{
    int a[NMAX];
    int j;
 
    for (j=0; j<NMAX; j++)
    {
        printf ("Elemento[%d]: \n", j);
        scanf("%d",&a[j]);
    } 
 
    j=0; 
    while (j<NMAX) 
    {
       if (a[j+1] < a[j])
          {
             printf ("Vettore decrescente");
             getch();
             exit(0);          
          }        
       else   
          j=j+1;        /* passa all'indice successivo */                  
    }
    printf ("Vettore crescente");
    getch();
    return 0;
}
 
 

crescente.
Fortunatamente era "crescente" e "non crescente" ero io che non avevo
compreso bene la traccia del problema.

        if (a[j+1] < a[j])
Quando j è uguale a NMAX-1 questo confronto diventa:
if (a[NMAX]<a[NMAX-1])
ed è errato, perché a[NMAX} non esiste.

Prova con questo
/* Programma per la verifica dell'ordinamento di un array */
int main(void)
{
int i,NMAX,vettore[100];
printf("Inserisci il numero di elementi del vettore (<100):");
scanf("%d",&NMAX);
/* lettura degli elementi del vettore */
printf("\n Inserisci gli elementi del vettore \n");
for (i=0;i<NMAX;i++)
scanf("%d",&vettore[i]);
i=0;
while ((i<NMAX) && (vettore[i]<vettore[i+1]))
i=i+1;
if (i==NMAX-1)
printf("\n Il vettore e' ordinato in senso crescente \n");
else
printf("Il vettore non è ordinato in senso crescente \n");
}
-- 
      Teaching OnLine 
Corsi online di programmazione
Php, Asp, C, C++, Visual Basic, Delphi
VBA per Access, Excel
Linux Shell Programming
------------------------------------
http://www.teachingonline.it

 Significa che si va da 0 a NMAX-1
ok quindi dovrei fare:
finché j <= NMAX-1

 finché j <= NMAX-1
Neanche, perché scrivere (j<NMAX) e (j<=NMAX-1) significa scrivere la 
stessa cosa.  Devi scrivere: (j<NMAX-1).
Se il numero di elementi è 5 (i.e. da 0 a 4), j deve andare da 0 a 3 e 
j+1 da 1 a 4.

 i=i+1;
Questo codice è errato, quando i vale NMAX-1, i+1 assume il valore NMAX 
e vettore[NMAX] non esiste.



 A dire il vero, prima di postare codice, com e' mio solito, l'ho
 compilato, eseguito, e verificato che funzionasse.
Avresti dovuto leggere meglio il codice, perchè i=i+1 viene eseguito nel
while, e quindi se sono vere le due condizioni, avviene l'incremento di i.
La variabile i non viene incrementata alla fine del ciclo, ma solo durante
il ciclo.
Comunque, ecco una prova dell'esecuzione del codice che tu dici essere
errato:
-----------------
Prova 1 
Inserisci il numero di elementi del vettore (<100):6
 Inserisci gli elementi del vettore
1
2
3
4
5
6
 Il vettore e' ordinato
-----------------
Prova  2
Inserisci il numero di elementi del vettore (<100):6
 Inserisci gli elementi del vettore
4
3
5
2
1
9
Il vettore non e' ordinato in senso crescente
-----------------
Prova 3 
Inserisci il numero di elementi del vettore (<100):6
 Inserisci gli elementi del vettore
6
5
4
3
2
1
Il vettore non e' ordinato in senso crescente
Come vedi, a me il codice funziona.
Saluti,
Franz


 while, e quindi se sono vere le due condizioni, avviene l'incremento di i.
Sei tu che devi prestare maggiore attenzione.
Scrivere:
i=0;
while (i<NMAX && (...))
   i=i+1;
significa verificare anche la condizione (i==NMAX-1) e quando questa 
condizione è vera si procede ad analizzare (vettore[i]<vettore[i+1]) 
che, ti ripeto, quando i==NMAX-1 diventa:
(vettore[NMAX-1]<vettore[NMAX]).
Quella condizione, a quel punto, è errata, perché vettore[NMAX] non esiste.

 Quella condizione, a quel punto, è errata, perché vettore[NMAX] non esiste.
Hai ragione, non ci avevo pensato (vecchie incrostazioni di Pascal e di
Fortran), ho modificato il codice del ciclo nel modo seguente, e non ho
verificato errori
i=1;
while ((i<NMAX) && (vettore[i-1]<vettore[i])) i=i+1;
Ora, quando la variabile "i" raggiunge il suo valore massimo è uguale a
NMAX-1, e viene eseguito il confronto tra Vettore[NMAX-2] e
Vettore[NMAX-1], cioè degli elementi nelle due ultime posizioni del
vettore, considerato che il primo indice e' zero.
Ad esempio, se NMAX=6, allora NMAX-1=5 e NMAX-2=4 e gli elementi del
vettore sono
V[0], V[1], V[2], V[3], V[NMAX-2],V[NMAX-1]
Frank

Perfetto ora ho capito
Ti ringrazio infinitamente per l'aiuto e per la pazienza.
ciao

 while ((i<NMAX) && (vettore[i-1]<vettore[i])) i=i+1;
Bastava anche solo modificare il vecchio (i<NMAX) in (i<NMAX-1).
Comunque, quello che ti è accaduto è una prova in più del fatto che non 
bisogna mai assumere il funzionamento di un programma come prova 
inequivocabile della sua correttezza.  A volte un programma produce 
risultati corretti per puro caso e la cosa "strabiliante" è che può 
farlo anche per molte volte.