• 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
417 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,073 wizyt
0 głosów
2 odpowiedzi 280 wizyt
pytanie zadane 13 maja 2019 w C i C++ przez antek97 Nowicjusz (220 p.)
0 głosów
1 odpowiedź 291 wizyt
pytanie zadane 7 kwietnia 2023 w C i C++ przez Zuzan Początkujący (390 p.)

92,661 zapytań

141,556 odpowiedzi

319,998 komentarzy

62,028 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

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!

...