2013-10-16 13 views
5

Ho scritto un semplice programma C per convertire char in Token s. Le cose funzionano bene ma non riesco a capire perché il valore della variabile size sta cambiando.Variabile inspiegabile nella variabile C

typedef struct _token { 
    int val; 
} Token; 

void parse(char* code, int size, Token** tokens) { 
    int i = 0; 
    for (; i < size; i++) { 
     tokens[i] = malloc(sizeof(Token)); 
     tokens[i]->val = code[i]; 
    } 
} 

int execute(char *path) { 
    char* code; 
    if (read_file(path, &code) != 0) { 
     return -1; 
    } 
    int size = strlen(code) - 1; 
    printf("BEFORE PARSE: %d\n", size); // 1st printf 
    Token *tokens; 
    parse(code, size, &tokens);   
    printf("AFTER PARSE: %d\n", size);  // 2nd printf 
    return 0; 
} 

se code contiene "abcde", il risultato è:

BEFORE PARSE: 5 
AFTER PARSE: 142786584 

Il secondo printf mostra valori diversi in diverse esecuzioni.

Si prega di aiuto!

PS: Sono un Noob!

EDIT:

int read_file(char* path, char** code) { 
    FILE* fp = fopen (path , "rb"); 
    if(!fp) { 
     return -1; 
    } 

    fseek(fp , 0L , SEEK_END); 
    long lSize = ftell(fp); 
    rewind(fp); 

    /* allocate memory for entire content */ 
    *code = calloc(1, lSize+1); 
    if(!*code) { 
     fclose(fp); 
     return -1; 
    } 

    /* copy the file into the buffer */ 
    if(1 != fread(*code , lSize, 1 , fp)) { 
     fclose(fp); 
     return -1; 
    } 

    fclose(fp); 
    return 0; 
} 
+2

devi gettoni malloc prima di chiamare parse. –

risposta

3

Si dispone di un tipico caso di overflow del buffer.

char* code; 

assegna un puntatore a carattere (tipicamente 8 byte), non un buffer per contenere i dati dei file.

Stessa cosa con

Token *tokens; 

Quando si scrive per tokens in parse di sovrascrivere parte del tuo stack e size con esso.

Assegnare abbastanza memoria per loro!

char * code = malloc(0x1000); 
Token *tokens = malloc(0x100 * sizeof(Token *)); 

e passare il puntatore, non il suo indirizzo:

read_file(path, code); 
parse(code, size, tokens); 

Qui viene corretto codice:

typedef struct _token { 
    int val; 
} Token; 

void parse(char* code, int size, Token* tokens) { 
    int i = 0; 
    for (; i < size; i++) { 
      // you already have memory now 
     tokens[i]->val = code[i]; 
    } 
} 

int execute(char *path) { 
    char* code = malloc(0x1000); 
    if (read_file(path, code) != 0) { 
     return -1; 
    } 
    int size = strlen(code) - 1; 
    printf("BEFORE PARSE: %d\n", size); // 1st printf 
    Token *tokens = calloc(sizeof(Token), 0x100); 
    parse(code, size, tokens);   
    printf("AFTER PARSE: %d\n", size);  // 2nd printf 
    return 0; 
} 
+0

Hai ragione sui token, ma mi sembra che il codice venga probabilmente modificato per puntare a un buffer allocato in read_file() - che sarebbe coerente con lo stile di implementazione usato in execute() –

+0

@ChrisStratton può essere. Non ha fornito il codice per read_file, quindi non posso dirlo con certezza. Sarebbe piuttosto inusuale però. –

+0

È la spiegazione logica per l'utilizzo dell'operatore &, e stilisticamente coerente con il codice che è stato fornito. Inoltre, anche se tu fossi in qualche modo giusto, non potrebbe essere la causa del problema riscontrato, che si verifica solo più tardi. –

5

E 'perché i token non è mai inizializzati. Cambiarlo in:

Tokens **tokens = malloc(sizeof(Tokens *) * size); 

Non dimenticare di liberare la memoria quando si è fatto con esso:

for (; i < size; i++) { 
    free(tokens[i]); 
} 

free(tokens); 
+0

Sei sicuro di voler chiamare 'free (token [i])'? Stai passando una struct invece di un puntatore. Inoltre potevi essere avvisato che stai chiamando 'malloc()' una volta ma 'free()' in un ciclo. In questo modo non possono mai eguagliare. –

+0

Anche 'sizeof (Tokens *)' è sbagliato quando si assegna un array i cui elementi sono di tipo 'Token', non' Token * '. –

+1

@ PavelŠimerda all'interno di 'parse()' sta allocando le singole strutture Token: 'token [i] = malloc (sizeof (Token));' così 'token 'è una matrice di' Token * '. Ma sì, per essere corretto, 'i token 'dovrebbero essere dichiarati come' Token ** 'e dovrà anche aggiornare il modo in cui' parse' vi accede. –