Język C malloc()

0

Hej! Mam drobny problem. Na politechnice programujemy w C z braku biblioteki <string> na potrzeby zajęć próbuję sobie sam napisać funkcję z inteligentną tablicą char... Pomysł jest prosty mamy wskaźnik alokujemy mu pamięć na 20 znaków char a następnie wczytujemy po 1 znaku za pomocą getchar() i zapisujemy do tablicy. Jak nadpiszemy przedostatni element tablicy na końcu stawiamy '\0' uruchamiamy funkcję zwieszającą pojemność tablicy. Robimy to myślę normalnie w funkcji jest lokalny wskaźnik który jest alokowany tą samą pojemnością co stary string znakowy specjalna funkcja kopiuje znaki z jednej tablicy do drugiej oryginalny wskaźnik ma przydzieloną pamięć dodatkową +5 elementów znowu funkcja kopiująca i zwolnienie starego wskaźnika... działa to tylko do 1 wywołania tej funkcji - pierwsze wywołanie przebiega bez problemu pamięć jest alokowana stringi przepisywane i ok. Podczas drugiego wywołania funkcji wykonywanie programu zatrzymuje się przy próbie alokowania pamięci dla wskaźnika lokalnego old. A teraz czas na kod:
//Definicje Funkcji

int rozmiar(char* text)
{
int i;
for(i=0; ;i++)
if (text[i] == '\0' ) return i;
}

inline void str_cpy(char* input, char* output, int size)
{
int i;
for(i=0; i < size; i++)
output[i] = input[i];
output[i+1] = '\0';
}

void re_size(char* text, int ile)
{

char * old;
old = (char*) malloc(rozmiar(text)sizeof(char)+1); // <-właśnie ta linia nie może wykonać się poraz drugi
str_cpy(text,old, rozmiar(text));
free(text);
text = (char
) malloc((rozmiar(old) + ile)*sizeof(char));
str_cpy(old,text,rozmiar(old));
free(old);

}

char* read(char* wsk)
{
char * old;
int i;
int s_rozmiar = 20;
wsk = (char*) malloc(s_rozmiar*sizeof(char));
for(i = 0; ; i++)
{
if((i+1) == s_rozmiar)
{
wsk[i] = '\0';
re_size(wsk,5);
s_rozmiar += 5;

}

if((wsk[i]=getchar()) =='\n'){
wsk[i]='\0';
fflush(stdin);
return wsk;
}
}
}

Jakieś pomysły.

0

