2010-01-26 19 views
9

OK, sto cercando di ottenere un sotto array da un array esistente e non sono sicuro di come farlo. Nel mio esempio ho un array molto grande, ma voglio creare un array dagli ultimi 5 elementi dell'array.Qual è il modo migliore per creare un sub array da una matrice esistente in C++?

Un esempio di che cosa sto parlando sarebbe:

int array1 = {1,2,3,...99,100}; 
int array2[5] = array1+95; 

So che questo non è corretto, ma sto avendo qualche difficoltà a ottenere nel modo giusto. Voglio ottenere gli elementi da 96 a 100 in array1 e metterli in array2 ma non voglio copiare gli array. Voglio solo array2 per iniziare all'elemento 96 in modo tale che array1 [96] e array2 [0] puntino alla stessa posizione.

+0

Tenete a mente non sarà tecnicamente essere fare un sub-array da punta a un elemento. – GManNickG

+0

Il 96 ° elemento di 'array1' è' array1 [95] '. Quando dici "mettili in array2", significa * copiando, in che altro modo li metterai in array2? Non c'è modo di fare quello che vuoi. È necessario copiare gli elementi o disporre di un puntatore che punta al 96 ° elemento di 'array1', oppure disporre di una matrice di 5 puntatori e fare in modo che il puntatore' i' punti all'elemento '95 + i' di' array1 '. –

+0

hai ragione, "mettendo loro array2" non intendevo copiare. Mi dispiace per la confusione terminologica. –

risposta

18

per questo:

"such that array1[96] and array2[0] would be pointing to the same location." 

si può fare:

int *arr2 = arr1 + 96; 
assert(arr2[0] == arr1[96] == 97); 
+3

Questo 'assert' dovrebbe essere un matematico che asserisce, non C :-) –

+0

questo funziona! Grazie! –

+1

+1 per la soluzione semplice che funziona. –

0

Hai detto che non si desidera copiare l'array, ma ottenere un puntatore agli ultimi cinque elementi. È quasi avuta:

int array1[] = {1,2,3,...99,100}; 
int* array2 = &array1[95]; 
+0

quando ho provato che ho ricevuto questo errore: non può convertire da 'int *' a 'int []' –

+1

'int array2 [] = array1 + 95;' è illegale. –

+0

Dovrebbe essere int array1 [] = {1,2,3, ... 99,100}; int * array2 = array1 + 95; Non è possibile inizializzare una matrice (parentesi quadre) con un puntatore: può indicare dove inizia ma non le sue dimensioni. – BenG

1

In C++ è possibile utilizzare un puntatore a int come un array int, in modo da ottenere l'array2 per iniziare al punto 96 in array1 è facile, ma non c'è alcun modo per dare array2 un limite di dimensione, in modo da poter fare questo

int array2 [] = & array1 [96];

o questo

int *array2 = &array1[96]; 

ma non questa

int array2[5] = &array1[96]; // this doesn't work. 

D'altra parte, C++ non impone limiti di dimensione dell'array comunque, quindi l'unica perdita reale è che si puo' t usa sizeof per ottenere il numero di elementi in array2.

nota: &array1[96] è la stessa cosa di array+96

edit: Correzione - int array[] = &array[96] non è valido, è possibile utilizzare solo [] come sinonimo di * quando si dichiara una lista di parametri di funzione.

quindi questo è consentito

extern int foo(int array2[]); 
foo (&array1[96]); 
+0

Ricevo ancora un errore quando provo a digitare: int array2 [] = & array1 [96].L'errore che ricevo è: impossibile convertire da 'int *' a 'int []' –

+0

@John: 'int array2 [] = & array1 [96];' non è corretto. –

+0

Sì, 'int foo []' e 'int * foo' sono intercambiabili solo come parametri di funzione. – jamesdlin

0
int array1[] = {1,2,3,...99,100}; 
int *array2 = &array1[96]; 
0
int arr[] = { 1, 2, 3, 4, 5}; 
int arr1[2]; 
copy(arr + 3, arr + 5, arr1); 
for(int i = 0; i < 2; i++) 
    cout << arr1[i] << endl; 

