2015-12-13 14 views
12

Do tej pory uważałem, że jest, ale po tym, jak dowiedziałem się, że kompilator może podkładać dane, aby dostosować je do wymagań architektury, na przykład mam wątpliwości. Więc zastanawiam się, czy char[4][3] ma taki sam układ pamięci, jak char[12]. Czy kompilator może wstawić dopełnienie po części char[3], aby dopasować ją tak, aby cała macierz zajęła 16 bajtów?Czy jest zagwarantowane, że typ T [x] [y] ma taki sam układ pamięci co T [x * y] w C?

Historia tła, która funkcja biblioteki pobiera kilka ciągów o stałej długości w parametrze char*, więc oczekuje ciągłego bufora bez paddig, a długość łańcucha może być nieparzysta. Tak więc pomyślałem, że deklaruję tablicę char[N_STRINGS][STRING_LENGTH], a następnie wygodnie zapełniam ją i przekazuję do funkcji, przesyłając ją do char*. Jak dotąd wydaje się, że działa. Ale nie jestem pewien, czy to rozwiązanie jest przenośne.

+4

Tablica jest przydzielana w sposób ciągły. Między elementami tablicy IMHO nie może być żadnego dopełnienia. – ameyCU

+4

Macierze C muszą być przylegające, bez dopełnień między elementami tablicy. Zatem ani 'char [4] [3]', ani 'char [12]' może zawierać dopełnienie, a 'sizeof' będzie mieć rozmiar" 12 * sizeof (char) "dla obu. –

+3

