Rozmiar dynamicznej zmiennej

0

Dzień dobry, przeczytałem sobie kurs C++ i mam taką
niejasność, chodzi mi o rozmiar zmiennej dynamicznej:

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

int main() {
  char *text;
  text = (char*) malloc(1);
  *text = 'a';
  *(text+1) = 'b';
  printf("%s", text);
  system("pause > nul");
  free(text);
  return 0;
}

według tego co napisali w kursie to malloc(n) przydziela pamięć
wielkości n bajtów i zwraca do niej wskaźnik.

  1. No i teraz pytanie: dlaczego do tej pamięci udaje się zapisać
    dwa bajty i na ekranie wyświetla się ciąg "ab", skoro rozmiar
    przydzielonej pamięci to tylko jeden bajt ?

  2. Czy dla zmiennej typu wskaźnikowego:

*(zmienna+n) jest równoznaczne ze zmienna[n] ?

  1. Gdzie znajdę jakiś help, może być z przykładami, byle by nie był
    kursem ;-) Coś pod kątem Dev C++ 4 ?
0
  1. No i teraz pytanie: dlaczego do tej pamięci udaje się zapisać
    dwa bajty i na ekranie wyświetla się ciąg "ab", skoro rozmiar
    przydzielonej pamięci to tylko jeden bajt ?

W trybie rzeczywistym pamięć nie jest chroniona. Akurat tak się złożyło, że miejsce na które wskazuje text jest wolne i zapisanie czegoś dalej niczego nie zmieni. Ale nie masz na to gwarancji i gdyby tam była inna zmienna, to byś ją zamazał.
C++ daje ogromne możliwości i niskopoziomową obsługę wskaźników, ale to nakłada na programistę obowiązek pamietania ile może zapisać do pamięci. Tu nie ma sprawdzania rozmiarów tablic, bo tablica to nic innego, jak wskaźnik na pierwszy element.

  1. Czy dla zmiennej typu wskaźnikowego:

*(zmienna+n) jest równoznaczne ze zmienna[n] ?

Tak, ale podobno - tylko podobno - sposób pierwszy jest szybszy.

0

Co do tej dynamicznej tablicy to i tak malloc jest uzalezniony od tego co mu daje
OS !! Wiec jak np pod Winda NT robisz malloc(1) czyli jeden bajt to na defaultowym
heapie rezerwowane jest 32bajty !!!! (16 taki naglowek i 16 bajtow na dane - mniej sie nie da
w tym dwa zajales i jeszcze zostalo 14 do uzytku bez martwienia sie o Access Violation !!)
i tego nie da sie zmienic - tak dziala VMM. Znowu jak zrobisz malloc(14) to na haepie
zostanie odlozone 48bajtow(16 naglowek + 16 + 16) ale nie pokaze Ci tego zadna funkcja :D

Wiec wszystko zalezy od OS i tego jak organizuje on pamiec !!
A to czy wywali blad to zalezy od teog czy nie natrafimy na koniec page'a,
na obszar reserved itp itd ale to juz inna historia ;)

Jedyny wartosciowy help to MSDN(C, C++, winapi, java itp itd) a jaki kompilator to juz bez roznicy ;) no chyba
ze chodzi o zakumanie poslugiwania sie IDE kompilatora bo C++ jest ponad kompilatorami ;)

Co do tych dwoch sposobow dojscia do elementu to looknij :

26:     qwaaa[20] = 'a';
00401050   mov         ecx,dword ptr [ebp-18h]
00401053   mov         byte ptr [ecx+14h],61h
27:     *(qwaaa + 20) = 'a';
00401057   mov         edx,dword ptr [ebp-18h]
0040105A   mov         byte ptr [edx+14h],61h

tak wygladaja zdisassemblowane oba dzialania(VC++). Wiec ta szybkosc jezeli (podobno ;) )
jest wieksza lub mniejsza to zalezy to tylko od kompilatora .

0

Dziękuję serdecznie za odpowiedzi

[browar] dla Marooned'a i [browar] dla snaj'a

a w takim razie jak bym chciał żeby po linijce:

*str = 'a';

powiększyć tę że pamięć, na którą wskazuje str,
to jak to wykonać, kiedy piszę ponownie:

str = (char*) malloc(2);

