Jestem stosunkowo nowy w C i potrzebuję pomocy w metodach radzenia sobie z tablicami. Pochodząc z programowania w Javie, jestem przyzwyczajony do mówienia int [] method()
w celu zwrócenia tablicy. Jednak odkryłem, że w C musisz używać wskaźników do tablic, kiedy je zwracasz. Będąc nowym programistą, naprawdę w ogóle tego nie rozumiem, nawet z wieloma forami, które przeglądałem.
Zasadniczo próbuję napisać metodę, która zwraca tablicę char w C. Dostarczę metodę (nazwijmy ją returnArray) z tablicą. Utworzy nową tablicę z poprzedniej tablicy i zwróci do niej wskaźnik. Potrzebuję tylko pomocy, jak to rozpocząć i jak odczytać wskaźnik po wysłaniu go z tablicy. Każda pomoc w wyjaśnieniu tego jest mile widziana.
Proponowany format kodu dla funkcji zwracającej tablicę
char *returnArray(char array []){
char returned [10];
//methods to pull values from array, interpret them, and then create new array
return &(returned[0]); //is this correct?
}
Wzywający funkcji
int main(){
int i=0;
char array []={1,0,0,0,0,1,1};
char arrayCount=0;
char* returnedArray = returnArray(&arrayCount); ///is this correct?
for (i=0; i<10;i++)
printf(%d, ",", returnedArray[i]); //is this correctly formatted?
}
Nie testowałem tego jeszcze, ponieważ mój kompilator C w tej chwili nie działa, ale chciałbym to rozgryźć
Odpowiedzi:
Nie możesz zwracać tablic z funkcji w C. Nie możesz (nie powinieneś) tego robić:
returned
jest tworzony z automatycznym czasem przechowywania i odniesienia do niego staną się nieważne, gdy opuści swój zakres deklarowania, tj. gdy funkcja powróci.Będziesz musiał dynamicznie przydzielać pamięć wewnątrz funkcji lub wypełnić wstępnie przydzielony bufor dostarczony przez wywołującego.
Opcja 1:
dynamicznie alokować pamięć wewnątrz funkcji (wywołujący odpowiedzialny za zwalnianie
ret
)Nazwij to tak:
Opcja 2:
wypełnij wstępnie przydzielony bufor dostarczony przez dzwoniącego (dzwoniący przydziela
buf
i przekazuje do funkcji)I nazwij to tak:
źródło
Sposób traktowania tablic w języku C bardzo różni się od sposobu traktowania w Javie i będziesz musiał odpowiednio dostosować swoje myślenie. Tablice w języku C nie są obiektami pierwszej klasy (to znaczy, że wyrażenie tablicowe nie zachowuje swojej „macierzy” w większości kontekstów). W języku C wyrażenie typu „tablica elementów N
T
” zostanie niejawnie przekonwertowane („rozpad”) na wyrażenie typu „wskaźnik doT
”, z wyjątkiem sytuacji, gdy wyrażenie tablicowe jest operandemsizeof
jednoargumentowym lub&
operatorów lub, lub jeśli wyrażenie tablicowe to literał łańcuchowy używany do inicjalizacji innej tablicy w deklaracji.Oznacza to między innymi, że nie można przekazać wyrażenia tablicowego do funkcji i odebrać je jako typ tablicowy ; funkcja faktycznie otrzymuje typ wskaźnika:
W wywołaniu do
foo
wyrażeniestr
jest konwertowane z typuchar [6]
nachar *
, dlatego zamiast parametrufoo
deklarowany jest pierwszy parametr . W , ponieważ wyrażenie tablicowe jest operandem operatora, nie jest konwertowane na typ wskaźnikowy, więc otrzymujesz liczbę bajtów w tablicy (6).char *a
char a[6]
sizeof str
sizeof
Jeśli jesteś naprawdę zainteresowany, możesz przeczytać książkę Dennisa Ritchiego The Development of the C Language, aby zrozumieć, skąd pochodzi ta terapia.
W rezultacie funkcje nie mogą zwracać typów tablicowych, co jest w porządku, ponieważ wyrażenia tablicowe również nie mogą być celem przypisania.
Najbezpieczniejszą metodą jest zdefiniowanie przez wywołującego tablicy i przekazanie jej adresu i rozmiaru do funkcji, która ma do niej pisać:
Inną metodą jest dynamiczne przydzielanie tablicy przez funkcję i zwracanie wskaźnika i rozmiaru:
W tym przypadku wywołujący jest odpowiedzialny za zwolnienie tablicy za pomocą
free
funkcji bibliotecznej.Zauważ, że
dst
w powyższym kodzie jest prosty wskaźnik dochar
, a nie wskaźnik do tablicychar
. Wskaźnik C i semantyka tablicy są takie, że można zastosować operator indeksu dolnego[]
do wyrażenia typu tablicowego lub typu wskaźnika; obasrc[i]
idst[i]
uzyskają dostęp doi
'-tego elementu tablicy (nawet jeślisrc
ma tylko typ tablicy).Państwo może zadeklarować wskaźnik do tablicy N-pierwiastkowej
T
i zrobić coś podobnego:Kilka wad z powyższym. Po pierwsze, starsze wersje języka C oczekują,
SOME_SIZE
że będzie to stała czasu kompilacji, co oznacza, że funkcja będzie działać zawsze tylko z jednym rozmiarem tablicy. Po drugie, przed zastosowaniem indeksu dolnego należy usunąć odwołanie ze wskaźnika, który zaśmieca kod. Wskaźniki do tablic działają lepiej, gdy masz do czynienia z tablicami wielowymiarowymi.źródło
bar
wskaźnik, a nie tablicę. W kontekście deklaracji parametru funkcjiT a[N]
iT a[]
oba są traktowane jakoT *a
.void returnArray(const char *srcArray, size_t srcSize, char *dstArray, char dstSize)
ostatni parametr powinien byćsize_t
typu notchar
.Nie twierdzę, że jest to najlepsze lub preferowane rozwiązanie danego problemu. Warto jednak pamiętać, że funkcje mogą zwracać struktury. Chociaż funkcje nie mogą zwracać tablic, tablice mogą być opakowane w struktury, a funkcja może zwrócić strukturę, przenosząc w ten sposób tablicę. Działa to w przypadku tablic o stałej długości.
Zapraszam do komentowania mocnych i słabych stron tej techniki. Nie pofatygowałem się, żeby to zrobić.
źródło
CHAR_ARRAY returned
na stercie? Z pewnością nie może być na stosie (w ramce stosu poreturnArray()
prawej?A co z tą cudownie złą implementacją?
tablica.h
main.c
źródło
struct
jako kontenera / obiektu tablicy. Pomyśl o tym jak o std :: vector w C ++. Preprocesor rozszerzyłbyint
wersję tego dostruct intArray { int* contents; int size; };
.W twoim przypadku tworzysz tablicę na stosie i gdy opuścisz zakres funkcji, tablica zostanie cofnięta. Zamiast tego utwórz tablicę alokowaną dynamicznie i zwróć do niej wskaźnik.
źródło
new
operatora w C. To jest C ++.sizeof(char)
na pewno1
tak będzie , więc w tym przypadku możesz upuścić ten kawałekmalloc
.&arr
. Chceszarr
być achar *
, i przekaż to w użyciuarr
.Możesz to zrobić używając pamięci sterty (poprzez wywołanie malloc () ), tak jak inne podane tutaj odpowiedzi, ale zawsze musisz zarządzać pamięcią (użyj funkcji free () za każdym razem, gdy wywołujesz swoją funkcję). Możesz to również zrobić za pomocą tablicy statycznej:
Możesz go używać bez martwienia się o zarządzanie pamięcią.
W tym przykładzie należy użyć słowa kluczowego static w definicji tablicy, aby ustawić okres istnienia tablicy na długość aplikacji, aby nie został zniszczony po instrukcji return. Oczywiście w ten sposób zajmujesz SIZE bajtów w swojej pamięci przez cały okres użytkowania aplikacji, więc odpowiednio ją dopasuj!
źródło
Twoja metoda zwróci lokalną zmienną stosu, która zakończy się poważnym niepowodzeniem. Aby zwrócić tablicę, utwórz tablicę poza funkcją, przekaż ją przez adres do funkcji, a następnie zmodyfikuj ją lub utwórz tablicę na stercie i zwróć tę zmienną. Oba będą działać, ale pierwsza nie wymaga żadnej dynamicznej alokacji pamięci, aby działała poprawnie.
źródło
Możesz użyć takiego kodu:
Kiedy to zrobisz, pamięć powinna zostać później zwolniona, przekazując adres do zwolnienia.
Istnieją inne opcje. Procedura może zwrócić wskaźnik do tablicy (lub części tablicy), która jest częścią jakiejś istniejącej struktury. Obiekt wywołujący może przekazać tablicę, a procedura po prostu zapisuje do tablicy, zamiast przydzielać miejsce na nową tablicę.
źródło