2012-04-16 2 views
10

La domanda è di descrivere cosa fa il codice, cosa fa la funzione.Comprensione del codice scritto male, secondo anno CS del documento precedente

Il seguente codice fa parte dei documenti di esame precedenti per un modulo C e C++ del 2 ° anno. Il compito è descrivere cosa fa il seguente pezzo di codice. Ho scritto il codice esattamente come presentato, con alcuni commenti aggiunti da me stesso.

int g(int * y, unsigned size, int z) { 
    int tmp = y[0]; 
    // what type is unsigned size? Int I presume. Why would you add an int to an array of ints? 
    int * b = y + size; 
    y[0] = z; 
    // I have the most difficulty understanding the following. 
    while (1) if (*(--b)==z){y[0] = tmp; return b - y;}; 
    // are the following 3 lines ever even reached? 
    y[0] = tmp; 
    if (tmp == z) return 0; 
    else return -1; 
} 
+7

Qual è la domanda? –

+0

"che tipo è la dimensione senza segno?" Perché, 'unsigned', o, con nome di famiglia,' unsigned int'. –

+18

Dev'essere completamente in disaccordo con la chiusura di questa domanda. Sono contrassegnati come 'compiti a casa ', è chiaro, e l'OP ha domande specifiche sul codice che sono chiaramente disposte e interamente rispondibili. –

risposta

10
// what type is unsigned size? 

E 'un unsigned int chiamato size. Lo aggiungi a un puntatore come nella normale aritmetica del puntatore: fai avanzare questo puntatore fino alla fine dell'array.

while (1) if (*(--b)==z){y[0] = tmp; return b - y;}; 

OK, abbiamo

  • while(1) = while (true), o 'loop per sempre'
  • *(--b) pre-decremento B e leggere il valore che l'indice della matrice
  • se abbiamo trovato z, sostituire il primo elemento con il valore che abbiamo letto e restituire b-y - aritmetica del puntatore per l'indice dell'array siamo a

, ad esempio, stiamo eseguendo una scansione all'indietro attraverso l'array per trovare l'ultima istanza di z e restituire l'indice in cui è stato trovato. Ci sarà sempre trovare z nella matrice perché abbiamo messo lì come primo elemento, vale a dire se z non è nella matrice allora torniamo 0.

// are the following 3 lines ever even reached? 

No, io non la penso così.

+2

C'è un problema con il codice, però: se 'size == 0', il ciclo inizierà la scansione all'indietro dalla posizione di memoria _prima_ il primo elemento di' y'. Questo non può essere buono. In particolare, in questo caso non si garantisce che il ciclo terminerà normalmente. Il ciclo terminerà quando trova una posizione di memoria casuale che ha il valore di 'z' memorizzato in esso o si bloccherà quando tenterà di dereferenziare un indirizzo di memoria illegale. –

+0

@Ted sì, vero - non esiste alcuna convalida dell'intervallo per "dimensione" in entrambi i casi. Buon posto! – Rup

7

tipo è formato unsigned

unsigned è breve per unsigned int.

Perché dovresti aggiungere un int a una serie di ints?

I puntatori e gli array non sono la stessa cosa. Il codice che hai mostrato usa puntatori, non matrici. Dopo la riga int * b = y + size;, b è un puntatore che punta alle voci size da cui punta . Ad esempio, se size fosse 2, b indicherà la terza voce. ASCII-art:

+---------+ 
| entry 0 |<--- `y` points here 
| entry 1 | 
| entry 2 |<--- `b` points here if `size` is `2` 
| entry 3 | 
| entry 4 | 
+---------+ 

ho più difficoltà a comprendere quanto segue.

while (1) if (*(--b)==z){y[0] = tmp; return b - y;};

Il ciclo guarda le voci nella memoria puntato da y a partire dalla registrazione prima quello identificato dal size. Se la voce è == per z, imposta y[0]-tmp e restituisce l'indice in cui è stata trovata la voce (mediante l'aritmetica dei puntatori, b - y restituisce il numero di voci tra cui b sta indicando e l'inizio del y. Dal momento che --b decrementa il puntatore, il circuito funziona a ritroso attraverso la memoria.

sono le seguenti 3 righe mai ancora raggiunto?

No. il return uscirà dalla funzione di quando viene trovata la prima voce corrispondente, w che può essere all'inizio (come y[0] è impostato su z nella fase iniziale). Come Ted Hoff fa notare nei commenti, tuttavia, il ciclo inizierà e continuerà oltre l'inizio (dove sta puntando) se size è 0 in ingresso, il che probabilmente causerebbe il fallimento del programma con una violazione di accesso alla memoria.

+0

Grazie, questo è molto utile. Inoltre Rup ha sottolineato che y [0] è impostato su z all'inizio, quindi z sarà sempre trovato. –

+0

@MikeGallagher: Doh, ho perso quel po '. Fisso. –

+0

@MikeGallagher - 'z' non verrà trovato se' size == 0'. –

5

La prima cosa che fa questo codice è dimostrare che l'autore è incompetente. Ma ho capito che è parte del compito: capire il codice scritto da persone incompetenti.

Per cominciare:

  • unsigned è un tipo valido C++, una contrazione per unsigned int. È meglio evitare , a meno che tu non stia manipolando bit.

  • Non ci sono matrici nel codice; stai aggiungendo un numero intero a un puntatore . E curiosamente, [] non è l'indicizzazione di array, ma
    definito in modo che a[b] è esattamente equivalente a *(a+b). (Almeno per i tipi di build.) Potresti voler trovare un libro su C, per spiegare ; in C++, generalmente utilizziamo std::vector, precisamente per evitare tutto di questa confusione sull'aritmetica del puntatore.

quanto riguarda la parte avete difficoltà a comprendere: per cominciare, di lasciare scriverlo in un modo sano di mente:

while (true) { 
    -- b; 
    if (*b == z) { 
     y[0] = tmp; 
     return b - y; 
    } 
} 

L'unica cosa che dovrebbe causare un problema c'è l'istruzione return : questa è sottrazione puntatore; in questo caso, poiché è il primo elemento di un array (a giudicare dal resto del codice), b - y calcola l'indice dell'elemento puntato a da b.

L'uso dei puntatori qui sarebbe pura offuscazione, tranne che l'idioma è onnipresente in C e viene portato avanti con gli iteratori in C++.

E hai ragione che il codice dopo il ciclo non può mai essere eseguito; il solo modo di lasciare il ciclo è attraverso il return.

Un modo molto più pulito di scrivere il ciclo sarebbe:

int i = size; 
while (i != 0 && y[i - 1] != z) { 
    -- i; 
} 
y[0] = tmp; 
return i; 
+1

Il tuo ultimo pezzo di codice non sembra del tutto corretto. Per uno, le parentesi non sono equilibrate. Supponendo che il rientro rifletta il rinforzo previsto, non è nemmeno equivalente al codice OP (in particolare quando 'size == 0'). –

+0

+1 solo per il "... scriviamolo in modo sano ..." ;-) –

+0

@TedHopp Ho dimenticato la parentesi di chiusura; Lo aggiusterò. Per quanto riguarda il caso in cui 'size == 0', il codice originale aveva un comportamento indefinito in quel caso, quindi non credo di dover essere identico :-). –