Spróbowałem z funkcją realloc();
....
if((i+1) == s_rozmiar)
{
wsk[i] = '\0';
//re_size(wsk,5);
wsk= (char*) realloc(wsk, rozmiar(wsk)+5*sizeof(char)); <-w ten sposób
s_rozmiar += 5;

}
....
efekt jest dokładnie ten sam:( tablica rozszerza się do 25 znaków a przy ponownej realokacji pamięci program zatrzymuje działanie:(

0

Dam Ci rade. Sformatuj ten kod. Moze wtedy komus bedzie sie chcialo go czytac, a nawet sam dojrzysz co robisz zle :)

0

Funkcja re_size nie zwraca nic, powinna albo przyjmować wskaźnik do wskaźnika do char, albo zwracać char*.

0

JAk tylko wroce od lekarza bo właśnie wychodzę:D
Sorki że nie ma wcięć ale w devie jakoś dziwnie robi czasem bardzo małe a czasem szerokie ,więc nie korzystam z tego (Programy w c++ piszę w visual'u Microsoftu).

0

W C jest biblioteka string.h. Zamiast przerzucać po znaku w pętli, użyj memcpy()... Reszcie się przyjrzę jak sformatujesz kod ;)

0

Celem ćwiczenia jest praca na funkcjach z biblioteki stdio :D więc nie mogę korzystać z biblioteki string.h :D trzeba pracować z tym co mamy:D a co do formatowania zaraz to zrobie tylko zjem bo dopiero co wróciłem:D

0

//Definicje Funkcji

int rozmiar(char* text)
{
int i;
for(i=0; ;i++)
if (text[i] == '\0' ) return i;
}

inline void str_cpy(char* input, char* output, int size)
{
int i;
for(i=0; i < size; i++)
output[i] = input[i];

 output[i+1] = '\0';

}

void re_size(char* text, int ile)
{

char * old;
old = (char*) malloc(rozmiar(text)*sizeof(char)+1);

  str_cpy(text,old, rozmiar(text));

  free(text);

  text = (char*) malloc((rozmiar(old) + ile)*sizeof(char));    

  str_cpy(old,text,rozmiar(old));
  
  free(old);

}

char* read(char* wsk)
{
char * tmp;
int i;
int s_rozmiar = 20;
wsk = (char*) malloc(s_rozmiar*sizeof(char));

for(i = 0;  ; i++)
      {
      if((i+1) == s_rozmiar)
               {
               wsk[i] = '\0';
               
               //re_size(wsk,5);
              // wsk= (char*) realloc(wsk, (rozmiar(wsk)+5)*sizeof(char));
                    if( (tmp =(char*) realloc(wsk, (rozmiar(wsk)+5) * sizeof(char))) == NULL )
                         {
                         printf("Blad zapisu pamieci");
                         }
                         else
                         { 
                         wsk = tmp;
                         }

                s_rozmiar += 5;

                }

        if((wsk[i]=getchar()) =='\n'){
        wsk[i]='\0';
        fflush(stdin);
        return wsk;
        }
 }    

}

dopisałem drugi wariant (bezpieczniejszy) z funkcją realloc(); skopiowany stąd//4programmers.net/C/Biblioteka_standardowa/Stdlib.h/Realloc Niestety to samo raz poszerzy tablice potem kaplica

0

Muszą być te funkcje?
Jeśli nie to:

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

int main()
{
    char ch;
    int rozmiar=20;
    char *napis=(char*)malloc(rozmiar); // pierwsza rezerwacja pamieci
    int i=0;
    while ((ch=getchar())!='\n')
    {
        if (i>=rozmiar-1)
        {
            rozmiar+=5;
            napis=(char*)realloc(napis, rozmiar);
        }
        napis[i++]=ch;
    }
    napis[i]=0;
    printf("Napis: '%s'\nRozmiar zaalokowany: %db\nDlugosc napisu: %d znakow\n", napis, rozmiar, i);
    free(napis);
    return 0;
}
0

Ojjjj... dlaczego tego nie umieściłeś jako kod...?

Polibuda napisał(a)
//Definicje Funkcji

int rozmiar(char* text)
{
  int i;
      for(i=0; ;i++)
           if (text[i] == '\0' ) return i;    
}

Bajzel. Część nazw funkcji i argumentów po polsku, część po angielsku... Brak spójności w nazwach (powinno być raczej str_size lub str_length zamiast rozmiar).

Polibuda napisał(a)
inline void str_cpy(char* input, char* output, int size)
{
 int i;
     for(i=0; i < size; i++)       
              output[i] = input[i];
 
     output[i+1] = '\0';
}

Brak kontroli zakresów (nie wierz w to, że size będzie zawsze dodatnie), sztuczne ograniczenie długości ciągu (ale uznajmy, że takie są założenia).

Polibuda napisał(a)
void re_size(char* text, int ile)
{

 char * old;
      old = (char*) malloc(rozmiar(text)*sizeof(char)+1);
    
      str_cpy(text,old, rozmiar(text));
    
      free(text);

      text = (char*) malloc((rozmiar(old) + ile)*sizeof(char));    
 
      str_cpy(old,text,rozmiar(old));
      
      free(old);
 
}

Auć... Nie uważasz, że to trochę bez sensu? Alokujesz pamięć, wrzucasz tam ciąg (który już jest gdzie indziej w pamięci), po czym znowu... ajj... Pomijając już fakt, że poza funkcją text wskazuje na kosmos po jej zakończeniu (free(text)). Memory leak i to straszny. Alokujesz pamięć, po czym tracisz do niej wskaźnik i nie masz jak jej zwolnić. W tej funkcji zmieniasz tylko kopię lokalną text. Szczerze mówiąc, nie wiem co Ty tutaj wyrzeźbiłeś...
Po pierwsze, funkcja powinna przyjmować wskaźnik na wskaźnik, lub zwracać nowy wskaźnik. Po drugie, nie lepiej zaalokować raz przestrzeń o rozmiarze docelowym i skopiować wszystkie dane?

char  *re_size(char*  text,  int  length)
{
    char   *new;
    
    if ( (new = (char*)malloc(rozmiar(text) * sizeof(char) + length + 1)) == NULL )
        return NULL /* błąd alokacji; przyczyna w errno */

    str_cpy(text, new, rozmiar(text));
    free(text); /* Nie zapomnij poinformować w dokumentacji, że ciąg zostanie zwolniony! */
    return new;
}

Popraw... się ;)

