I am writing a method that has to do with strings and I was stuck on how to go about coding this. Any help getting it started or tips at all would be great. Thanks.


MyString::MyString(const char* s)

This constructor takes a pointer to a constant C-style string as its argument. It should set the size of the string to the number of characters in the C-style string (not including the null character), allocate a string text array of that size, and then copy the characters of the C-style string into the string text array.

For getting the size, you can already use the strlen function:

size_t sz;
sz = strlen(s);

You can use new[] and delete[] for the memory allocation to hold the desired string.

After that, you copy the string passed via the argument to the newly allocated memory, use strcpy.

Note: Within your object you'll do some dynamic memory allocation.
You'll probably want to implement a destructor, a copy constructor, and overload the assignment operator as well.

You probably already know this but don't forget the +1 in the allocation for storing the terminator.

sz = strlen( s );
char *p = new char[ sz+1 ]

Ya i'll be writing a destructor, copy constructor, and overload methods as the program goes on. This is what I have came up with for this method I feel like the third like in the method is incorrect.

MyString::MyString(const char* s)
        {
        stringSize = strlen(s);
        new char[stringSize];
        strcpy (char[stringSize, s);
        }

Corrections:

MyString::MyString(const char* s)
{
    [B]// don't forget the type:[/B]
    [B]size_t[/B] stringSize = strlen(s);

    [B]// you need a pointer to the newly allocated memory:[/B]
    [B]// don't forget to allocate memory for the null-terminator as well:[/B]
    [B]char *p[/B] = new char[stringSize[B]+1[/B]];

    strcpy ([B]p[/B], s);
}

What Tux4Life said!

But would make sense to store the string size so future strlen() requests of your string in class only needs to return the value. Not look it up!

MyString::MyString(const char* s)
{
        stringSize = strlen(s);
        szString = new char[ stringSize + 1];
        strcpy ( szString, s );
}
Comments
Yes that would be better :)

For my stringSize I have the type declared as a char* in my header file so I would use that instead of size_t correct? Also the char* p I just create within the method right so it can hold the new array?

>For my stringSize I have the type declared as a char* in my header file so I would use that instead of size_t correct?
Nope, to store a size, you don't use a char pointer, instead you use size_t (you can compare it to an unsigned int).

Awesome thanks for the help guys, got that working, might be back with a few questions later.

Alright came across an issue with overloading this is the first time I have done any operator overloading so bare with me haha.

This is what it is suppose to do.

const MyString& operator=(const char* rightOp)

The assignment operator should also be overloaded to allow assignment of a C-style string to a MyString object.

This is what I got and I am getting quite a few errors.

const MyString& MyString::operator=(const char* rightOp)
        {
        if(this != *rightOp)
                {
                delete[] stringStorage;
                stringStorage = new char[rightOp.stringSize];
                for(int = 0; i < rightOp.stringSize; i++)
                        stringStorage[i] = rightOp.stringStorage[i];
                stringSize = rightOp.stringSize;
                }
        return *this;
        }

Without listing the first few errors you receive it's not possible to say with surety what you have going. However, the object you have used called this is a pointer and rightOp is apparently a C styled string. As such you can't derefernce a C styled string. What you probable want is to see if the address stored in this and the address of rightOp are the same address (ie, are the same object).

Sorry about that the errors I am getting are listed below. Thanks.

MyString.cpp: In member function âconst MyString& MyString::operator=(const char*)â:
MyString.cpp:59: error: ISO C++ forbids comparison between pointer and integer
MyString.cpp:62: error: request for member âstringSizeâ in ârightOpâ, which is of non-class type âconst char*â
MyString.cpp:63: error: request for member âstringSizeâ in ârightOpâ, which is of non-class type âconst char*â
MyString.cpp:64: error: request for member âstringStorageâ in ârightOpâ, which is of non-class type âconst char*â
MyString.cpp:65: error: request for member âstringSizeâ in ârightOpâ, which is of non-class type âconst char*â

Yup, that's what the first error message says to me. You could try something like this:

if(this != rightOp)

sinc the name of an array acts as an address for the first element of that array. Hopefully they will allow comparisons of two addresses. If that doesn't work, then someone else can probably give you the correct version.

Alternatively, since this will never be a simple C Style string it can never have the same address as a C Style string and therefore you could probably get by without the comparison. If you are assigning one MyString to another, however, then it could in theory be the same address, so looking for identity is recommended.

I went ahead and got rid of the comparison because I was looking through notes and saw that in this case it is not needed. Still having issues with the other errors though. I'm going to keep playing with it though, I'll be on here if anyone has anymore advice. Thanks!

