2010-01-26 13 views
9

OK, próbuję uzyskać tablicę podrzędną z istniejącej tablicy i po prostu nie jestem pewien, jak to zrobić. W moim przykładzie mam bardzo dużą tablicę, ale chcę utworzyć tablicę z ostatnich 5 elementów tablicy.Jaki jest najlepszy sposób utworzenia tablicy podrzędnej z istniejącej tablicy w C++?

Przykładem tego, co mówię byłoby:

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

wiem, że to nie jest poprawne, ale mam pewne problemy z dostaniem go w prawo. Chcę uzyskać elementy od 96 do 100 w tablicy 1 i umieścić je w tablicy2, ale nie chcę kopiować tablic. Chcę tylko, aby tablica 2 zaczynała się od elementu 96, tak aby array1 [96] i array2 [0] wskazywałyby tę samą lokalizację.

+0

Należy pamiętać, że technicznie nie tworzy się podszablonu, wskazując na element. – GManNickG

+0

96. elementem 'tablica1' jest' tablica1 [95] '. Kiedy mówisz "umieść je w tablicy2", oznacza to * kopiowanie, jak inaczej umieścisz je w tablicy 2? Nie ma sposobu, aby zrobić to, co chcesz. Musisz albo skopiować elementy, albo mieć wskaźnik wskazujący na 96. element tablicy 'tablica1' lub tablicę 5 wskaźników, a wskaźnik" i "wskazywać na element' 95 + i' z 'tablica1 '. –

+0

masz rację, przez "umieszczenie ich array2" nie chciałem kopiować. Przykro mi z powodu pomieszania terminologii. –

Odpowiedz

18

na to:

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

można zrobić:

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

Że 'asert' powinien być matematykiem twierdząc, nie C :-) –

+0

to działa! Dziękuję Ci! –

+1

+1 za proste rozwiązanie, które działa. –

0

Powiedziałeś, że nie chcesz, aby skopiować tablicę, ale uzyskać wskaźnik do ostatnich pięciu elementów. Prawie miałem go:

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

kiedy próbowałem, że mam ten błąd: nie można przekonwertować z 'int *' na 'int []' –

+1

'int array2 [] = array1 + 95;' jest nielegalne. –

+0

Powinien być int array1 [] = {1,2,3, ... 99,100}; int * array2 = tablica1 + 95; Nie można zainicjować tablicy (nawiasów kwadratowych) za pomocą wskaźnika - może ona określić, gdzie zaczyna, ale nie określa jej rozmiaru. – BenG

1

W C++ można użyć int wskaźnik jako int tablicy, więc coraz tablica2 rozpocząć się na pozycji 96 w tablica1 jest łatwe, ale nie jest jakiś sposób, aby dać tablica2 ograniczenie wielkości, to można to zrobić

int tablica2 [] = & array1 [96];

czy to

int *array2 = &array1[96]; 

ale nie tym

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

Z drugiej strony, C++ nie wymusza limity rozmiaru tablicy tak, więc jedyna prawdziwa strata jest to, że można” t użyj sizeof, aby uzyskać liczbę elementów w array2.

uwaga: &array1[96] to samo, co array+96

EDIT: korekta - int array[] = &array[96] nie jest prawidłowy, można użyć tylko [] jako synonim * podczas deklarowania listę parametrów funkcji.

więc jest to dozwolone

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

Ciągle pojawia się błąd, gdy próbuję wpisać: int array2 [] = i array1 [96].Błąd, który otrzymuję: nie można przekonwertować z 'int *' na 'int []' –

+0

@John: 'int array2 [] = & array1 [96];' jest zły. –

+0

Tak, 'int foo []' i 'int * foo' są wymienne tylko jako parametry funkcji. – 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; 

Kod nie jest bezpieczne, jeśli granice nie są prawidłowo obsługiwane.

8

hack referencyjny programista C chcących obalić system typu, aby uzyskać to działa:

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

Teraz array2 będzie tablica dla wszystkich zamiarów i celów, i będzie sub-tablicę array1 , a nawet będzie znośna dla tej znanej funkcji szablonu C++ array_size. Chociaż najlepszym sposobem na poradzenie sobie z tym hackery jest ukryć go z więcej hackery!

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

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

Nice. Okropne według niektórych standardów, ale wynik końcowy a) wygląda całkiem zgrabnie, b) robi dokładnie to, czego oczekujesz, c) jest funkcjonalnie identyczny z rzeczywistą tablicą, i d) będzie również miał dodatkową premię (lub niewłaściwą funkcję) bycia identyczne odniesienie do oryginału, więc dwie zmiany razem.

UPDATE: Jeśli wolisz, wersja matrycy (rodzaj):

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); 

Mamy jeszcze przekazać typ. Ponieważ jeden z naszych argumentów musi być użyty jako część obsady, nie możemy w czysty sposób (IMHO) unikać tego makra. Moglibyśmy to zrobić:

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); 

Jednak celem jest uczynienie kodu wywołującego możliwie najczystszym, a połączenie jest nieco owłosione. Wersja czysto makro ma prawdopodobnie najmniejszy narzut i prawdopodobnie jest najczystsza w tym przypadku.

+1

Jest tak źle, że to dobrze :-). +1. –

+0

Dzięki. Zajęło mi to znacznie dłużej, ponieważ chciałem, aby działało z rzeczywistym castingiem w C++, ale w końcu dałem za wygraną i zrobiłem _work_. Ulepszenia (szczególnie potencjalna wersja 'make_sub_array' jako funkcja szablonu - próbowałem tego przez jakiś czas, zanim się poddałem) powitanie. –

+0

@ Chris: Mój C++ - fu nie jest wspaniały, jestem bardziej osobą C, ale spróbuję! –

3

Dla zupełnie innego podejścia można zrobić coś takiego.

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

lub

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

Pozwoliłoby prawdziwą kopię elementów swojej wektorze.

+0

Powinien być 'std :: vector 'dla zawieszki. W każdym razie +1 dla najbardziej "C++" odpowiedzi. –

3

Można użyć boost::iterator_range do reprezentowania „plastry” tablic/pojemnikach:

#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"; 
} 

Należy pamiętać, że zakres iterator „wie” o wielkości sub-macierzy. Sprawdza nawet dla ciebie granice. Nie można uzyskać tej funkcji za pomocą prostego wskaźnika.

Przydatność Boost.Range stanie się bardziej widoczna, gdy dowiesz się o kontenerach i iteratorach STL.

W przypadku algebry liniowej, Boost.uBlas obsługuje zakresy i przekroje dla swoich macierzy i wektorów.

Powiązane problemy