Zobacz również [Czy tablice C mogą zawierać dopełnienie między elementami?] (Http://stackoverflow.com/questions/1066681/can-c-arrays-contain-padding-in-between-elements) –

Odpowiedz

3

To, co określasz jako typy, nie jest typem. Typ T, o którym wspomniałeś w tytule, to (w tym przypadku) wskaźnik do znaku.

Masz rację, jeśli chodzi o struktury, wyrównanie jest czynnikiem, który może prowadzić do dodawania padding, co może oznaczać, że twoja struktura zajmuje więcej bajtów niż na pierwszy rzut oka.

Po przypisaniu tablicy tablica będzie ciągła w pamięci. Pamiętaj, że po indeksowaniu w tablicy array[3] jest odpowiednikiem *(array + 3).

Na przykład następujący program powinien wydrukować 12:

#include <stdio.h> 

int main() { 
    char array[4][3]; 
    printf("%zu", sizeof(array)); 
    return 0; 
} 
+1

Tablice są * zawsze * ciągłe w pamięci, to cała idea. –

+3

'T' w tytule jest typem, a nie zmienną. Reszta pytania używa 'char' dla' T'. – interjay

+0

@ jens Dobra uwaga, moje użycie "statycznie" było niepotrzebne i bardziej prawdopodobne, że wprowadzi czytelnika w nieistniejącą dychotomię. – fvgs

-4

Ściśle mówiąc układ 2-D jest szereg odnośników do tablic 1-D. Ogólnie nie można zakładać więcej.

wziąłbym pogląd, że jeśli chcesz sąsiedni blok dowolnego typu następnie zadeklarować sąsiedniego bloku 1D, zamiast nadzieją dla danego układu z kompilator lub starcie.

Teraz prawdopodobnie kompilator przydzieli ciągły blok dla tablicy 2-D, gdy z góry zna wymiary (tj. Są one stałe w czasie kompilacji), ale nie jest to ścisła interpretacja.

Pamiętaj int main(int argc, char **argv) ;

To char **argv jest tablicą wskaźników do char wskaźniki.

W bardziej ogólnym programowaniu można np. malloc() każdy wiersz w tablicy 2D osobno, a zamiana wiersza jest tak prosta jak zamiana wartości na te wskaźniki. Na przykład:

char **array = NULL ; 

array = malloc(2 * sizeof(char *)) ; 

array[0] = malloc(24) ; 

array[1] = malloc(11) ; 

strcpy(array[0], "first") ; 
strcpy(array[1], "second") ; 

printf("%s\n%s\n", array[0], array[1]) ; 

/* swap the rows */ 

char *t = array[0] ; 
array[0] = array[1] ; 
array[1] = t ; 

printf("%s\n%s\n", array[0], array[1]) ; 

free(array[0]) ; 
free(array[1]) ; 
free(array) ; 
+0

Biorąc pod uwagę naturę pytania, należy zauważyć, że tablica znaków podana przez 'tablica [0]' nie jestsiaduje z tablicą znaków podaną przez 'tablica [1]'. Co więcej, nie zaleca się dynamicznego przydzielania tablic, jeśli można je alokować statycznie. – fvgs

+8

"_Struktowo mówiąc tablica 2-D to tablica wskaźników do tablic 1-D." Nie, nie jest! Tablice _ ** nie są ** _ wskaźnikami. – edmz

+3

Nie należy promować pseudo 2D tablic, czyli wskaźników do wskaźników. Jest to bardzo nie w porządku i powinno zostać wyrzucone ze wszystkich książek i kursów wprowadzających. –

10

Tablica M elementów typu A zawiera wszystkie elementy w sąsiadujących pozycjach w pamięci, w ogóle bez marginesów dopełnienia. Ten fakt nie jest zależny od charakteru A.

Teraz, jeśli A jest typem "tablicy N elementów posiadających typ T", to każdy element w tablicy typu T będzie miał ponownie N sąsiadujących pozycji w pamięci. Wszystkie te bloki N obiektów typu T są również przechowywane w sąsiadujących pozycjach.

Rezultatem jest istnienie w pamięci elementów M * N typu T, przechowywanych w sąsiadujących pozycjach.

Element [i][j] tablicy jest przechowywany w pozycji i*N+j.

8

Rozważmy

T array[size]; 
array[0]; // 1 

1 jest formalnie zdefiniowany jako:

Definicja operatora indeksem [] jest to, że E1[E2] jest identyczne (*((E1)+(E2)))

per § 6.5 .2.1, zdanie 2 zaczerpnięte ze standardowego szkicu C N1570. Po nałożeniu na tablicach wielowymiarowych «Układ której elementy są układy», mamy:

Jeżeli E oznacza macierz N-wymiarowa (n ≥ 2) o wymiarach i × j × ... × k, wtedy E (stosowany jako niebędąca lwartość) przekształca się wskaźnik do (n - 1) Macierz wymiarowej o wymiarach j × . . . × k.

związku z tym, biorąc pod uwagę E = T array[i][j] i S = array[i][j], S najpierw przekształca się wskaźnik do jednowymiarowej tablicy rozmiaru j, a mianowicie T (*ptr)[j] = &array[i].

Jeżeli jednoargumentowy * operatora jest stosowane do tego wskaźnika jawnie lub niejawnie wyniku indeksowanie wynik jest odnośny (n - 1) Macierz wymiarową, który z kolei jest przekształcony do wskaźnika, jeśli jest używany jako inny niż l-wartość.

i ta reguła ma zastosowanie rekursywnie. Możemy wnioskować, że aby to zrobić, tablica n-dimensional musi być przydzielona w sposób ciągły.

Wynika z tego, że tablice są zapisywane w rzędach, głównym celem (ostatni dolny zmienia najszybciej).

pod względem układu logicznego.

Ponieważ char [12] musi być przechowywany w sposób ciągły, tak samo jak w przypadku char [3][4], a ponieważ mają one takie samo wyrównanie, powinny być zgodne, mimo że są to technicznie różne typy.

+1

Punktem centralnym moich wątpliwości jest: Czy implementacje są bezpłatne dla pad * końca * tablica do zaokrąglenia do wyrównania? Jeśli odpowiedź brzmi tak, to mogę sobie wyobrazić, że 'sizeof (char [3]) == 4' na wyrównanym do słowa procesorze, co ułatwia adresowanie elementów tablicy' char [4] [3] '. Oznacza to, że podparki zawierają implied padding, a jeśli użyjesz 'char [12]' implementacja jest wymagana do spakowania danych bez dopełnienia. – Calmarius

+0

Jeśli mówimy o wyrównaniu, "_Alignof (char [N])" będzie "_Alignof (char)", który jest 1. Od 'sizeof (char [3]) == 3', będziesz musiał przemyśleć ponownie pytania, ponieważ punkt wyjścia jest niepoprawny. – edmz

+0

@black: Dano 'struct x {char arr [3] [4]; }; struct y {char arr [4] [3]; }; 'czy standard gwarantuje, że' _Alignof (struct x) 'i' _Alignof (struct y) 'będą równe? – supercat

Powiązane problemy