Brak rezerwacji pamięci dla tablic w strukturach

0

Witam,

Potrzebuję zrobić strukturę w której będą wpisane jakieś dane "zdefiniowane" podczas kodzenia.
W uproszczeniu podam mój problem:

struct menu_t{
    char text[];
    /* ... */
};

/* program */
static struct menu_t menu = { .text="Ala ma kota" };

I program podczas działania się wysypuje, kompilator nie przydziela miejsca dla łańcucha tylko go "kopiuje" do obszaru który nie jest zarezerwowany. Przy najbliższym wskoczeniu do jakiejś funkcji, zawartość menu.text jest nadpisywana(przez adresy powrotu i tak dalej...)
Tworząc taki zapis na strukturze, kierowałem się tym:

int main(){ // programy z przedszkola ;) 
  char text[] = "Ala ma kota";
  /* ... */
}

Tutaj jakoś kompilator rezerwuje pamięć dla tekstu, dlaczego tak nie jest z strukturą? Jak to rozwiązać?
Nie mogę z góry nałożyć długości w strukturze, jest ona rozbudowana i długości tekstów(oraz tablic do następnych struktur) jest bardzo różnorodna.

0

Zaobserwowałem że nie wysypuje się gdy przy łańcuchu jest * a przy strukturach(w strukturze [])

struct menu_t{
  char * txt;
  struct przycisk_t przyciski[];
}


/* program */
static struct menu_t menu = {
  .txt = "Napis scienny",
  .przyciski = {
    [0]={ .... },
    [1]={ .... },
    [2]={ .... },
  }
};
0

Taki zapis:

 char text[] = "Ala ma kota";

wolno stosowac TYLKO w trakcie tworzenie tablicy i on automatycznie powoduje "zarezerwowanie" pamieci na stosie. Probojac zrobic to w innym miejscu powinienes mieć błąd kompilacji.

0

Użyj stringa lub gorzej odpowiednio dużej tablicy. Wskaźnik może być. Chociaż przechowywanie zewnętrznego zasobu nie jest dobrym pomysłem.
Dla struktury też rezerwuje. Ale skąd ma wiedzieć ile ma zarezerwować na tablicę znaków nie znając jej długości.

0

Jesli masz ograniczone zasoby (embedded?), to mozesz w strukturze przechowywac tylko wskaznik, a pamiec rezerwowac dynamicznie (malloc). Natomiast jesli to zwykla, wspólczesna maszyna, to zdefiniowalbym w strukturze pole o maksymalnej mozliwej dlugosci -- co za róznica czy zajmiesz 1 czy nawet 100 kB? Dobrym zwyczajem jest uzywanie makr w takich przypadkach:

#define MAX_MENU_TEXT_LEN 255

struct menu_t {
    char text[MAX_MENU_TEXT_LEN+1];
    /* ... */
};
 
/* program */
static struct menu_t menu;
strcpy(menu.text, "Ala ma kota");

Jesli cos da sie rozwiazac w prosty sposób, to kombinowanie jest grzechem.

0

Chociaz dla menu lepiej zrobic tak:

/* max str lengths */
#define MAX_MENU_TEXT_LEN 100

/* menu items */
#define M_FILE_NEW 1
#define M_FILE_OPEN 2
.
.
.
#define M_FILE_EXIT n
 
struct menu_t {
    int id;
    char text[MAX_MENU_TEXT_LEN+1];
    /* ... */
};
 
/* program */
static struct menu_t menu[] = {
    {M_FILE_NEW, "Ala ma kota", ...},
    {M_FILE_OPEN, "Kot ma Ale", ...},
    .
    .
    .
    {M_FILE_EXIT, "Koniec", ...}
};
0
char text[] = "Ala ma kota";

Nie rób tak. Używaj const jeśli do zmiennej przypisujesz literał:

const char text[] = "Ala ma kota";
const char *text = "Ala ma kota";
1

Dodać const tam gdzie są zadeklarowane "zmienne" w strukturze?

struct button_t {
  int x, y, w, h;
  char * text;
  void (*onClick)(); /* zdarzenie wciśnięcia przycisku */
};

struct window_t {
  char * caption;
  int blen; /* ilosc klawiszy */
  struct button_t  buttons[];
};


  static struct window_t win = {
    .caption = "Okno nawigacyjne",
    .blen = 2,
    .buttons = {
      [0]={.x = 60, .y = 50, .w = 200, .h = 50, .onClick=funkcja1, .text="Modyfikuj obroty silnika"},
      [1]={.x = 60, .y = 120, .w = 200, .h = 50, .onClick=funkcja1,  .text="Zmien przelozenie"},
    }
  };

Coś takiego na razie się nie wysypuje.
"window" też będzie tablicą.

0

Nie wysypuje się, ale istnieje zagrożenie, że w końcu jakiś bug powstanie.
char * text - to jest wskaźnik na zwykły char i sugeruje, że wskazywane znaki są modyfikowalne.
Ty podajesz literał czyli wskaźnik na znaki niemodyfikowalne (const):
text = "lierał";
To jest tylko przypisanie wskaźnika na znaki. Same znaki nie są nigdzie kopiowane. O ile taka konwersja jest dozwolona, o tyle może doprowadzić do błędu. Jeśli teraz zrobimy
text[0] = 'X';
to nam się program wysypie bo piszemy po pamięci const (po literale). Tak więc zawczasu należałoby oznaczyć text jako wskaźnik na znaki niemodyfikowalne:
const char *text
Wtedy kompilator zadba o to, aby nie dało się modyfikować tego tekstu, text[0] = 'X'; nie skompiluje się.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.