to wartość wskaźnika się zmienia więc wydaje mi
się że to przydziela nową pamięć, a czy dało by
się powiększyć aktualną ?

Tak mi przychodzi do głowy że jeśli zmieni się
wskaźnik to free(str) zwolni to nowe miejsce w
pamięci, da się jakoś po utracie wskaźnika
zwolnić poprzednie miejsce z pamięci ?
Czy gdyby taka sytuacja zaistniała wewnątrz funkcji
to pamięć została by automatycznie zwolniona po
jej zakończeniu, tak jak to się dzieje po
zakończeniu programu ?

Nie wiem czy to nie będzie przesada ale mam jeszcze
pytanie ;-) Zauważyłem że taka konstrukcja:

char *str;
str = "bla bla";

działa bez problemu. Czy to też się zalicza do
dynamicznego przydziału pamięci ?

No i już ostatnia sprawa, jak naprawić poniższy
kod ? Założenie miałem takie żeby funkcja na podstawie
argumentu tworzyła w pamięci kopię zmiennej i zwracała
wskaźnik do tej kopii, natomiast wyświetlają się na
ekranie dwa znaki: =p

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* fun(char *s) {
  char *tmp;
  tmp = (char*) malloc(strlen(s));
  while(*s) {
    *tmp = *s;
    tmp++, s++;
  }
  return tmp;
}
void main() {
  char *str1, *str2;
  str1 = "bla bla bla bla";
  str2 = fun(str1);
  printf("%s", str2);
  system("pause > nul");
}
0

Ad. 1
str = (char *) realloc(str, nowy_rozmiar);
Ad. 2
char *str; <- jakiś wskaźnik
"bla bla" <- jakaś "stała"

str = "bla bla"; <- ustawienie wskaźnika na tą stałą. Wobec tego nie bardzo jest to dynamiczny przydział, gdyż tutaj pamięci nie alokujesz.

Ad. 3

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* fun(char *s) 
{
  char *tmp;
  tmp = (char*) malloc(strlen(s));
  strcpy(tmp, s);
  return tmp;
}
void main() {
  char *str1, *str2;
  str1 = "bla bla bla bla";
  str2 = fun(str1);
  printf("%s", str2);
  system("pause > nul");
}

Jeżeli chciałbyś swoją metodą, to musisz zapamiętywać początek tablicy:

char* fun(char *s) {
  char *tmp, *pom;
  tmp = (char*) malloc(strlen(s));
  pom = tmp;
  while(*s) {
    *tmp = *s;
    tmp++, s++;
  }
  return pom;
}

Bo inaczej ucieknie ci wskaźnik i będzie wskazywał miejsce za tablicą.

0

Bo inaczej ucieknie ci wskaźnik i będzie wskazywał miejsce za tablicą.

no to teraz [browar] dla Dryobates'a, że też ja nie mogłem
przez 3 godziny wpaść na takie logiczne rozwiązanie... [glowa]

BTW: Doszlifowałem sobie tę funkcję o tak:

char *fun(char *s) {
  char *t, *r;
  r = t = (char*) malloc(strlen(s) + 1);
  do *t++ = *s; while (*s++);
  return r;
}

i muszę powiedzieć że składnia C++ jest przednia :-D

To mam teraz najostateczniejszą niejasność (jak na dziś),
rozumiem że taką dynamicznie stworzoną zmienną
trzeba zwolnić przez free().

No i w przypadku gdy jest ona takim PChar to rozumiem
że to ile pamięci zwolnić wiadomo dzięki 0x00, który
jest na końcu łańcucha, a co w przypadku gdy to będzie
dynamicznie przydzielona pamięć na jakieś rekordy ?

Skąd free() będzie wiedziało jakiego to jest rozmiaru ?

Marooned napisał: "Tu nie ma sprawdzania rozmiarów tablic,
bo tablica to nic innego, jak wskaźnik na pierwszy element"

To znaczy że nie da się w C++ pobrać wielkości dynamicznie
przydzielonej pamięci (o ile nie jest to typu *char,
który kończy się zerowym bajtem) ?

0

Już snaj napisał, że jest rezerwowane w rzeczywistości więcej niż wymagasz. Jak zwalniasz, to odczytuje informacje z nagłówka i zwalnia cały blok.

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