2009-06-28 8 views
7

Piszę mały program w języku C, aby wykonać kilka operacji na liczbach i musi on ominąć tablice między funkcjami. Funkcje powinny akceptować i zwracać wskaźniki, prawda?Czy wskaźniki i tablice są różne w C?

Na przykład, (wiem, że to nie może być najbardziej efektywne rzecz):

int* reverse(int* l, int len) { 
    int* reversed = malloc(sizeof(*reversed)*len); 
    int i, j; 
    for (i = 0, j = len-1; i < len; i++, j--) { 
     reversed[j] = l[i]; 
    } 
    return reversed; 
} 

używam wskazówek prawda?

+1

Twój przykład wygląda w porządku. Szerszy temat różnicy między tablicami i wskaźnikami został już wcześniej omawiany, na przykład na stronie http://stackoverflow.com/questions/660752/pointer-vs-array-in-c-non-trivial-difference. –

+0

(To nie kwalifikuje się jako odpowiedź) Tablica i algebra wskaźnik różnią się tylko w tym sizeof (nazwa_elementu) zwraca liczbę elementów nazwa_tabeli, a nie rozmiar tablicy w bajtach. – jpinto3912

Odpowiedz

14

fragmencie kodu jest poprawna. Jednak wskaźniki i tablice w C są rzeczywiście różne. Mówiąc prosto "wskaźnik do typu T" nie jest taki sam jak "tablica typu T".

Proszę spojrzeć na C Faq omawiając tablice Wskaźniki &, aby lepiej to zrozumieć.

+2

Wznowienie dla C Faq - bardziej szczegółowe niż odpowiedź wejdzie na SO. –

+1

+1 dla C FAQ –

1

Z perspektywy niskiego poziomu, tablica jest ciągłym fragmentem pamięci, do którego dostęp ma adres początku tego fragmentu i przesunięcia, a więc od tego poziomu abstrakcji jest wskaźnikiem. Jednak z perspektywy języka C typ tablicy różni się od typu wskaźnika. Zasadniczo tablica może być przypisana do wartości wskaźnika, ale to nie ten sam typ, co.

Dla celów twojej funkcji, robisz OK.

+3

Twoje odważne oświadczenie prosi o wyjaśnienie. –

+0

nevermind, Crashworks wyjaśnił to już –

0

tablice w C są reprezentowane i manipulowane przez wskaźnik do pierwszego elementu, np.

int arr[50]; 
int * ptr1 = arr; 
int * ptr2 = &arr[0]; 

w tym przykładzie, PTR1 == PTR2 ponieważ adres pierwszego elementu tablicy, a wskaźnik bazowy tablicy jest taka sama.

więc podstawowym przykładem jest poprawne, choć podejrzewam, że malloc powinien prawdopodobnie:

int* reversed = malloc(sizeof(int)*len); 

+0

To na wszelki wypadek chcę go zmienić na coś innego (np. 'Long'), więc nie będę musiał zmieniać dwóch rzeczy. – Javier

+1

Nie, jego malloc jest w porządku (i lepiej od twojego) od C99. – smcameron

+0

@ [smcameron]: @reyjavikvi]: ciekawa technika (nie zauważyłem przedrostka * po raz pierwszy, przepraszam za to!). Nauczyłem się C w 1982 roku i nie używałem go zbytnio od 1994 roku, więc nigdy nie czytałem specyfikacji C99 (musiałem przegapić notatkę na ten temat ;-)) –

1

W teorii pedantycznej tablice i wskaźniki są różnymi rzeczami, ponieważ tablica określa region pamięci i dlatego rozmiar tablicy jest częścią tego typu. Tak więc jeden mówi, że nazwa tablicy rozpada się na wskaźnik, gdy jest używany w tym kontekście. There's a detailed explanation in the C-FAQ.

W praktyce są takie same, ponieważ formalnie a[i] to to samo, co *(a+i), dlatego też back-end kompilatora traktuje nazwę tablicy i wskaźnik dokładnie w ten sam sposób. Jedyna różnica, na którą warto się martwić, to fakt, że fragment kodu jest w porządku. Po prostu pamiętaj, aby zwolnić pamięć, że twoja funkcja jest zgodna z tym, kto ją nazywa.

2

Łącze do C-FAQ: Tablice i wskaźniki zostały już podane, ale istnieje również dokładne wyjaśnienie w C for Smarties: Arrays and Pointers. Możesz najpierw przeczytać stronę "Wyrażenia analityczne".

Kilka rzeczy o swoim przykładzie, które powinny zostać poprawione:

  1. Korzystanie int zamiast prawidłowej size_t do przechowywania rozmiary obiektu.
  2. Nie można sprawdzić wartości zwracanej malloc().

Jednym ze sposobów, aby „naprawić” ten drugi problem to niech rozmówca zdecydować, gdzie przechowywany jest wyjście (chyba rozmówca nie chce lub potrzebuje świeżo przydzielona tablicę):

int *reverse(int *out, int *l, size_t len) { 
    size_t i, j; 
    for (i = 0, j = len - 1; i < len; ++i, --j) { 
    out[j] = l[i]; 
    } 
    return out; 
}