2016-01-25 12 views
11

Quando si tenta di eseguire questo, mi dà un errore dicendo che il valore nella variabile a non è costante. Questo non ha senso per me perché ho reso esplicitamente la variabile a costante. La dimensione di un array deve essere più costante di quella? Significato, solo #define a 5 o inizializzarlo come int arr[5] o utilizzando malloc? Cosa c'è di sbagliato in ciò che ho fatto?Definizione della dimensione di un array utilizzando un const int

int main{ 

    const int a = 5; 
    int i; 
    int arr [a]; 

    for (i = 0; i < 5; i++) { 
     arr[i] = i * 2; 
    } 

    printf("%d", arr[1]); 
    return 0; 
} 
+1

La tua postulazione secondo cui le alternative disponibili sono in gran parte "# define" o "malloc" è corretta: scegli una di queste due opzioni per risolverla. La risposta di l3x fa un buon lavoro di spiegazione del perché. – GrandOpener

risposta

9

In C, const dovrebbe essere letta come sola lettura. Non definisce un tempo di compilazione.

const int a = 5; 

Qui a, è non un'espressione costante come richiesto dal C standard:

6.7.9 Inizializzazione
4 Tutte le espressioni in un inizializzatore per un oggetto che ha statico o filo la durata di archiviazione deve essere costante espressioni o stringhe letterali.

Quindi l'errore indica che si sta utilizzando un compilatore C89/C90. È possibile leggere l'input dell'utente per a e dichiarare un variable length array, che è una funzione C99, che ha durata di archiviazione automatica.

Utilizzare #define è un altro modo. Ma è semplicemente una sostituzione testuale e definisce un array con durata di archiviazione automatica. È lo stesso che definisce tu stesso lo int arr[5];.

se si desidera allocare memoria su storage dinamico (comunemente noto come "heap"), è necessario utilizzare le funzioni famiglia malloc(), che avranno una durata durante l'esecuzione del programma finché non si chiama free() su di esso.

(Si noti che questo comportamento di const è solo in C. C++ differisce in questo e funzionerà come previsto).


Se compilo il codice C89, non riesce con:

#include <stdio.h> 

int main(){ 

    const int a = 5; 
    int i; 
    int arr [a]; 

    for (i = 0; i < 5; i++) { 
     arr[i] = i * 2; 
    } 

    printf("%d", arr[1]); 
    return 0; 
} 

$ gcc -Wall -Wextra -std=c89 -pedantic-errors test.c 
test.c: In function âmainâ: 
test.c:7:4: error: ISO C90 forbids variable length array âarrâ [-Wvla] 
    int arr [a]; 
    ^

perché C89 non supporta i VLA (Anche se gcc supporta come an extension anche in C89/C90). Quindi, se stai utilizzando un compilatore che non supporta C99, non puoi utilizzare VLA. Ad esempio, Visual Studio non supporta completamente tutte le funzioni C99 e C11. Sebbene, , VLA non sono uno di loro.

Ma lo stesso codice compila in C99 e C11 senza alcun problema:

$ gcc -Wall -Wextra -std=c99 -pedantic-errors t.c 
$ gcc -Wall -Wextra -std=c11 -pedantic-errors t.c 

è perché sono stati aggiunti gli array di lunghezza variabile (VLA) in C99. Si noti che i VLA sono stati resi facoltativi nello standard C11. Quindi un'implementazione potrebbe non supportare VLA in C11. È necessario eseguire un test con __STDC_NO_VLA__ per verificare se i VLA non sono supportati dall'implementazione.

Da 6.10.8.3 Conditional feature macros

__STDC_NO_VLA__
Il numero intero costante 1, inteso per indicare che l'implementazione non supporta le matrici di lunghezza variabile o variabilmente tipi modificati.

Personalmente non utilizzo VLA in quanto l'errore di allocazione non può essere trovato in modo da poter essere trovato se la dimensione dell'array è ragionevolmente grande. Per esempio.

size_t size = 8*1024; 
int arr[size]; 

Nel frammento di cui sopra, se arr allocazione fallita, non si sa fino a runtime. Che cos'è una dimensione "abbastanza piccola" per cui l'allocazione della memoria dipende dalla piattaforma. Quindi su una macchina, l'allocazione 1MB può avere successo e un'altra potrebbe fallire e la parte peggiore è che non c'è modo di cogliere questo fallimento.

Quindi l'uso di VLA è limitato e può essere utilizzato solo con piccoli array che si sa che avranno sempre successo su una determinata piattaforma. Ma in questo vorrei semplicemente codificare a macchina le dimensioni dell'array e occuparmi delle condizioni al contorno.

+0

Oppure, se si desidera veramente la dimensione dell'array con hardcoded, utilizzare una direttiva '# define' chiamata' arraySize' o qualcosa del genere. – rlam12

+0

Non capisco perché hai solo fatto un riferimento alle VLA. Non è quello che OP sta cercando di fare? Se usa MSVC anche la versione 2015 non supporta il VLA. Ha persino menzionato i tuoi metodi nella domanda, quindi li comprende chiaramente. –

+0

@WeatherVane Hai ragione, ti garantisce un po 'più di spiegazione. Ho fatto un aggiornamento. Grazie. –

0

A const - la variabile qualificata non è la stessa cosa di una costante espressione; un'espressione costante ha il suo valore noto al momento della compilazione, mentre una variabile qualificata const (normalmente) non lo fa (anche se sembra che dovrebbe).

Si noti che in C99 e versioni successive, è possibile dichiarare gli array a lunghezza variabile, in cui la dimensione dell'array non è nota fino al runtime. È necessario utilizzare un C99 o compilatore tardi, e dato che la funzione è stata fatta opzionale nello standard 2011, si deve controllare una macro funzione per vedere se i VLA sono disponibili:

static const int a = 10; // a is not a constant expression 

#if defined(__STDC__) && defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && !defined(__STDC_NO_VLA__) 
/** 
* VLAs are available in this environment 
*/ 
#define USE_VLA 1 
#endif 

#ifdef USE_VLA 
    int arr[a]; 
#else 
    /** 
    * VLAs are not available, either because it's a pre-1999 implementation, 
    * or it's a post-2011 implementation that does not support optional 
    * VLAs. We'll have to use dynamic memory allocation here, meaning we'll 
    * also need an explicit free call when we're done with arr 
    */ 
    int *arr = malloc(sizeof *arr * a); 
#endif 
... 
    do_something_interesting_with(a); 
... 
#ifndef USE_VLA 
    free(a); 
#endif 

Almeno fino a poco tempo , Il compilatore C di Microsoft non supportava VLA. Hanno comunque aggiunto alcune funzionalità C99, come dichiarazioni e codici misti, quindi forse l'ultima versione supporta gli VLA. Non lo so.

1

Forse utilizzare un enum per definire il valore di a.

enum { a = 5 }; 
int arr [a]; 

Forse questo non è l'intenzione di un enum, ma i membri del enumerazioni sono la cosa più vicina ad una costante in C. A differenza della pratica comune di definire tutto con #define, la visibilità di a è limitato dalla portata e qui è lo stesso di arr.

+0

Fantastica idea !!! – outoftime

Problemi correlati