Il codice non è sicuro se i confini non sono gestite correttamente.

8

Un hack di riferimento da un programmatore C disposti a sovvertire il sistema di tipi per ottenere quello che funziona:

int (&array2)[5] = (int (&)[5])(*(array1 + 5)); 

Ora array2 sarà un array per tutti gli effetti, e sarà un sub-array di array1 e sarà persino passabile a quella famosa funzione modello C++ array_size. Anche se il modo migliore per gestire questo hackery è quello di nasconderlo con più hacker!

#define make_sub_array(type, arr, off, len) (type (&)[len])(*(arr + off)); 

int (&array2)[5] = make_sub_array(int, array1, 5, 5); 

Nice. Terribile secondo alcuni standard, ma il risultato finale a) sembra piuttosto accurato, b) fa esattamente quello che vuoi, c) è funzionalmente identico a un array reale, e d) avrà anche il bonus (o caratteristica errata) di essere un riferimento identico all'originale, quindi i due cambiano insieme.

UPDATE: Se si preferisce, una versione su modelli (o quasi):

template <typename T, size_t M> 
T (&_make_sub_array(T (&orig)[M], size_t o))[] 
{ 
    return (T (&)[])(*(orig + o)); 
} 
#define make_sub_array(type, array, n, o) (type (&)[n])_make_sub_array(array, o) 

int (&array2)[5] = make_sub_array(int, array1, 5, 5); 

Dobbiamo ancora passare il tipo. Poiché uno dei nostri argomenti deve essere usato come parte del cast, non possiamo pulire (IMHO) evitando la macro. Si potrebbe fare questo:

template <typename T, size_t M, size_t N> 
T (&make_sub_array(T (&orig)[M], size_t o))[N] 
{ 
    return (T (&)[N])(*(orig + o)); 
} 

int (&array2)[5] = make_sub_array<int, 15, 5>(array1, 5); 

Ma l'obiettivo è quello di rendere il codice chiamante più pulito possibile, e quella chiamata è un po 'pelosa. La versione pure-macro ha probabilmente il minor overhead ed è probabilmente la più pulita da implementare in questo caso.

+1

È così brutto che va bene :-). +1. –

+0

Grazie. Mi ci è voluto molto più tempo perché volevo farlo funzionare con il cast effettivo del C++, ma alla fine ho rinunciato e l'ho realizzato _work_. Miglioramenti (specialmente una versione potenziale di 'make_sub_array' come funzione di template - l'ho provato per un po 'prima di rinunciare) benvenuto. –

+0

@Chris: My C++ - fu non è grande, sono più una persona C, ma ci proverò! –

3

Per un approccio completamente diverso si potrebbe fare qualcosa di simile.

vector<int> v0(array1 + 95, array1 + 100); 

o

vector<int> v1(array1, array1 + 100); 
vector<int> v2(v1.begin() + 95, v1.end()); 

Questo sarebbe un vero e proprio copia degli elementi del vostro vettore.

+0

Dovrebbe essere 'std :: vector 'per la pendantry. Ad ogni modo, +1 per la risposta più "C++". –

3

È possibile utilizzare boost::iterator_range per rappresentare "fette" di array/contenitori:

#include <iostream> 
#include <boost/range.hpp> 

int main() 
{ 
    int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 

    // Create a "proxy" of array[5..7] 
    // The range implements the concept of a random sequence containter 
    boost::iterator_range<int*> subarray(&array[5], &array[7]+1); 

    // Output: 3 elements: 5 6 7 
    std::cout << subarray.size() << " elements: " 
       << subarray[0] << " " 
       << subarray[1] << " " 
       << subarray[2] << "\n"; 
} 

nota che la gamma iteratore "sa" circa le dimensioni del sub-array. Farà anche i controlli per te. Non è possibile ottenere tale funzionalità da un semplice puntatore.

L'utilità di Boost.Range diventerà più evidente una volta che si impara a conoscere contenitori STL e iteratori.

Se siete in algebra lineare, Boost.uBlas supporta gli intervalli e le fette per le sue matrici e vettori.

Problemi correlati