Domanda Esercizio con errore di compilazione

alessina02

Utente Bronze
2 Gennaio 2022
35
11
0
25
Ultima modifica:
Salve. Il mio esercizio mi dice di leggere da tastiera due numeri h e k e di inizializzare h vettori di lunghezza k. poi mi chiede di stampare due coppie di vettori e devono essere le due coppie che hanno il minor numero di elementi diversi nella stessa posizione e di mettere tra parentesi gli elementi diversi. [Esempio: con input h=3, k=6, 1 2 3 2 3 4 1 2 4 2 4 4 1 3 3 1 3 4 dovrebbe stampare
1 2 (3) 2 (3) 4 - 1 2 (4) 2 (4) 4
1 (2) 3 (2) 3 4 - 1 (3) 3 (1) 3 4]

ll problema è che il mio compilatore stampa l'output corretto e anche alcuni compilatori trovati sul web, ma il mio professore dice che con lo stesso input ha quest'output:
gcc -o aaa 1969731.1.c
./aaa
3 6 1 2 3 2 3 4 1 2 4 2 4 4 1 3 3 1 3 4
(49725488) (24576) (3) 2 1 (2) - (1) (2) (4) 2 1 (3)
(49725488) (24576) 3 (2) (1) (2) - (1) (3) 3 (1) (3) (4)

lui dovrebbe usare gcc come compilatore. Qualcuno può aiutarmi?


C:
/*Homework 3 es 1*/
#include <stdio.h>
#include <stdlib.h>
int leggi_dato (int);
int main ()
{ int h,k,i,j,m,n,p,z1,y1,z2,y2;
h=leggi_dato(h);
k=leggi_dato(k);
int **arrays;
arrays=malloc(k);
for (i=0; i<h; i++) {arrays[i]=malloc(k);
    for (j=0; j<k; j++) scanf ("%d", &arrays[i][j]);}
   
int x=k, t=k;
for (i=0; i<h; i++)
    {for (j=i+1; j<h; j++)
        {p=0; for (m=0; m<k; m++)
            {if (arrays[i][m]!=arrays[j][m]) p++;}
        if (p<x) {y2=y1; z2=z1; y1=i; z1=j; x=p;}
        else if (p<t){y2=i; z2=j; t=p;}}}
       

if ((y1==0)&&(y2==0)&&(z1==0)&&(z2==0)) {y1=0; y2=0; z1=1; z2=2;}
   
for (n=0; n<k; n++) {
    if (arrays[y1][n]==arrays [z1][n]) {
         printf ("%d\t", arrays[y1][n]);}
     else printf ("(%d)\t", arrays[y1][n]);}
printf ("-\t");
for (n=0; n<k; n++) {
    if (arrays[y1][n]==arrays [z1][n]) printf ("%d\t", arrays [z1][n]);
        else printf ("(%d)\t", arrays[z1][n]);}

printf ("\n\n");
   
for (n=0; n<k; n++) {
    if (arrays[y2][n]==arrays [z2][n]) {
         printf ("%d\t", arrays[y2][n]);}
    else printf ("(%d)\t", arrays[y2][n]);}
printf ("-\t");
for (n=0; n<k; n++) {
    if (arrays[y2][n]==arrays [z2][n]) printf ("%d\t", arrays [z2][n]);
    else printf ("(%d)\t", arrays[z2][n]);}


return 0;
}
 