MyString::MyString(const char* s)

This constructor takes a pointer to a constant C-style string as its argument. It should set the size of the string to the number of characters in the C-style string (not including the null character), allocate a string text array of that size, and then copy the characters of the C-style string into the string text array.

I was told strcpy does not work for this method and that I for loop should be used. I get everything coded correctly except the for loop which has me a bit confused. Any suggestions?

MyString::MyString(const char* s)
        {
        size_t stringSize = strlen(s);
        *stringStorage = new char[stringSize+1];
        for(int i = 0; stringSize > stringStorage; i++)
                char[stringSize+1] = s;
        }

>It should set the size of the string to the number of characters in the C-style string (not including the null character), allocate a string text array of that size, and then copy the characters of the C-style string into the string text array.

Why would someone want to do that?
You have to allocate space for the null terminator as well.
Otherwise you'll run into problems while displaying the string using cout for example.

I am certainly no expert in STL, but it is my understanding that the const char * embedded in the STL string class isn't necessarily implemented as a C style string----that is, it isn't necessarily a null terminated char array. To output such an object you could overload the << operator using a loop in the method body to display each char separately, just like you could use a loop rather than strcpy() to assign/copy the object. I suspect if you look under the hood of strcpy() you will find a loop as well, but we're even further out of my surety level on that speculaton. The only reason to do this that I can think of is to make the STL string object independent of any C coding requirements. Independent confirmation not a bad idea before spreading this around too far is a good idea.

Comments
You've got a point there :)

Well, as long as you hold the correct number of characters in a variable, this would be no problem, but a null-terminator takes 1 byte extra space, and you won't have to add several other routines to make the string display correctly on the screen.

But, of course, if his assignment is to do it without a null-terminator, then my advise probably doesn't make much sense :)

>The only reason to do this that I can think of is to make the STL string object independent of any C coding requirements.
Yeah, probably his teacher wants that he avoids functions from the standard function library.

Ya I don't know why he wants us to ignore the null terminator but he does. So I am at a standstill with this for now I guess. any idea how I could code this for loop? I cant really go any farther without it.

These are the three files I have for this program so far I am also getting a segmentation fault error, so if anyone is willing to look at these that be great. I attached them to this post with the link to the assignment if needed. Also, assign3.cpp is given by my teacher so I did not have to do with the coding on that.

http://www.cs.niu.edu/~mcmahon/cs241/Assign/as3241m09.html

Attachments
/*********************************************************************
CSCI 241 Assignment 3

Programmer: your name
Logon ID:   your z-id
Date Due:   7/13/2009

Purpose: This driver program tests the MyString class.
*********************************************************************/

#include "MyString.h"
#include <iostream>

using namespace std;

int main()
   {
   int test = 1;

   cout << "Test " << test++ << ": Constructors and printing\n" << endl;

   const MyString  s1, s2("Hello");

   cout << "s1: " << s1 << endl;
   cout << "s2: " << s2 << endl;

   cout << "\nTest " << test++ << ": Size\n" << endl;

   cout << "s1 contains " << s1.size() << " characters\n";
   cout << "s2 contains " << s2.size() << " characters\n";

   cout << "\nTest " << test++ << ": String concatenation\n" << endl;

   const MyString s3("bye"), s4("world");

   cout << "s3: " << s3 << endl;
   cout << "s4: " << s4 << endl << endl;

   cout << "s1 + s4 is " << s1 + s4 << endl;
   cout << "\"good\" + s3 is " << "good" + s3 << endl;
   cout << "s4 + \"ly\" is " << s4 + "ly" << endl;
   cout << "s2 + \", \" + s4 is " << s2 + ", " + s4 << endl;
      
   cout << "\nTest " << test++ << ": Subscripting\n" << endl;

   const MyString s5("hot dog");
   MyString s6("cough");

   cout << "s5: " << s5 << endl;
   cout << "s6: " << s6 << endl;

   cout << "\ns5[0] = " << s5[0] << endl;
   cout << "s5[3] = " << s5[3] << endl;
   cout << "s5[6] = " << s5[6] << endl;

   cout << "\ns6[0] = " << s6[0] << endl;
   cout << "s6[1] = " << s6[1] << endl;

   s6[0] = 'l';
   s6[1] = 'a';

   cout << "\ns6: " << s6 << endl;

   cout << "\nTest " << test++ << ": Equality\n" << endl;

   const MyString s7("good"), s8("bye");

   cout << s7 << " and " << s7 << " are ";

   if (s8 == s3)
      cout << "equal" << endl;
   else
      cout << "not equal" << endl;

   cout << s7 << " and " << s8 << " are ";

   if (s7 == s8)
      cout << "equal" << endl;
   else
      cout << "not equal" << endl;

   cout << "\nTest " << test++ << ": Copy constructor\n" << endl;

   MyString s9 = s5;
   MyString* s10 = new MyString(s6);
   
   cout << "s9: " << s9 << endl;
   cout << "s10: " << *s10 << endl;

   cout << "\nTest " << test++ << ": Assignment operators\n" << endl;
   
   MyString s11;

   s9 = s4;
   *s10 = *s10;
   s11 = *s10 = s2;

   cout << "s9: " << s9 << endl;
   cout << "s10: " << *s10 << endl;
   cout << "s11: " << s11 << endl;

   s9 = "This is some new text";

   cout << "\ns9: " << s9 << endl;

   cout << "\nTest " << test++ << ": Destructor\n" << endl;

   delete s10;

   cout << "s9: " << s9 << endl;
   cout << "s11: " << s11 << endl;

   return 0;
   }