0

Testuje sobie funkcje malloc i mam kilka pytań.

  1. Poniższy kod kompiluje się na MinGW:
int main(int argc, char** argv) {    
    char *napis;
    int rozmiar = 10;
    int i=0;    
    napis = (char*)malloc(rozmiar+1);
    napis ="wiecej_niz_10_znakow";
    printf("%s",napis); 
    free(napis);    
    return (EXIT_SUCCESS);
}

Dlaczego skoro do zmiennej napis przypisano wiecej niz 10 znakow?

  1. Druga sprawa ze na cygwinie mimo, że napis jest krótszy niż 10 znaków, wywala błąd po uruchomieniu programu..
int main(int argc, char** argv) {    
    char *napis;
    int rozmiar = 10;
    int i=0;    
    napis = (char*)malloc(rozmiar+1);
    napis ="tekst";
    printf("%s",napis); 
    free(napis);    
    return (EXIT_SUCCESS);
}
0

Spójrz na taki zapis:

int a;
a = 5;
a = 10;

To jest dokładnie to samo, co próbujesz zrobić z własnym napisem. Najpierw alokujesz pamięć i przypisujesz wskaźnik nań do zmiennej, a później przypisujesz zupełnie inny wskaźnik - na stałą tekstową, która najprawdopodobniej znajduje się gdzieś w pamięci, która jest chroniona przed zapisem. I ty tą pamięć, której zmieniać nie możesz - chcesz zmienić, tj. zwolnić. Stąd błędy.

Rozwiązanie: strcpy.

0
TezPolibuda napisał(a)

Testuje sobie funkcje malloc i mam kilka pytań.

  1. Poniższy kod kompiluje się na MinGW:

Źle przypisujesz ciąg znaków (jak już kolega wyżej Ci zwrócił uwagę). Ale wiem o co chcesz zapytać, więc dam Ci taki przykład (z "prawidłowym" przypisaniem):

char  *foo(int  size)
{
    char   *t;

    t = (char*)malloc(size);
    strcpy(t, "Ala ma kota");
    return t;
}

Kompilator nie jest w stanie stwierdzić czy przekroczyłeś zakres czy nie, gdyż rozmiar alokowanej pamięci nie jest znany na etapie kompilacji.
Język C nie ma kontroli zakresów, zatem wyjechanie poza granice nie powoduje błędu podczas kompilacji. Spowoduje błąd podczas działania programu, jeśli wyjedziesz na obszar pamięci, który nie został Ci przydzielony (błąd segmentacji). Musisz być uważny pisząc kod i używać funkcji, które nie zezwolą na zapisanie większej liczby bajtów niż określona przez Ciebie, np. strncpy.

0