Non ho provato a compilarlo con gcc ma ho notato due cose:
C:
arrays=malloc(k);
for (i=0; i<h; i++) {arrays[i]=malloc(k);

Nella prima malloc una semplice svista, andava messo h. In questo caso non c'è stata corruzione di memoria perché nell'input di esempio k > h.
Poi ho notato che le variabili y1 e z1 vengono usate prima di essere state inizializzate, questo potrebbe essere il motivo che fa leggere quei valori su compilatori diversi: magari il tuo li inizializza a 0, il suo no e finisce per fare una lettura out-of-bounds.
 
Ultima modifica:
Il codice è incompleto:

Codice:
➜ gcc -o aaa a.c
/usr/bin/ld: /tmp/ccnVP0b0.o: in function `main':
a.c:(.text+0x13): undefined reference to `leggi_dato'
/usr/bin/ld: a.c:(.text+0x20): undefined reference to `leggi_dato'
collect2: error: ld returned 1 exit status

Una volta corretto:

Codice:
➜ ./aaa      
3 6 1 2 3 2 3 4 1 2 4 2 4 4 1 3 3 1 3 4
1    2    (3)    2    (3)    4    -    1    2    (4)    2(4)    4

Questa la mia versione di gcc:

Codice:
gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)

Il tuo codice ha vari problemi. Il maggiore è l'organizzazione, che rende difficile debuggarlo. Invece di avere tutto nel main, cerca di dividerlo in varie funzioni, cosicché siano facili da debuggare.

Per esempio, se mettiamo il tuo codice che crea l'array di input in una funzione dedicata, e aggiungiamo un commento spiegando cosa dovrebbe fare:

C:
/*
Given two input parameters k and h, returns a an array of size h * k
(h vectors of size k)
*/
int **create_input_array(int k, int h)
{
    int i, j;
    int **input_array;
    input_array = malloc(k);
    for (i = 0; i < h; i++)
    {
        input_array[i] = malloc(k);
        for (j = 0; j < k; j++)
        {
            scanf("%d", &input_array[i][j]);
        }
    }
    return input_array;
}

Mhh, forse l'errore non si vede ancora benissimo, proviamo a usare nomi di variabili più indicativi, ad esempio sostituiamo "h" con "rows_nr" e "k" con "columns_nr"

C:
/*
Given two input parameters columns_nr and rows_nr, returns a an array
of size rows_nr * columns_nr (rows_nr vectors of size columns_nr)
*/
int **create_input_array(int columns_nr, int rows_nr)
{
    int i, j;
    int **input_array;
    input_array = malloc(columns_nr);
    for (i = 0; i < rows_nr; i++)
    {
        input_array[i] = malloc(columns_nr);
        for (j = 0; j < columns_nr; j++)
        {
            scanf("%d", &input_array[i][j]);
        }
    }
    return input_array;
}
Ecco, adesso si vede bene l'errore: entrambe le malloc usano `columns_nr` (nella tua versione originale, `k`).

Quindi, il comportamento di parte del programma è decisamente undefined: il prof ha un output diverso perché probabilmente esegue vari programmi uno dopo l'altro, e parte della memoria che usi è "sporca".

Ora, non sono sicuro di aver capito il tuo algoritmo, e mi sembra che non vada bene per molti tipi differenti di input (cosa succede, per esempio, se il h e k sono 10 e 10?).

Se io dovessi fare un esercizio del genere, affronterei il problema in questo modo:
- creo una funzione che calcoli la "distanza" tra due vettori (quanti numeri di differenza ci sono tra due vettori?)
- inizierei a ciclare sulla matrice, finché ci sono vettori, stampano prima quelli con distanza zero, poi quelli con distanza 1, e cosi via
 
Scusate non credo di aver capito bene. In pratica il problema è che salvo due volte nella malloc e quindi si sovrascrive giusto? Quindi potrei eliminare la riga 10 del programma
C:
arrays=malloc (k)
e lasciare solo il ciclo for, in questo modo salverei tutto una volta sola. Se qualcuno potesse compilarlo su gcc senza la riga 10 e vedere se dà il giusto output sarebbe perfetto
 
È una vita che non scrivo codice C, ma ci ho provato. Il codice non è ottimale (si possono fare vari miglioramenti per renderlo più performante, e.g. non ricontrollando gli stessi array), e ha zero gestione degli errori, ma sembra funzionare:

C:
#include <stdio.h>
#include <stdlib.h>

/*
Given two input parameters array_length and nr_arrays, returns a an array
of size nr_arrays * array_length (nr_arrays vectors of size array_length)
*/
int **create_input_array(int array_length, int nr_arrays)
{
    int **input_array;
    input_array = malloc(nr_arrays);

    for (size_t i = 0; i < nr_arrays; i++)
    {
        input_array[i] = malloc(array_length);
        for (size_t j = 0; j < array_length; j++)
        {
            scanf("%d", &input_array[i][j]);
        }
    }

    return input_array;
}

/*
Given two arrays, both of the same length, calculates the Levenshtein distance
among them (i.e, how many different digits in the same position they have)
*/
int calculate_distance(int *first_array, int *second_array, int length)
{
    int distance = 0;

    for (size_t i = 0; i < length; i++)
    {
        if (first_array[i] != second_array[i])
        {
            distance++;
        }
    }

    return distance;
}

/*
Given two arrays, both of the same length, print them both, using brackets
to highlight the values in the same position which differs as value
*/
void print_arrays_highlight_differences(int *first_array, int *second_array, int length)
{

    for (size_t n = 0; n < length; n++)
    {
        if (first_array[n] == second_array[n])
        {
            printf(" %i ", first_array[n]);
        }
        else
        {
            printf("(%i)", first_array[n]);
        }
    }

    printf("\t-\t");

    for (size_t n = 0; n < length; n++)
    {
        if (first_array[n] == second_array[n])
        {
            printf(" %i ", second_array[n]);
        }
        else
        {
            printf("(%i)", second_array[n]);
        }
    }

    printf("\n");
}

int leggi_dato();
int main()
{
    int nr_arrays, array_length, i, j, m, n, p, z1, y1, z2, y2;

    nr_arrays = leggi_dato();
    array_length = leggi_dato();

    int **arrays = create_input_array(array_length, nr_arrays);

    // Let's keep track of how many arrays we have already printed
    int arrays_already_printed = 0;

    // This counter will increase in each cycle of the loop, to track
    // which "distance" we want to print now
    int distance_counter = 0;

    while (arrays_already_printed < nr_arrays)
    {
        // We go through all the arrays
        for (size_t i = 0; i < nr_arrays; i++)
        {
            // Each array checks only the ones after itself
            for (size_t j = i + 1; j < nr_arrays; j++)
            {
                if (calculate_distance(arrays[i], arrays[j], array_length) == distance_counter)
                {
                    print_arrays_highlight_differences(arrays[i], arrays[j], array_length);
                    arrays_already_printed += 2;
                    break; // We have found the "pair" we were looking for,
                           // let's skip to the next row of the matrix
                }
            }
        }

        distance_counter++;
    }

    return 0;
}

int leggi_dato()
{
    int a;
    scanf("%d", &a);
    return a;
}
Messaggio unito automaticamente:

Scusate non credo di aver capito bene. In pratica il problema è che salvo due volte nella malloc e quindi si sovrascrive giusto? Quindi potrei eliminare la riga 10 del programma
C:
arrays=malloc (k)
e lasciare solo il ciclo for, in questo modo salverei tutto una volta sola. Se qualcuno potesse compilarlo su gcc senza la riga 10 e vedere se dà il giusto output sarebbe perfetto
No, devi comunque allocare anche arrays.
Ma arrays rappresenta il numero di vettori che hai, quindi linea 10 dovrebbe essere arrays=malloc (h).
Dopodiché, per ognuno degli array da 0 a h, devi inizializzare con arrays[i] = malloc(k)