2010-04-29 10 views
8

ecco il codice:Come determinare la fine di un array intero quando si manipola con un puntatore intero?

int myInt[] ={ 1, 2, 3, 4, 5 }; 
int *myIntPtr = &myInt[0]; 
while(*myIntPtr != NULL) 
{ 
    cout<<*myIntPtr<<endl; 
    myIntPtr++; 
} 

Output: 12345....<junks>.......... 

Per array di caratteri: (Dal momento che abbiamo un carattere null alla fine, non è un problema, mentre l'iterazione)

char myChar[] ={ 'A', 'B', 'C', 'D', 'E', '\0' }; 
char *myCharPtr = &myChar[0]; 
while(*myCharPtr != NULL) 
{ 
    cout<<*myCharPtr<<endl; 
    myCharPtr++; 
} 

Output: ABCDE 

La mia domanda è dato diciamo per aggiungere NULL carattere come la fine delle stringhe, escludiamo tali problemi! Se nel caso, è la regola per aggiungere 0 alla fine dell'array intero, avremmo potuto evitare questo problema. Cosa dire?

risposta

10

La convenzione C-stringhe è che un carattere * termina con un carattere '\ 0'. Per array o qualsiasi altro contenitore C++ ci sono altri idiomi che possono essere applicati.Avanti segue le mie preferenze

Il modo migliore per iterare sulle sequenze è quello di usare il Range-based per-loop inclusi in C++ 0x

int my_array[] = {1, 2, 3, 4, 5}; 
for(int& x : my_array) 
{ 
    cout<<x<<endl; 
} 

Se il compilatore non forniscono questo ancora, usare iteratori

for(int* it = std::begin(array); it!=std::end(array); ++it) 
{ 
    cout<<*it<<endl; 
} 

E se non è possibile utilizzare né std :: inizio/fine

for(int* it = &array[0]; it!=&array[sizeof(array)]; ++it) 
{ 
    cout<<*it<<endl; 
} 

PS Boost. Foreach emula il ciclo for-based basato su intervalli sui compilatori C++ 98

+0

Dove è definito std :: begin/end? Arriva con C++ 0x? –

+0

@Christian: Sì o con Boost. – UncleBens

+0

@Christian Sì, questa è una nuova funzionalità di C++ relativa a Range. Boost.Range include questo e molto altro, semplificando molto l'algoritmo sulle sequenze. –

11

In C++ la soluzione migliore è utilizzare un vettore std :: non un array. i vettori portano le loro dimensioni in giro con loro. Il problema con l'utilizzo di zero (o qualsiasi altro valore) come end marker è che ovviamente non può apparire altrove nell'array. Questo non è tanto un problema per le stringhe, poiché raramente vogliamo stampare il carattere con il codice zero, ma è un problema quando si usano matrici di interi.

+0

Sto bene con l'utilizzo di std :: vector qui. Una domanda generale che ho. In che modo, nei vettori, sono in grado di determinare la dimensione dell'array intero? – AKN

+0

@AKN Trasportano la dimensione intorno come un valore separato di qualche tipo. –

+0

@AKN std: vector non è solo un array, è probabilmente una struct che contiene un array e un int per la lunghezza e forse più. – phkahler

3

Si può certamente decidere sul proprio "sentinel" value da memorizzare alla fine della matrice di numeri interi. Se i tuoi numeri interi sono sempre previsti non negativi, ad esempio, puoi usare -1 come valore sentinella che segna la fine dell'array.

int myInt[] ={ 1, 2, 3, 4, 5, -1 }; 
int *myIntPtr = &myInt[0]; 
while(*myIntPtr >= 0) 
{ 
    cout<<*myIntPtr<<endl; 
    myIntPtr++; 
} 
1

Il valore di char 0 ha un significato speciale, standardizzato per convenzione e pratica. Il valore int 0 non lo è, quindi non può essere una regola generale. Se funziona nel tuo caso specifico, puoi seguirlo. Tuttavia, in generale, è meglio tenere traccia della lunghezza degli array interi separatamente, poiché questo funziona universalmente. Oppure usa std::vector o un contenitore simile che gestisce quel lavoro per te.

0

Usa std :: vector, come dice Neil.

o farlo il modo iteratore:

int myInt[] ={ 100, 200, 300, 400, 500 }; 
int *myIntPtr = &myInt[0]; 
int *myIntPtr_end = myIntPtr + 5; 
while(myIntPtr != myIntPtr_end) 
    { 
    cout<<*myIntPtr<<endl; 
    ++myIntPtr; 
    } 
+0

Qui vediamo '5' e ofcourse che è la lunghezza che possiamo usare direttamente! :) – AKN