Kumashi poczekaj ,bo mi namieszałeś jak piekło teraz wcześniejszą wypowiedzią:D
Nie umieściłem jako kod ,bo zwyczajnie nie wiem jak to zrobić ,a potrzebowałem w miarę szybkiej odpowiedzi.
Niespójność nazw wynika z tego ,że gdybym chciał zrobić zmienna size to na 99% kolidowała ,by z jakaś funkcja z biblioteki (chyba miałem kiedyś problem z tą nazwą i dlatego czasami tylko dodaje _ a czasami używam polskich nazw (Jedynie w programach na zajęcia ,gdyż są na tyle małe ,że jestem w stanie je spamiętać.
właśnie dlatego napisałem funkcję z parametrem int określającym rozmiar żeby ,był zawsze dodatni:) a przechodząc do meritum:
[quote] Auć... Nie uważasz, że to trochę bez sensu? Alokujesz pamięć, wrzucasz tam ciąg (który już jest gdzie indziej w pamięci), po czym znowu... ajj... Pomijając już fakt, że poza funkcją text wskazuje na kosmos po jej zakończeniu (free(text)). Memory leak i to straszny. Alokujesz pamięć, po czym tracisz do niej wskaźnik i nie masz jak jej zwolnić. W tej funkcji zmieniasz tylko kopię lokalną text. Szczerze mówiąc, nie wiem co Ty tutaj wyrzeźbiłeś...
Po pierwsze, funkcja powinna przyjmować wskaźnik na wskaźnik, lub zwracać nowy wskaźnik. Po drugie, nie lepiej zaalokować raz przestrzeń o rozmiarze docelowym i skopiować wszystkie dane? [/quote]
Nie uważam tego za bezsensowne. Przepisuje sobie wartość do lokalnego wskaźnika ,który na chwile ma przydzieloną pamięć mogącą pomieścić dany string.
Z zasady Każdą dynamiczne alokowaną pamięć trzeba zwolnić bo jeśli się tego nie zrobi. to straci się adres pamięci gdzie ta zarezerwowana pamięć jest. Ja to rozumiem tak że pamięć dalej będzie zajęta przez pewne składniki dane (i nie będzie mogła być nadpisana) ,ale my utracimy do niej możliwość dostępu. (może rozumuję źle) następnie alokuję nową pamięć odpowiednio powiększoną zapisuję jej adres do starego wskaźnika i i przepisuje do niego starą wartość wyrażenia po czym zwalniam pamięć zajmowaną przez wskaźnik tymczasowy. Ponieważ funkcja odbierała wskaźnik to znaczy że w trakcie pracy funkcji modyfikowała wartość oryginalnego wskaźnika i teraz on ma tą powiększoną wartość. I to działa problem w tym że do drugiego obiegu pętli. działanie programu pokazuje że po wprowadzeniu więcej niż 24 znaki tablica char przechowuje 24 znaki po czym przy próbie alokacji pamięci się zawiesza. Problem jest zapewne w tym że czegoś nie rozumiem ,ale to nie tłumaczy wcale ,nie działają obie wersje z korzystające z funkcji realloc; pierwsza jest błędna - wiem ,ale 2 jest kropka w kropkę (tylko zmienione są nazwy zmiennych) identyczna tak jak podane było na załączonej stronie a mimo wszystko jej działanie jest identyczne jak działanie mojej wersji.
mógłbym to zrobić tak jak proponujesz ale nie w funkcji. Dlaczego? bo musiał bym zwrócić adres tego nowego wskaźnika a to oznacza że nie mógłbym zwolnić przydzielonej mu pamięci ,aż do instrukcji return ,a umieszczanie jej po returnie nie miało by już sensu. chyba że ja naprawdę czegoś nie rozumiem.
bilbosz musi być funkcja... program nie polega na takiej alokacji tylko na pobraniu imienia i nazwiska użytkownika (a potem kilka innych zadań też z wczytywaniem) ale alokowanie dwóch tablic o rozmiarze powiedzmy po 50 elementów każda i wczytywanie wartości do niej byłoby zbyt proste i nic by mnie nie nauczyło to umiem od dawna... chcę sięgnąć wyżej zrobić coś więcej niż to co wymagane:D

0
Polibuda napisał(a)

Kumashi poczekaj ,bo mi namieszałeś jak piekło teraz wcześniejszą wypowiedzią:D
Nie umieściłem jako kod ,bo zwyczajnie nie wiem jak to zrobić ,a potrzebowałem w miarę szybkiej odpowiedzi.

Umieść kod w znacznikach code, np.

<code class="c">int main(void);</code>

Polibuda napisał(a)

Niespójność nazw wynika z tego ,że gdybym chciał zrobić zmienna size to na 99% kolidowała ,by z jakaś funkcja z biblioteki (chyba miałem kiedyś problem z tą nazwą i dlatego czasami tylko dodaje _ a czasami używam polskich nazw (Jedynie w programach na zajęcia ,gdyż są na tyle małe ,że jestem w stanie je spamiętać.

Nie ma konfliktu nazw w bibliotece standardowej z size, length, str_size czy str_length. Możesz też stosować nazwy skrócone (len) czy różnego rodzaju prefiksy i sufiksy. Jeśli chcesz uniknąć konfliktów w dół w przypadku nazw funkcji, deklaruj je jako static.
Jak chcesz, to nazywaj je po polsku, ale niech to będzie spójne, a nie robisz z kodu Esperanto. To naprawdę utrudnia czytanie, o pisaniu nie wspominając. A nazwy zapamiętasz przez miesiąc, może dwa. Programy na zajęcia musi czytać Twój wykładowca, miej dla niego litość.

Polibuda napisał(a)

właśnie dlatego napisałem funkcję z parametrem int określającym rozmiar żeby ,był zawsze dodatni:)

Typ int to jest liczba całkowita ze znakiem. Zapewne chodziło Ci o ''unsigned int'.

Polibuda napisał(a)

Nie uważam tego za bezsensowne. Przepisuje sobie wartość do lokalnego wskaźnika ,który na chwile ma przydzieloną pamięć mogącą pomieścić dany string.

Po co? Przecież te dane masz już w pamięci. Nikt Ci ich nie ukradnie w środku funkcji. Niepotrzebnie kopiujesz dane, a dla wykładowcy to może wyglądać jak brak znajomości działania wskaźników.

Polibuda napisał(a)

Z zasady Każdą dynamiczne alokowaną pamięć trzeba zwolnić bo jeśli się tego nie zrobi. to straci się adres pamięci gdzie ta zarezerwowana pamięć jest. Ja to rozumiem tak że pamięć dalej będzie zajęta przez pewne składniki dane (i nie będzie mogła być nadpisana) ,ale my utracimy do niej możliwość dostępu. (może rozumuję źle) następnie alokuję nową pamięć odpowiednio powiększoną zapisuję jej adres do starego wskaźnika i i przepisuje do niego starą wartość wyrażenia po czym zwalniam pamięć zajmowaną przez wskaźnik tymczasowy. Ponieważ funkcja odbierała wskaźnik to znaczy że w trakcie pracy funkcji modyfikowała wartość oryginalnego wskaźnika i teraz on ma tą powiększoną wartość.

Ale Ty modyfikujesz tylko lokalną kopię wskaźnika. Żeby zmodyfikować wskaźnik, musisz do funkcji przekazać wskaźnik na wskaźnik. Przy czym funkcja free() ma gdzieś czy Ty jej przekazujesz kopię lokalną czy nie i zwalnia obszar, do którego adres masz zapisany we wskaźniku. W efekcie dealokujesz pamięć, a wartość wskaźnika poza funkcją pozostaje bez zmian, zatem wskazuje on na zdealokowaną przestrzeń, lub zaalokowaną już pod inne dane. Ponadto, adres do nowozaalokowanej przestrzeni masz tylko w kopii lokalnej, do której tracisz dostęp po wyjściu z funkcji i masz dokładnie to, o czym piszesz na początku powyższego cytatu.

Polibuda napisał(a)

I to działa problem w tym że do drugiego obiegu pętli.

To Ci działa, gdyż po zdealokowaniu pamięć nie jest czyszczona i dalej możesz się do tych danych dobrać przez stary adres, tyle że nie powinieneś. Tutaj masz główny błąd i dalsze dywagacje na temat działania nie mają sensu, gdyż masz zwalone dane. Program może się zachowywać w sposób nieprzewidywalny, zawieszać się, wysypywać z błędem, generować błędne wyniki, uśmiercić chomika, ...

Polibuda napisał(a)

mógłbym to zrobić tak jak proponujesz ale nie w funkcji. Dlaczego? bo musiał bym zwrócić adres tego nowego wskaźnika a to oznacza że nie mógłbym zwolnić przydzielonej mu pamięci ,aż do instrukcji return ,a umieszczanie jej po returnie nie miało by już sensu. chyba że ja naprawdę czegoś nie rozumiem.

Nie rozumiesz. Zwalniasz tylko "starą" przestrzeń, a wskaźnik do nowej zwracasz lub zapisujesz pod w "starym" miejscu (jeśli funkcja będzie przyjmowała wskaźnik na wskaźnik). I nie musisz robić rzeźby z dwiema alokacjami. Spróbuj pokombinować sam, a jak Ci nie będzie szło, daj znać. Napiszę Ci oba warianty.

Polibuda napisał(a)

bilbosz musi być funkcja... program nie polega na takiej alokacji tylko na pobraniu imienia i nazwiska użytkownika (a potem kilka innych zadań też z wczytywaniem) ale alokowanie dwóch tablic o rozmiarze powiedzmy po 50 elementów każda i wczytywanie wartości do niej byłoby zbyt proste i nic by mnie nie nauczyło to umiem od dawna... chcę sięgnąć wyżej zrobić coś więcej niż to co wymagane:D

No to jak chcesz wyzwania, to zrób to na liście powiązanej i "kompiluj" ciąg wynikowy po pobraniu wszystkich danych ;)

0

Dziękuję koledze:) chyba już wiem o co w tym wszystkim chodzi:D Na pewno odniosę się jeszcze do odpowiedniej literatury żeby na przyszłość nie mieć takich problemów:) co do tracenia danych w funkcji myślałem że jak zwolnię pamięć przez free(); to utracę mój wczytany do tej pory string na zawsze dlatego go przepisywałem. dlatego na wszelki wypadek go zapisywałem:) Da się na tym forum przyznać jakiegoś sog'a za pomoc czy coś?? i czy może mi ktoś wyjaśnić czemu wersja "zapożyczona" z tego materiału z linku również się sypała??
Wykładowca nie czyta:D ja mu pokazuje jak działa program dostaje 2 plusy:D i mam zajęcia z głowy:D (te programy mamy robić na zajęciach) dzięki wszystkim:D

