• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Problem z alokacją pamięci

Object Storage Arubacloud
0 głosów
395 wizyt
pytanie zadane 1 marca 2019 w C i C++ przez Hailon Początkujący (310 p.)

Witam

W trakcie wykonywania programu w konsoli otrzymuje komunikat o treści.

Przykładowe uruchomienie programu:

Podaj swoje imie: Jan Kowalski
Mam na imie Jan Kowalski.
Ciag
MAM NA IMIE JAN KOWALSKI I UCZE SIE C++.
zawiera 4 'A'.
terminate called after throwing an instance of 'St9bad_alloc'
  what():  std::bad_alloc

Process returned 3 (0x3)   execution time : 14.780 s
Press any key to continue.

Header:

// string2.h -- poprawiona i uzupe³niona implementacja klasy reprezentuj¹cej
// ci¹gi znaków
#ifndef STRING2_H_INCLUDED
#define STRING2_H_INCLUDED
#include <iostream>
using std::ostream;
using std::istream;

class String
{
    private:
        char * str;             // wskaŸnik ci¹gu
        int len;                // d³ugoœæ ci¹gu
        static int num_strings; // liczba obiektów klasy
        static const int CINLIM = 80; // limit d³ugoœci ci¹gu na wejœciu
    public:
        // konstruktory i pozosta³e metody klasy
        String(const char * s);   // konstruktor
        String();                 // konstruktor domyœlny
        String(const String &);   // konstruktor kopiuj¹cy
        ~String();                // destruktor
        int length () const { return len; }
        String & stringlow();
        String & stringup();
        int has(char);
        // metody przeci¹¿aj¹ce operatory
        String & operator=(const String &);
        String & operator=(const char *);
        String & operator+(const String & st1);
        char & operator[](int i);
        const char & operator[](int i) const;
        // funkcje zaprzyjaŸnione przeci¹¿aj¹ce operatory
        friend bool operator<(const String &st, const String &st2);
        friend bool operator>(const String &st1, const String &st2);
        friend bool operator==(const String &st, const String &st2);
        friend String & operator+(char *, String & st1);
        friend ostream & operator<<(ostream & os, const String & st);
        friend istream & operator>>(istream & is, String & st);
        // metoda statyczna
        static int HowMany();
};


#endif // STRING2_H_INCLUDED

Definicje:

// string2.cpp -- implementacje metod klasy String
#include <cstring>    // albo string.h
#include "string2.h"
#include <cctype>
using std::cin;
using std::cout;

// inicjalizacja statycznej sk³adowej klasy
int String::num_strings = 0;

// metoda statyczna
int String::HowMany()
{
    return num_strings;
}

int String::has(char s)
{
    int total = 0;
    for(int i = 0; i < len; i++)
    {
        if(str[i] == s)
            total++;
    }
    return total;
}

// metody klasy
String::String(const char * s)          // konstruuje obiekt String z ci¹gu C
{
    len = std::strlen(s);               // ustawienie d³ugoœci ci¹gu
    str = new char[len + 1];            // przydzia³ pamiêci
    std::strcpy(str, s);                // inicjalizacja wskaŸnika ci¹gu
    num_strings++;                      // aktualizacja licznika obiektów
}

String::String()                        // konstruktor domyœlny
{
    len = 4;
    str = new char[1];
    str[0] = '\0';                      // domyœlny ci¹g obiektów klasy
    num_strings++;
}

String::String(const String & st)
{
    num_strings++;                      // aktualizacja sk³adowej statycznej
    len = st.len;                       // ta sama d³ugoœæ ci¹gu
    str = new char [len + 1];           // przydzia³ pamiêci
    std::strcpy(str, st.str);           // skopiowanie ci¹gu
}

String::~String()                        // destruktor (niezbêdny)
{
    --num_strings;                       // koniecznie
    delete [] str;                       // koniecznie
}

// metody przeci¹¿aj¹ce operatory
// przypisywanie obiektu klasy String do innego obiektu tej klasy
String & String::operator=(const String & st)
{
    if (this == &st)
        return *this;
    delete [] str;
    len = st.len;
    str = new char[len + 1];
    std::strcpy(str, st.str);
    return *this;
}

// przypisywanie ci¹gu C do obiektu klasy String
String & String::operator=(const char * s)
{
    delete [] str;
    len = std::strlen(s);
    str = new char[len + 1];
    std::strcpy(str, s);
    return *this;
}

String & String::operator+(const String & st1)
{
    len += st1.len;
    str = std::strcat(str, st1.str);
    return *this;
}

String & operator+(char * s, String & st1)
{
    st1.len += std::strlen(s);
    st1.str = std::strcat(s, st1.str);
    return st1;
}

String & String::stringlow()
{
    for(int i = 0; i < len; i++)
    {
        if(isupper(str[i]))
            str[i] = tolower(str[i]);
        else
            continue;
    }
    return *this;
}

String & String::stringup()
{
     for(int i = 0; i < len; i++)
    {
        if(islower(str[i]))
            str[i] = toupper(str[i]);
        else
            continue;
    }
    return *this;
}

// pe³ny dostêp do znaków ci¹gu (dla obiektów zwyk³ych)
char & String::operator[](int i)
{
    return str[i];
}