/****************************************************************
   FILE:      MyString.cpp
   AUTHOR:    Justin R. Smith
   LOGON ID:  Z136340
   DUE DATE:  7/13/2009

   PURPOSE:   Contains method implications for the MyString class.
****************************************************************/

#include "MyString.h"
#include <iostream>
#include <iomanip>
#include <cstring>

using namespace std;

	MyString::MyString()
	{
	stringStorage = 0;
	stringSize = NULL;
	}

	MyString::MyString(const char* s)
	{
	size_t stringSize = strlen(s);			
	stringStorage = new char[stringSize+1];
//	for(int i = 0; stringSize > stringStorage; i++)
//		char[stringSize+1] = s;
	}
	
	MyString::MyString(const MyString& oldMyString)
	{
	
	stringStorage = new char[oldMyString.stringSize];
	for(int i = 0; i < oldMyString.stringSize; i++)
		stringStorage[i] = oldMyString.stringStorage[i];
	stringSize = oldMyString.stringSize;
	}

	MyString::~MyString()
	{
	delete[] stringStorage;
	}	

	const MyString& MyString::operator=(const MyString& rightOp)
	{
	if(this != &rightOp)
		{
		delete[] stringStorage;
		stringStorage = new char[rightOp.stringSize];
		for(int i = 0; i < rightOp.stringSize; i++)
			stringStorage[i] = rightOp.stringStorage[i];
		stringSize = rightOp.stringSize;
		}
	return *this;
	}

	const MyString& MyString::operator=(const char* rightOp)
	{
	int i = 0;

	if (NULL != stringStorage)
	{
		delete[] stringStorage;
	}
	stringSize = strlen( rightOp );

	stringStorage = new char[ stringSize + 1 ];

	for( i = 0; i < stringSize; i++)
		stringStorage[i] = rightOp[i];

	stringStorage[i] = 0;	
	return *this;
	}

	ostream& operator<<(ostream& osObject, const MyString& rightOp)
	{
	int i;
	for (i = 0; i < rightOp.stringStorage[i]; i++);
		cout << rightOp.stringStorage[i];
	return osObject;
	}
	
	int MyString::size() const
	{
	return stringSize;
	}

	MyString MyString::operator+(const MyString& rightOp) const
	{
	strcat(this->stringStorage, rightOp.stringStorage);
	return *this;
	}

	MyString MyString::operator+(const char* rightOp) const
	{
	strcat(this->stringStorage, rightOp);
	return *this;
	}

	MyString operator+(const char* leftOp, const MyString& rightOp)
	{
	MyString result; 
	result.stringSize = strlen(leftOp) + rightOp.stringSize;
	new char[result.stringSize];
	return result;		
	}

	char MyString::operator[](int ndx) const
	{
	return stringStorage[ndx];
	}

	char MyString::operator[](int ndx)
	{
	return stringStorage[ndx];
	}
	
	bool MyString::operator==(const MyString& rightOp) const		
	{
	if(strcmp(stringStorage, rightOp.stringStorage) == 0 && strlen(stringStorage) == strlen(rightOp.stringStorage))
		return true;
	else
		return false;
	}
/****************************************************************
   FILE:      MyString.h
   AUTHOR:    Justin Smith
   LOGON ID:  Z136340
   DUE DATE:  7/13/09

   PURPOSE:   does the declarion of the class MyString
****************************************************************/