0
Polibuda napisał(a)

co do tracenia danych w funkcji myślałem że jak zwolnię pamięć przez free(); to utracę mój wczytany do tej pory string na zawsze dlatego go przepisywałem.

Utracisz go. Albo inaczej, w pamięci on będzie do czasu, aż coś innego go nie nadpisze, ale Ty powinieneś go traktować jak utracony i nie odwoływać się do niego po zdealokowaniu funkcją free().
Dobra, wkleję te dwa warianty żeby było wiadomo o co chodzi. Będzie łatwiej zrozumieć. W funkcjach użyłem strlen() do pobrania rozmiaru ciągu i strncpy() do kopiowania danych, ale sobie poradzisz z zamianą na własne funkcje. Pamiętaj tylko, że strncpy() przyjmuje odwrotną kolejność argumentów do przyjętej przez Ciebie.

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



static int  resize_ptr(char  **text, unsigned int  length)
{
    char            *ptr;
    unsigned int    newlen;


    newlen = strlen(*text) + length + 1;
    if ( (ptr = (char*)malloc(newlen)) == NULL )
        return 0;

    strncpy(ptr, *text, newlen - 1);
    free(*text);
    *text = ptr;

    return newlen;
}



static char  *resize_return(char  *text, unsigned int  length, unsigned int  *newlen)
{
    char            *ptr;


    *newlen = strlen(text) + length + 1;
    if ( (ptr = (char*)malloc(*newlen)) == NULL )
        return NULL;

    strncpy(ptr, text, *newlen - 1);
    return ptr;
}



