String operator overload problem

Hi, I've got a task to write a prototype of string class, but I'm stuck with the '>>' operator.

This is how it looks now:
1
2
3
4
std::istream& operator>>(std::istream& in, typeString& toload) {
    in >> toload.content;
    return in;
}


But of course, when I want to
1
2
typeString example;
std::cin >> example;


When I was debugging the problem occured in line with 'in >> toload.content'.
There is an error: "Exception thrown: write access violation." I don't know how to do this properly. What is wrong?
Thanks
Last edited on
¿what's `content'? ¿does it have enough space?
When I was debugging the problem occured in line with 'in >> toload.content'.
So, what is content?
You really need to give us more code. Based on the 6 lines you've shown us, I have the following questions:

1. What type is content?
2. Is content public, protected or private?
3. Is operator>> a friend of typeString?
4. What istream object did you pass to the 'in' argument?
5. How was the istream object created and initialized?

These questions all require additional code to answer.

It would be helpful to us is you created a program containing just enough code to reproduce the problem (strip out everything else that doesn't affect the problem) and post it here. Make sure the program compiles and runs to produce the problem.
Hi, thank you for answers. I didn't think about how little information I gave, sorry.
There is the part of the code which contains just enough to reproduce the problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <iostream>
#define N 100000

class typeString {
public:
    int length;
    char* content;
    char& operator[](int index);
    const char& operator[](int index) const;
    typeString& operator =(const typeString& source);
    void swap(typeString& other);
    friend std::ostream& operator <<(std::ostream& out, const typeString& towrite); //friend??
    friend std::istream& operator >>(std::istream& in, typeString& toload);

    typeString(const typeString& source);
    typeString(const char*);
    typeString();
    ~typeString();
};

char& typeString::operator[](int index)
{
    return content[index];
}

const char& typeString::operator[](int index) const
{
    return content[index];
}

typeString::typeString() {
    content = 0;
    length = 0;
}

typeString::~typeString() {
    delete[] content;
}

typeString::typeString(const typeString& source) //copy
{
    length = source.length;
    content = new char[length + 1];
    for (int k = 0; k < length; k++)
        content[k] = source.content[k];

    content[length] = '\0';
}

void typeString::swap(typeString& other)
{
    // ... swap the lengths and pointers ...
}

typeString& typeString::operator=(const typeString& other)
{
    if (this != &other)
    {
        typeString temp(other);
        swap(temp);
    }
    return *this;
}

int charLength(const char* number) {
    int c = 0;
    while (*(number++)) c++;
    return c;
}

typeString::typeString(const char* number) {
    length = charLength(number);
    content = new char[length + 1];
    for (int k = 0; k < length; k++)
        content[k] = number[k];

    content[length] = '\0';
}

std::ostream& operator<<(std::ostream& out, const typeString& towrite) {
    out << towrite.content;
    return out;
}

std::istream& operator>>(std::istream& in, typeString& toload) {
    in >> toload.content;
    return in;
}

class numberData {
public:
    int index = 0;
    typeString thisNumber;
    numberData* nextNumber = NULL;
};

numberData* createNext(typeString sentNumber)
{
    numberData* newData = new numberData();
    newData->thisNumber = sentNumber;
    newData->nextNumber = NULL;
    return newData;
}

void addNumber(numberData** myData, typeString thisNumber)
{
    static int index = 0;

    numberData* newData = createNext(thisNumber);
    newData->thisNumber = thisNumber;
    newData->nextNumber = *myData;
    newData->index = index++;
    *myData = newData;
}

void readNumbers(numberData** myData)
{
    std::cout << "How many numbers to read? : ";
    int n;
    do {
        std::cin >> n;
        if (n > 100000 || n < 1)
            std::cout << "ERROR: value between 0 and 100 000. Load again. " << std::endl;
    } while (n < 1 || n > N);

    typeString number;
    while (n-- > 0)
    {
        std::cin >> number;
        addNumber(myData, number);
    }
}

int main()
{
    numberData* myData = NULL;
    readNumbers(&myData);
    return 0;
}


The problem appears when I want to cin a number. So, answering questions:
1 and 2. content is char* content to save number and it's public
3. Operator >> is friend of typeString, but to be honest I don't know why it should be a friend, but without it there is an error "too many parameters for this operator function".
4. I wanted to pass char* content to save it as a string
5. added code
OK.
myData is NULL in line 136.
You pass an address to myData (which contains NULL) to readNumbers.
You pass the same address (which still contains NULL) to addNumber.

In line 113 you dereference myData and try to assign newData to it. However, the contents of myData is NULL, so you are trying to assign to the NULL pointer. (Edit: there is no object at *myData to assign to.)

Instead, change line 113 to
myData = &newData;

Even better, make myData a reference to a pointer.

Last edited on
Line 126 creates the object number where number.content is nullptr.

On Line 129/86 you try to write data to the nullptr which will crash. Before you execute line 86 you need to make sure that you have a sufficient large buffer/content to write the data to.
@coder777, but how to have a buffer large enough to write string of any length? I need it to work like std::cin >> std::string.

@doug4, I'm not sure if I get it fully, but if what I pass is NULL, should I pass instead not an address of myData but exactly myData to those functions?
When I change line 113 the same error occurs. I don't know if it matters, but when I used normal std::string from <string> library everything worked fine, I don't know where is the problem in class typeString.
The only way I know to do that is to have your class attempt to read from cin up to a fixed number of bytes and if it exceeds that, stop, reallocate more space, and read more.

I think this may be what you need (?)

std::cin.read(&buf, available_size);
but that isnt going to stop on whitespace the way cin does, you may need to dig into the lower level objects behind cin to see if you can find something that will read up to N bytes, whitespace delimited, and loop that increasing your memory as you go until its all worked out.

alternately, you can allocate some stupidly large thing that is as big as you want to support, read into it, get its length, allocate twice that to your object (or whatever, giving yourself a little room to grow/edit/etc), copy the data, toss the oversized buffer (or keep it forever as static to re-use for performance?) and call it good. Its simple, and it will work for most applications.
Last edited on
I'm not sure exactly what you are asking.

I can think of a number of ways to do what you want. Here are 5 of them. I prefer them in the order that I present them (number 1. is my most preferred).

1. Just return the object from the function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

class MyClass
{
public:
    int value;
};

MyClass func()
{
    MyClass x;
    x.value = 10;
    return x;
}

int main()
{
    MyClass x = func();
    std::cout << x.value;

    return 0;
}


2. Pass an object reference to the function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

class MyClass
{
public:
    int value;
};

void func(MyClass& x)
{
    x.value = 10;
}

int main()
{
    MyClass x;
    func(x);
    std::cout << x.value;

    return 0;
}


3. Pass a reference to an object pointer to the function (function creates dynamic object)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

class MyClass
{
public:
    int value;
};

void func(MyClass*& x_ptr)
{
    x_ptr = new MyClass;
    x_ptr->value = 10;
}

int main()
{
    MyClass* x_ptr = NULL;
    func(x_ptr);
    std::cout << x_ptr->value;
    delete x_ptr;

    return 0;
}


4. Pass an object pointer to the function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

class MyClass
{
public:
    int value;
};

void func(MyClass* x_ptr)
{
    x_ptr->value = 10;
}

int main()
{
    MyClass x;
    func(&x);
    std::cout << x.value;

    return 0;
}


5. Pass a pointer to a pointer to an object to the function (function creates dynamic object)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

class MyClass
{
public:
    int value;
};

void func(MyClass** x_ptr_ptr)
{
    MyClass* newPtr = new MyClass;
    newPtr->value = 10;
    *x_ptr_ptr = newPtr;
}

int main()
{
    MyClass* x_ptr = NULL;
    func(&x_ptr);
    std::cout << x_ptr->value;
    delete x_ptr;

    return 0;
}


Note: It is better to use std::make_unique than 'new'.

Note 2: This in no way resolves the issues that coder777 brought up.
Hey, I forgot to answer earlier, but somehow I managed to make everything work with your help... Probably there are still some bugs and problems, but what I need for now is okay. Thanks so much.
Topic archived. No new replies allowed.