2014-06-30 17 views
5

Witam Jestem nowy na tej stronie i potrzebuję pomocy w zrozumieniu, co byłoby uważane za "normę" podczas kodowania struktur w C, które wymagają ciągów znaków. W zasadzie zastanawiam się, które z poniższych sposobów byłoby uznane za „standard przemysłowy” podczas korzystania struktur w C, aby śledzić wszystkie wymagania dotyczące pamięci struktura wymaga:Jak powinienem zadeklarować ciągi w strukturach C?

1) stały rozmiar wyrażenie:

typedef struct 
{ 
    int damage; 
    char name[40]; 
} Item; 

mogę teraz dostać rozmiar korzystając sizeof(Item)

2) tablicy znaków Pointer

typedef struct 
{ 
    int damage; 
    char *name; 
} Item; 

wiem, że mogę przechowywać rozmiar name przy użyciu drugiej zmiennej, ale czy istnieje inny sposób?

i) istnieje inna zaleta pomocą stałego rozmiaru (1)

char name[40]; 

porównaniu następujący sposób i stosując wskaźnik do tablicy Char (2)?

char *name; 

A jeśli tak, jaka jest korzyść?

ii) Czy ciąg znaków za pomocą wskaźnika do tablicy znaków (2) zostanie zapisany sekwencyjnie i natychmiast po strukturze (bezpośrednio za wskaźnikiem do łańcucha) lub czy będzie przechowywany w innym miejscu w pamięci?

iii) Chciałabym wiedzieć, w jaki sposób można znaleźć długość zmiennej char * smyczkową (bez użycia size_t lub wartość całkowitą do przechowywania długości)

+0

Dlaczego to oznaczono jako C++? – Rapptz

+0

@Rapptz: Przypuszczam, że ponieważ kod C++ często zużywa i eksponuje API kompatybilne z C, ponieważ są one znacznie bardziej kompatybilne z innymi językami –

+1

Dla C++ jest to idiomatyczne użycie 'std :: string' -' struct Foo {std :: string fa; }; '. –

Odpowiedz

6

Istnieją zasadniczo 3 wspólne konwencje strun. Wszystkie trzy znajdują się w stanie dzikim, zarówno dla reprezentacji w pamięci, jak i przechowywania/transmisji.

  1. Naprawiono rozmiar. Dostęp jest bardzo wydajny, ale jeśli rzeczywista długość różni się zarówno przestrzenią odpadów, jak i jedną z poniższych metod określania końca "prawdziwej" treści.
  2. Długość z prefiksem. Dodatkowe miejsce jest uwzględnione w dynamicznym przydziale, aby utrzymać długość. Ze wskaźnika można znaleźć zarówno treść postaci, jak i długość bezpośrednio przed nią. Przykład: BSTR Czasami długość jest kodowana, aby była bardziej efektywna pod względem przestrzeni w przypadku krótkich łańcuchów. Przykład: ASN-1
  3. Zakończony. Ciąg znaków rozciąga się do pierwszego wystąpienia znaku zakończenia (zazwyczaj NUL), a treść nie może zawierać tego znaku. Wariacje spowodowały, że terminacja była dwa razy NUL, aby umożliwić istnienie indywidualnych znaków NUL w łańcuchu, który jest często traktowany jako spakowana lista ciągów znaków. Inne warianty używają kodowania, takiego jak wypychanie bajtów (działałby także kod UTF-8), aby zagwarantować, że istnieje jakiś kod zarezerwowany dla zakończenia, który nie może pojawić się w zakodowanej wersji zawartości.

W trzecim przypadku istnieje funkcja, taka jak strlen, aby wyszukać terminator i znaleźć jego długość.

Oba przypadki, w których używane są wskaźniki, mogą wskazywać dane bezpośrednio po ustalonej części struktury, jeśli ostrożnie przydzieli się je w ten sposób.Jeśli chcesz to wymusić, użyj elastycznej tablicy na końcu twojej struktury (nie potrzebujesz wskaźnika). Tak:

typedef struct 
{ 
    int damage; 
    char name[]; // terminated 
} Item; 

lub

typedef struct 
{ 
    int damage; 
    int length_of_name; 
    char name[]; 
} Item; 
+0

Myślę, że to się nazywa "elastyczny", a nie "nierówny" i nie jest obsługiwany przez wszystkie kompilatory. – anatolyg

+0

@anatolyg: Dzięki za to. Myślę, że to standard dla C i nielegalne w C++? –

+0

@BenVoigt, AFAIK, tak, nielegalne w C++. – chris

0

Jeśli znasz maksymalną długość łańcucha, czego potrzebujesz, a następnie można użyć tablicę znaków. Oznacza to jednak, że zużyjesz więcej pamięci niż zwykle używasz z dynamicznie przydzielanymi tablicami znaków. Zobacz także CString, jeśli używasz C++. Możesz znaleźć długość tablicy znaków za pomocą strlen. W przypadku alokacji statycznej uważam, że będzie częścią zmiennej. Dynamiczny może znajdować się w dowolnym miejscu sterty.

1
1) is there any other advantage to using the fixed size (1) 

char name[40]; 

versus doing the following and using a pointer to a char array (2)? 

char *name; 

and if so, what is the advantage? 

Z macierzy zadeklarowane jako char name[40]; przestrzeń dla nazwy jest już przydzielone i jesteś wolny, aby skopiować informacje do name z name[0] przez name[39]. Jednak w przypadku char *name; jest to po prostu wskaźnik i może być użyty do wskazania istniejącego ciągu znaków w pamięci, ale sam nie może być używany do kopiowania informacji, dopóki nie przydzieli pamięci do przechowywania tych informacji. Tak, że masz ciąg 30 znaków, który chcesz skopiować do name zadeklarowanej jako char *name;, najpierw należy przeznaczyć z malloc 30 znaków plus dodatkowego charakteru trzymać null kończące znak:

char *name; 
name = malloc (sizeof (char) * (30 + 1)); 

Wtedy jesteś bezpłatne kopiowanie informacji do/z name. Zaletą przydzielania dynamicznego jest to, że można uzyskać realloc pamięć dla name, jeśli informacje przechowywane w nazwie rosną. powyżej 30 znaków. Dodatkowym wymaganiem po przydzieleniu pamięci dla name, jesteś odpowiedzialny za zwolnienie pamięci przydzielonej, gdy nie jest już potrzebna. To jest przybliżony zarys zalet/wad/wymagań dotyczących korzystania z jednego w przeciwieństwie do drugiego.

Powiązane problemy