int  main(void)
{
    char            *text, *text2;
    unsigned int    length;


    /* Przekazanie wskaźnika na wskaźnik */
    text = (char*)malloc(4);
    strncpy(text, "Ala", 3);
    printf("1a. %s (-)\n", text);

    length = resize_ptr(&text, 3);
    strncat(text, " ma", 3);
    printf("2a. %s (%d)\n", text, length);

    length = resize_ptr(&text, 5);
    strncat(text, " kota", 5);
    printf("3a. %s (%d)\n", text, length);

    free(text);

    /* Zwracanie nowego wskaźnika */
    text = (char*)malloc(4);
    strncpy(text, "Ala", 3);
    printf("1b. %s (-)\n", text);

    text2 = resize_return(text, 3, &length);
    free(text);
    strncat(text2, " ma", 3);
    printf("2b. %s (%d)\n", text2, length);

    text = resize_return(text2, 5, &length);
    free(text2);
    strncat(text, " kota", 5);
    printf("3b. %s (%d)\n", text, length);

    free(text);
    return 0;
}
0

http://4programmers.net/Forum/C_i_C++/49138-Tablica_wskaznikow?hl=realloc

post dryobatesa, nie '+n', tylko '*2'

poza tym http://4programmers.net/Forum/C_i_C++/158350-Arytmetyka_wskaznikow_-_wlasne_strcpy?hl=strcpy
a mozna jeszcze prościej (kompilator c może się burzyć, jeśli taki skondensowany zapis naruszy jakiś standard, ale w c++ zasadniczo takie konstrukcje przechodzą)

char* my_strcpy(char* dst,char* src){
  char* b=dst;
  do while((*(b++)=*(src++))); // podwójny nawias chroni przed warningiem '... parenthesis ...' (paradontozą)
  return dst;
}

