Stos i sterta jeszcze raz.

0

Nie do końca jeszcze rozumiem idei działania stosu i sterty.
Z tego co wiem to zmienne lokalne są tworzone na stosie a globalne na stercie. Stos jest przydzielany przez OS podczas uruchamiania programu. Można go przepełnić poprzez zbyt częste wywoływanie funkcji?

Sterta nie jest ściśle przydzielona do konkretnego programu. Zmienne dynamiczne są tworzone na stercie. Gdzie będą tworzone zmienne lokalne dynamiczne?

Tak jak w poniższym przykładzie?

#include <stdio.h>

void fun ()
{
    double * ptr;

    ptr = (double*)malloc(65000 * sizeof(double));
}

int main()
{
    while (1)
    {
        fun();
    }
    getch();
}
2

Wskaźnik będzie na stosie, a zaalokowana pamięć na stercie.

0
  1. Stos można przepełnić za głęboką rekurencją. Wywołanie funkcji odkłada na stos adres powrotu (żeby program wiedział gdzie byłeś zanim funkcje wywołałeś). Jeśli z funkcji x wołasz kolejną a z tamtej kolejną i... to odkładasz tych adresów dużo i stos moze się skończyć
  2. malloc/new alokują pamięć na stercie, ale pokazywać na tą pamięć możesz za pomocą zmiennej lokalnej (na stosie) lub innej zmiennej na stercie.
0

Mam tutaj jeszcze mały program który porusza zagadnienia stosu.

 #include<stdio.h>
#include<stdlib.h>

void print(void)
{
    printf("Hello\n");
}

int* add(int a, int b)
{
    int c = a + b;
    return &c;
}

int main()
{
    int a = 2;
    int b = 4; 

    int * c = add(a, b);
    print();
    printf("%d + %d = %d\n", a, b ,*c);
    getch();

    return 0;
}

Wywołanie funkcji print powoduje odłożenie na stos parę wartości i nadpisuje wartość na którą wskazuje wskaźnik c.

W poniższym przykładzie zamiast funkcji print deklaruję tablicę 100 elementową, potem ją wypełniam, ale wartość na którą wskazuje wskaźnik c, nie jest już nadpisana. Dlaczego?

 #include<stdio.h>
#include<stdlib.h>

void print(void)
{
    printf("Hello\n");
}

int* add(int a, int b)
{
    int c = a + b;
    return &c;
}

int main()
{
    int a = 2;
    int b = 4; 

    int * c = add(a, b);
    int tab[100];
    for (int i = 0; i < 100; i++)
    {
        tab[i] = i*10;
    }
    printf("%d + %d = %d\n", a, b ,*c);
    getch();

    return 0;
}
1

To jest UB:

 int c = a + b;
 return &c;

Zwracasz wskaźnik do zmiennej, która po wyjściu z funkcji już nie istnieje.

A jeśli chodzi o to dlaczego tak się dzieje, no to zmienne a, b, c, i tablica tab leżą w jednym regionie pamięci po sobie. Wchodząc do funkcji add stos się powiększa, wychodząc z funkcji stos się pomniejsza, i zapisanie czegokolwiek do a, b, c, tab nie skutkuje zmianą pamięci zmiennej c w funkcji add. printf natomiast prawdopodobnie tworzy własne zmienne, dokładnie w miejscu gdzie była zmienna c (lub nawet adres powrotu tam jest zapisywany). Wszystko zależy od kompilatora.

Tutaj widać o co tutaj chodzi: http://ideone.com/5MFISr

0
mwl4 napisał(a):

To jest UB:

 int c = a + b;
 return &c;

Zwracasz wskaźnik do zmiennej, która po wyjściu z funkcji już nie istnieje.

To jest błąd, ale to nie jest UB.
UB będzie dopiero dereferencja tego wskaźnika:

   int * c = add(a, b);
   printf("%d + %d = %d\n", a, b ,*c); // <---------- UB

.

Sterta nie jest ściśle przydzielona do konkretnego programu.

Sterta jest ściśle przydzielona do konkretnego programu. Każdy program ma własną stertę.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0