+0

int * myIntPtr_end = myIntPtr + 5; Il puntatore * myIntPtr_end punta a SOME_JUNK_VALUE dopo l'ultimo valore. (cioè) dopo il 500. Poiché per questo difetto di progettazione, ritengo che non sia consigliabile. Cosa dire? – AKN

+0

Indipendentemente dal fatto che stia puntando alla posta indesiderata, purché non si denunci il puntatore. Per quanto riguarda la lunghezza dell'array, ovviamente è disponibile nel tuo esempio. Se stai parlando di puntatori a array senza informazioni sulla lunghezza, è qualcosa che devi aggiungere alla tua domanda/descrizione. –

3

Cosa succede ad usare sizeof? http://www.cppreference.com/wiki/keywords/sizeof

+0

Perché non esiste una cosa del genere - stai pensando a sizeof. e questo non può essere usato una volta che l'array è decaduto in un puntatore. –

+0

@Neil Butterworth grazie, era solo un caso accidentale di dislessia :) Tuttavia, non è stato detto nulla sul fatto di non essere in grado di accedere all'array. Questo può anche essere usato ulteriormente per implementare qualcosa come la classe del modello di matrice di controllo del limite. –

0
for(i=0; i < sizeof(myInt); i++) 
{ 
    cout<<*myIntPtr<<endl; 
    myIntPtr++; 
} 

Se stai suggerendo codice in cui viene manipolato myIntPtr non ha alcuna idea della dimensione del blocco a cui punta, hai a decidere per un valore magico nella propria matrice int, o ristrutturare il codice in modo che sizeof(myInt) è anche disponibile.

Le funzioni della libreria C standard utilizzano il secondo approccio: ogni volta che è necessario passare un'area del buffer tramite un puntatore, è necessario passare la sua dimensione nella stessa chiamata.

+1

Grazie kostas. Ma sizeof (myInt) non fornirà direttamente la dimensione dell'array. Quindi questo può essere cambiato in 'int nIntArrSize = sizeof (myInt)/sizeof (int)' – AKN

1

In primo luogo, non "aggiungi carattere NULL" alla fine della stringa. Non esiste una cosa come "carattere NULL". Aggiungiamo il carattere zero, che a volte viene chiamato "NUL carattere". Ma NULL non ha assolutamente nulla a che fare con questo. NULL viene normalmente utilizzato nel contesto del puntatore e non nel contesto di caratteri o interi. I tuoi confronti come *myCharPtr != NULL o *myIntPtr != NULL verranno compilati (a causa del modo in cui NULL è definito in C++), ma praticamente non ha senso. Se stai cercando un carattere zero in un array, puoi verificarlo come *myCharPtr != '\0' o come *myCharPtr != 0 o semplicemente come *myCharPtr, ma mai come *myCharPtr != NULL.