char* my_strncpy(char* dst,char* src,unsigned count=(unsigned)-1){ // jeśli w wywołaniu nie podasz ostatniego parametru, to zadziała jak strcpy
  char* b=dst;
  if(count)do while((*(b++)=*(src++)) && --count); // z dst i src mozna robic wszystko, sa tymczasowe, na stosie, nie na stercie
  return dst;
}

void* my_memcpy(void* dst,void* src,unsigned n){
  char* a=(char*)src;  // char ma zawsze 1 bajt? 
  char* b=(char*)dst;
  while(n--)*(b++)=*(a++);
  return dst;
}

// a tak w ogole

char* resize_return(char* text,int deltalength,unsigned* newlen){ // int!, skoro zmieniasz rozmiar, to daj mozliwość w obie strony.
  unsigned len=strlen(text)+deltalength+1;
  char* ptr=(char*)realloc(text,len*sizeof(char)); // jeśli char zawsze i wszedzie ma 1 bajt z definicji, to można sizeof() wywalić
  if(ptr){ // jeśli się nie uda to stary adres jest wciąż aktualny 
    *newlen=len; // dopiero przypisujesz nową wartośc, jeśli się uda zaalokować pamięć
    ptr[len-1]=0; // zakonczyc ciag znakow
  }
  return prt;
}

// ... przykład użycia
unsigned len=miljart;
char* text=(char*)malloc(sizeof(char)*len);
// ...
char* p=resize_return(tekst,+20,&len)
if(p)text=p;

0

Może głupie pytanie, ale czy realokując pamięć do elementu tablicy wyrazów można przydzielić dodatkową pamięć tylko dla jednego elementu tablicy czy trzeba od razu do wszystkich? Chce sie upewnić czy każdy element tablicy musi mieć przydzielony taki sam rozmiar pamięci.

Np. Jeżeli wstępnie alokuje dla każdego wyrazu w tablicy wyrazów 5bajtów, a w trakcie działania programu użytkownik wpisze do tablicy element przekraczający zakres.

0

Możesz przydzielić pamięć "na zaś" jeśli nie wiesz ile dokładnie potrzebujesz. Najwyżej część pamięci nie będzie użyta. Nie szastaj jednak zasobami. Alokowanie 1MB na pobranie odpowiedzi od użytkownika to raczej nie jest dobry pomysł. Często też da się albo określić dokładny rozmiar danych, albo górny limit wielkości, jaki mogą przyjąć dane wejściowe.

Jeśli użytkownik wpisze więcej elementów niż jesteś w stanie pomieścić w przeznaczonym na to bloku pamięci, to mogą się dziać straszne rzeczy. Język C nie zabroni Ci tego, dlatego trzeba się pilnować i nie używać funkcji typu gets czy scanf gdzie nie masz kontroli nad zakresami. A co się może stać? Poniżej masz przykładowy kod. Pytanie: ile razy wykona się pętla for? Najpierw spróbuj odpowiedzieć na to pytanie bez kompilowania i uruchamiania kodu :)

#include <stdio.h>
#include <string.h>


int  main(void)
{
    char    text[24];
    int     cnt;
    int     i;


    cnt = 3;
    strcpy(text, "Ala ma kota, a kot ma Ale");

    for ( i = 0; i < cnt; i++ )
        printf("%d\n", i);

    return 0;
}

Tak, to jest błąd programisty (nie języka). Nie, kompilator nie będzie krzyczał, nawet jak w GCC włączysz flagę -Wall.

0

Noo wydaje się, że to że tekst "Ala ma kota.." jest za dlugi i przekracza zakres nie ma wpływu na petle, ktora wykona sie 3 razy.. Myle sie?:P

0

Tablica text moze pomiescic 24 znaki, podczas gdy ty kopiujesz do niej >24 znaki. Rozważ to

0

Nie kopiuje:D może jestem świeżak ,ale błędy przekroczenia zakresu sprawdzam w pierwszej kolejności. Tablica może pomieścić 25 znaków 20+5 = 25:) a poza tym błąd
ujawnia się nie przy próbie wpisania wartości ,lecz przy alokacji pamięci.. jednym słowem mam 99% pewności że to nie przekroczenie zakresu:)

0

Sorki myślałem że to jeszcze do mojego problemu)

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