[C] Costruzione di un quadrato magico con vettore multidimensionale dinamico

meganerd
Ho creato un programma che "avrebbe dovuto" stampare un quadrato magico, ma non mi dà i risultati corretti. E' tutto il pomeriggio che cerco di capire dove ho sbagliato ma il programma mi sembra corretto e.

"Memorizzate il quadrato magico in un vettore a due dimensioni. Iniziate met­tendo il numero 1 in mezzo alla riga 0. Disponete i numeri rimanenti 2, 3, ... ,n2 muovendovi in su di una riga e di una colonna. Qualsiasi tentativo di andare fuori dai limiti del vettore deve "arrotolarsi" sulla faccia opposta del vettore stesso. Per esempio, invece di memorizzare il prossimo numero nella riga -1, dovremmo salvarlo nella riga n 1 (l'ultima riga). Invece di memorizzare il prossimo numero nella colonna n, lo memorizzeremo nella colonna 0. Se un particolare elemento del vettore è già occupato mettete il numero immediatamente sotto il numero che è stato memorizzato precedentemente."

Ad esempio per n = 5 il risultato corretto sarebbe

17 24  1  8 15
23  5  7 14 16 
 4  6 13 20 22
10 12 19 21  3 
11 18 25  2  9 


#include <stdio.h>

int main(void)
{
    int grandezza = 1, quadrato[grandezza][grandezza], indice_r = 0, indice_c = 0, provv_indice_r = 0, provv_indice_c = 0;

    printf("La grandezza del quadrato deve essere compresa tra 1 e 99 e deve essere dispari.\nInserisci la grandezza: ");
    scanf("%d", &grandezza);
//Il punto da cui partire è la colonna centrale
    indice_c = grandezza/2;

//Mi assicuro che tutti gli elementi siano uguali a zero
    for (int r = 0; r < grandezza; r++) {
        for (int c = 0; c < grandezza; c++) {
            quadrato[r][c] = 0;
        }
    }

//Qui gli indici del vettore sono 0 e 2, i inizia da uno che è il primo elemento da inserire
    for (int i = 1; i <= grandezza*grandezza; i += 1) {
        quadrato[indice_r][indice_c] = i;
//Uso degli indici provvisori per controllare che la casella successiva (in diagonale) non sia occupata
        provv_indice_r = (indice_r + (grandezza - 1)) % grandezza;
        provv_indice_c = (indice_c + 1) % grandezza;
//Se la casella in questione è diversa da zero (occupata), l'indice delle colonne rimane quello di prima, ma mi sposto in basso
//di una riga; se anche la casella in questione (in pratica quella sotto) è occupata vuol dire che il quadrato è pieno
        if (quadrato[provv_indice_r][provv_indice_c] != 0) {
            indice_r = (indice_r + 1) % grandezza;
            if (quadrato[indice_r][indice_c] != 0) {
                break;
            }
//Se la casella è libera allora posso rendere definitivi gli indici provvisori
        } else {
            indice_r = provv_indice_r;
            indice_c = provv_indice_c;
        }
//A questo punto avrò gli indici aggiornati, che potranno esseere usati per assegnare la prossima i nella casella corrispondente
//e il ciclo si ripete
    }

//Stampo la matrice creata
    for (int r = 0; r < grandezza; r++) {
        for (int c = 0; c < grandezza; c++) {
            printf("%2d ", quadrato[r][c]);
        }
        printf("\n\n");
    }

    return 0;
}


Grazie in anticipo

Risposte
apatriarca
C'è un problema nella dichiarazione del tuo vettore bidimensionale. Anche se hai dichiarato l'array usando una variabile come dimensione, la dimensione dell'array non varia al variare di essa. La dimensione viene valutata nel punto di creazione e rimane poi costante. Nel tuo caso hai quindi che il tuo array bidimensionale ha dimensione \(1 \times 1\).. L'array va insomma dichiarato dopo lo scanf oppure dichiarato come puntatore e poi allocato dinamicamente sempre dopo lo scanf.

Correggendo questo problema sembra che il programma stampi il quadrato corretto. Credo quindi potesse essere l'unico errore.

meganerd
Si era proprio quello! In precedenza avevo anche provato a metterla dopo perchè avevo il dubbio, ma non funzionava comunque (per un altro bug), l'ho quindi riportata in alto pensando fosse ininfluente, ma una volta risolto l'altro errore mi sono dimenticato di provare a dichiararlo dopo. Inoltre qualche giorno fa avevo fatto un algoritmo (l'esercizio sul cifrario di cesare per il quale avevo chiesto consiglio) e avevo usato un vettore variabile dichiarandolo e solo dopo aggiornando la variabile lunghezza da input, però mi sembra che funzioni bene.

Quindi mi confermi che se uso una variabile per la lunghezza di un vettore devo dichiararlo sempre dopo? E non posso più cambiare tale lunghezza dopo aver dichiarato il vettore?

Se hai tempo per dare un'occhiata ti lascio l'algoritmo dell'esercizio sul cifrario.

#include <stdio.h>

int main(void)
{
    int n = 1, carattere, scorrimento;
    char frase[n];

    printf("Inserisci la frase da decifrare: ");
    while ( (carattere = getchar()) != '\n' ) {
        frase[n-1] = carattere;
        n += 1;
    }
    n -= 1;

    printf("Inserisci lo scorrimento (1-25): ");
    scanf("%d", &scorrimento);
    for (int i = 0;i < n; i++) {
        if ( (frase[i] >= 'a') && (frase[i] <= 'z') ) {
            printf("%c", ((frase[i] - 'a' + scorrimento) % 26) + 'a');
        } else if ( (frase[i] >= 'A') && (frase[i] <= 'Z') ) {
            printf("%c", ((frase[i] - 'A' + scorrimento) % 26) + 'A');
        } else printf("%c", frase[i]);
    }

    return 0;
}


Vedendo che (apparentemente) funziona avevo concluso che anche facendo la dichiarazione prima, la grandezza del vettore si adattasse automaticamente all'aggiornarsi della variabile n usata per la grandezza del vettore stesso. Mi confermi che avevo capito male?

apatriarca
Sì, devi sempre metterlo dopo. A seconda dei casi potrebbe non cascare o funzionare in modo errato. Ma è solo un caso. Su un altro computer o altro compilatore potrebbe comportarsi diversamente.

meganerd
Meno male che ho chiesto allora!

Solo un'ultima cosa. Nell'ultimo algoritmo che ho postato l'idea era quella di far adattare la grandezza del vettore al numero di lettere della frase, quindi la grandezza del vettore veniva aggiornata man mano che la getchar() riceveva una lettera in input... va da se che quell'idea poteva funzionare solo se i vettori variabili funzionassero nella maniera in cui avevo capito io e si poteva dichiararli prima di avere il valore della variabile. Dovendo spostare la dichiarazione dopo, quell'algoritmo non ha più senso, quindi ti chiedo: vedi un modo di impostare la variabile in maniera non esplicita (per esplicita intendo come nel programma del quadrato magico ossia chiedendolo all'utente), ma facendola "dedurre" all'algoritmo in base alla lunghezza della frase? So che quel programma non ha bisogno nemmeno dei vettori, ma visto che sono degli esercizi volevo togliermi questa curiosità.

apatriarca
Il C è un linguaggio di livello abbastanza basso. Non ci sono astrazioni che non siano praticamente immediate da fare in assembly. Inoltre farlo funzionare come vorresti richiederebbe di controllare continuamente se il valore della variabile è cambiato o usare qualche altro tipo di meccanismo. Non è insomma semplice.

meganerd
Capito. Grazie mille!

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.