In secondo luogo, il carattere zero è chiamato carattere zero per un motivo: è uguale a zero intero. Il tipo di carattere in C++ è solo un tipo di intero semplice dopo tutto. L'unica ragione per cui possiamo usare il carattere zero come qualcosa di speciale nel contesto delle stringhe è perché il suo significato è riservato a quello scopo specifico. In generale, nel contesto intero riservare zero a tale scopo è chiaramente impossibile per ovvi motivi: zero è utile quanto qualsiasi altro valore intero. Tuttavia, se nella specifica applicazione intero zero può essere utilizzato come valore riservato, sentitevi liberi di usarlo in quel modo. Oppure puoi usare qualsiasi altro valore intero per quello scopo. Ma in generale, facendo riferimento alla domanda che si pone nel titolo, c'è in nessun modo per determinare la fine di un array. È tua responsabilità sapere dove si trova la fine (conoscendo il numero totale di elementi o segnando la fine con un valore riservato di tua scelta o in qualche altro modo). Non c'è modo di determinare la fine di un array anche con le stringhe, perché tutto quello che puoi sperare è trovare la fine della stringa , che non è necessariamente la fine dell'array che memorizza quella stringa.

Se si aggiunge esplicitamente uno zero alla fine della matrice di interi, il primo ciclo si fermerebbe felicemente. Per qualche ragione hai esplicitamente aggiunto \0 alla fine dell'array di caratteri (e il secondo ciclo si ferma), ma non hai aggiunto zero alla fine dell'array intero (e il primo ciclo non si ferma). Ti stai chiedendo perché il tuo primo ciclo non si è fermato a zero? Dunque non hai messo lo zero lì dentro. È così semplice

1

Entrambi gli standard ASCII e Unicode definiscono un carattere con valore 0 come carattere NULL, non un marcatore di fine serie/stringa. È solo la convenzione C/C++ che le stringhe vengono terminate con questo carattere. Pascal usa una notazione diversa. Inoltre, il carattere NULL non indica necessariamente la fine dell'array che contiene la stringa. Ci sono diverse funzioni API Win32 che utilizzano doppia terminazione null archi (la finestra di file aperto per uno), in questo modo:

"one\0two\0three\0" // there's an implicit '\0' appended in C/C++ 

Questo è un codice valido C/C++, il carattere NULL non significa la fine della matrice .

Per adattare questa idea di un valore NULL agli array di numeri interi significa che devi sacrificare uno dei valori interi. Se i tuoi dati sono costituiti da un sottoinsieme del set di numeri interi, questo non è un problema, ma se i tuoi dati possono essere costituiti da qualsiasi valore intero, non c'è modo di deteminare se un intero dato è il marcatore di fine array o un valore valido In quest'ultimo caso, hai bisogno di ulteriori informazioni sul numero di elementi nella matrice, manualmente o automaticamente tramite un vettore std ::.

0

Il modo generico di creare il puntatore finale per qualsiasi array è il seguente: Determinare innanzitutto il numero di elementi nell'array utilizzando sizeof(array)/sizeof(array[0]). Nota che sizeof appare due volte perché restituisce la dimensione di un oggetto in byte. Quindi per un array statico, questa è la dimensione dell'array divisa per la dimensione di un elemento nell'array. Quindi il puntatore finale su un array è array+number_of_elements. Quindi questo dovrebbe funzionare:

int myInt[]={1, 2, 3, 4, 5}; 
int myIntNumElements = sizeof(myInt)/sizeof(myInt[0]); 
int *myIntEnd = myInt + myIntNumElelents; 

for (int *myIntPtr = myInt; myInt != myIntEnd; myIntPtr++) 
    { 
    cout << *myIntPtr << endl; 
    } 

E ora per alcune avvertenze:

puntatore punta
  • alla fine per una posizione subito dopo la fine della matrice! Quindi *myIntPtr restituisce la posta indesiderata, non il valore dell'ultimo elemento nella matrice.
  • Questo va bene solo per gli array regolari e statici! Per i contenitori, utilizzare le funzioni membro e gli iteratori delle funzioni begin e end.
  • Questo approccio funziona con qualsiasi versione di C++. Tuttavia, se si utilizza C++ - 11 o successivo, si consiglia di utilizzare le funzioni std::begin e std::end in per economico come segue:

    for (int *myIntPtr = std::begin(myInt); myIntPtr != std::end(myIntPtr); myIntPtr++)

  • Questo metodo è destinato ad essere considerato in aggiunta al altre risposte Qual è il migliore è una questione di contesto.

Problemi correlati