// dostêp (do odczytu) do znaków ci¹gu (dla obiektów const)
const char & String::operator[](int i) const
{
    return str[i];
}

// zaprzyjaŸnione funkcje przeci¹¿aj¹ce operatory
bool operator<(const String &st1, const String &st2)
{
    return (std::strcmp(st1.str, st2.str) < 0);
}

bool operator>(const String &st1, const String &st2)
{
    return st2 < st1;
}

bool operator==(const String &st1, const String &st2)
{
    return (std::strcmp(st1.str, st2.str) == 0);
}

// wyprowadzenie ci¹gu na wyjœcie
ostream & operator<<(ostream & os, const String & st)
{
    os << st.str;
    return os;
}

// wczytywanie ci¹gu z wejœcia (uproszczone)
istream & operator>>(istream & is, String & st)
{
    char temp[String::CINLIM];
    is.get(temp, String::CINLIM);
    if (is)
        st = temp;
    while (is && is.get() != '\n')
        continue;
    return is;
}

Funkcja main:

#include "string2.h"
using namespace std;

int main()
{
    String s1(" i ucze sie C++.");
    String s2 = "Podaj swoje imie: ";
    String s3;
    String s4("Mam na imie ");
    cout << s2;
    cin >> s3;
    s2 = s4 + s3;
    cout << s2 << ".\n";
    s2 = s2 + s1;
    s2.stringup();
    cout << "Ciag\n" << s2 << "\nzawiera " << s2.has('A')
         << " 'A'.\n";
    s1 = "czerwona";
    String rgb[3] = { String(s1), String("zielona"), String("niebieska")};
    cout << "Podaj nazwe barwy podstawowej: ";
    String ans;
    bool success = false;
    while (cin >> ans)
    {
        ans.stringlow();
        for(int i = 0; i <3; i++)
        {
            if (ans == rgb[i])
            {
                cout << "Prawidlowo!\n";
                success = true;
                break;
            }
        }
        if (success)
                break;
            else
                cout << "Sprobuj ponownie!\n";
    }
    cout << "Zegnam\n";
    return 0;
}

Proszę o jakieś wskazówki ;)

1 odpowiedź

+1 głos
odpowiedź 1 marca 2019 przez j23 Mędrzec (194,920 p.)
edycja 1 marca 2019 przez j23
  • Linia 39: dlaczego 4, a nie 0?
  • Linie 85 i 92: strcat dołącza jeden c-string do drugiego, nie przydziela nowej odpowiednio dużej pamięci. Oba operatory+ powinny zwrócić nowy obiekt klasy String będący sumą obu operandów.
  • dziwny ten operator wejścia...
komentarz 1 marca 2019 przez Hailon Początkujący (310 p.)

Hmm... Spróbowałem coś takiego, ale w takim przypadku program całkowicie sie wykrzacza :/

Do tego doszło ostrzeżenie od kompilatora w związku z próbą zwrócenia wartości lokalnej :/

String & String::operator+(const String & st1)
{
    String sum;
    sum.len = st1.len + len;
    sum.str = std::strcat(str, st1.str);
    return sum;
}

String & operator+(char * s, String & st1)
{
    String sum;
    sum.len = st1.len + std::strlen(s);
    sum.str = std::strcat(s, st1.str);
    return sum;
}

 

1
komentarz 1 marca 2019 przez j23 Mędrzec (194,920 p.)
String String::operator+(const String & st1) const
{
	String sum;

	delete[] sum.str; // patrz domyślny ctor

	sum.len = st1.len + len;
	sum.str = new char[sum.len + 1];
	auto p = std::copy_n(str, len, sum.str);
	*std::copy_n(st1.str, st1.len, p) = 0;
	return sum;
}
 
String operator+(const char *s, const String & st1) const
{
	String sum;

	delete[] sum.str;  // patrz domyślny ctor

	auto s_len = strlen(s);
	sum.len = st1.len + s_len;
	sum.str = new char[sum.len + 1];
	auto p = std::copy_n(s, s_len, sum.str);
	*std::copy_n(st1.str, st1.len, p) = 0;
	return sum;
}

 

komentarz 1 marca 2019 przez Hailon Początkujący (310 p.)
O kurcze, kompletnie zapomniałem, o przydziale nowej pamięci ;)

Dzieki bardzo za pomoc! :)
1
komentarz 1 marca 2019 przez j23 Mędrzec (194,920 p.)
Problemem był nie tylko przydział pamięci, ale też to, że zwracałeś referencję na obiekt lokalny, co nawet przy poprawnie zrobionym przydzielaniu pamięci wywracałoby program.

 

Popraw też punkt pierwszy i przemyśl sensowność operatora >> (chyba że to jakiś wymóg).

Podobne pytania

0 głosów
1 odpowiedź 1,052 wizyt
0 głosów
2 odpowiedzi 268 wizyt
pytanie zadane 13 maja 2019 w C i C++ przez antek97 Nowicjusz (220 p.)
0 głosów
1 odpowiedź 277 wizyt
pytanie zadane 7 kwietnia 2023 w C i C++ przez Zuzan Początkujący (390 p.)

92,565 zapytań

141,416 odpowiedzi

319,596 komentarzy

61,948 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...