#ifndef MYSTRING_H
#define MYSTRING_H
#include <iomanip>
#include <iostream>

using namespace std;
class MyString
	{
	friend ostream& operator<<(ostream&, const MyString&);
	friend MyString operator+(const char*, const MyString&);

	private:
		char* stringStorage;
		int stringSize;
	public:
		MyString();
		MyString(const char*);
		MyString(const MyString&);
		~MyString();
		const MyString& operator=(const MyString&);
		const MyString& operator=(const char*);
		int size() const;
		MyString operator+(const MyString&) const;
		MyString operator+(const char* rightOp) const;
		char operator[](int ndx) const;
		char operator[](int ndx);
		bool operator==(const MyString&) const;
	};

#endif /* MYSTRING_H */

Ya I don't know why he wants us to ignore the null terminator but he does. So I am at a standstill with this for now I guess. any idea how I could code this for loop? I cant really go any farther without it.

Well, first you need to create a good skeleton for your for-loop:

for(size_t i = 0; i < sz; ++i) {
   // Other code here        
}

This for-loop will run the same amount of times, as the amount of characters there are in the original string (null terminator not included).
This is exactly what we need.

Now we have the for-loop skeleton, we can start adding features to copy the whole thing to a non null-terminated character array inside the class:

// Our copy routine:
for(size_t i = 0; i < sz; ++i) {
   p[i] = original[i];
}

In the above example I assume that p is a pointer to the newly allocated memory to hold the non-null-terminated copy of the original string.
original in my example is the string you pass via the class' constructor.
sz is the value you get by using the strlen-function like this: sz = strlen(original); (I want to note that sz has size_t as it's type).

According to the fact that your program gives a segmentation fault, I would suggest you to comment out all the features you haven't implemented yet, that will make it easier to track down the bug.

Alright will try that I'm working on that for loop right now so i'll get back to ya on that.

This is what I ended up doing for that for loop and got no errors. This is the code for the whole method.

MyString::MyString(const char* s)
        {
        size_t stringSize = strlen(s);
        stringStorage = new char[stringSize+1];
        for(size_t i = 0; i < stringSize; i++)
                stringStorage[i] = s[i];
        }

It seems like segmentation fault starts here

cout << "s1: " << s1 << endl;
   cout << "s2: " << s2 << endl;

should i post my overload operator code for that to see if that is the problem?

It seems like segmentation fault starts here

cout << "s1: " << s1 << endl;
   cout << "s2: " << s2 << endl;

should i post my overload operator code for that to see if that is the problem?

Yes please.

BTW, the +1 here (look at your constructor) is optional, and may be left out.
As you told yourself, your teacher requires you to do it without allocating memory for the null terminator:
so stringStorage = new char[stringSize+1]; would become stringStorage = new char[stringSize]; then :)

this is my overload

ostream& operator<<(ostream& osObject, const MyString& rightOp)
        {
        int i;
        for (i = 0; i < rightOp.stringStorage[i]; i++)
                cout << rightOp.stringStorage[i];
        return osObject;
        }

ostream& operator<<(ostream& osObject, const MyString& rightOp)

The stream insertion operator should be overloaded so that a Mystring can be sent to the standard output. This function should loop through the characters of the string text array and print them out one at a time.

This operator function must be implemented as a standalone function. Make the function a friend of the MyString class.

Well, this line will cause a segmentation fault: for (i = 0; i < rightOp.stringStorage[i]; i++) (If a null terminator had existed at the end of the string, this line wouldn't cause a segmentation fault)

The result is that rightOp.stringStorage will always be evaluated to true, bringing your program into a never ending loop.
(In case of coincidence, your program might come across a null terminator, before it actually starts trying to access any other data which it isn't allowed to access, but this is very rare)

So my advice: fix it! :P

would it have something to do with using the osObject within the loop?

would it have something to do with using the osObject within the loop?

No, just let that loop run the same amount of times, as there are characters in the string.

I just see that you'll have to make variable stringSize a private data member of your class, so your other methods can access the stringSize variable too.

Assuming that you make the additional fixes, your constructor would now look like:

MyString::MyString(const char* s)
{
  stringSize = strlen(s);
  stringStorage = new char[stringSize];
  
  for(size_t i = 0; i < stringSize; i++)
      stringStorage[i] = s[i];
}

But remember to put the following declaration: size_t stringSize in the private section of your class.

I have stringSize declared as an int in my private section already just change that to size_t?

This article has been dead for over six months. Start a new discussion instead.