danie
danie

Reputation: 31

C++ Pascal Strings errors. I cannot find the error in my code

Below is my code and then below that the error message. I would appreciate any help. Thank you. The Assignment is as follows:

Modify the provided String class to internally store Pascal strings, which are character arrays that start with a number of characters in the string, followed by those characters, with no terminating null character. That is:

  • str should contain a Pascal string.
  • The constructor created in your Pascal string lab should be included. The normal C-string constructor should also be included, and must convert to Pascal string.
  • The c_str function must convert back to a C string to provide a C string to the user. It is okay to allocate the memory for the string in this function.
  • All other functions must perform correctly given the change to the internal string format.
  • You may not store a C string internally along with the Pascal string.
Pascal.cpp
// Pascal Main cpp


#include <iostream>
#include <algorithm>
#include "Pascal.h"
#include <exception>
using namespace std;
// Default constructor
String::String() {
    arr = new char[1];
    arr[0] = '\0';
    len = 0;
}

// Constructor. Converts a C-string to a String object
String::String(const char *s) {
    len = strlen(s);
    arr = new char[len + 1];
    std::copy(s, s + len + 1, arr);
}

// Copy constructor.
String::String(const String &obj) {
    len = obj.len;
    arr = new char[len + 1];
    std::copy(obj.arr, obj.arr + len + 1, arr);
}

// Move constructor.
String::String(String &&obj) {
    len = obj.len;
    arr = obj.arr;
    obj.arr = nullptr;
}

String::String(const char *str, bool pascal) {
    judge = pascal;
    if (judge) {
        len = strlen(str) - 1;
        const char *temp = str;
        arr = new char[len + 1];
        arr[0] = len + '0';
        for (int i = 1; i <= len; i++) {
            arr[i] = temp[i];
        }

    }
    else {
        len = strlen(str);
        arr = new char[len + 1];
        std::copy(str, str + len + 1, arr);
    }
}

// Destructor
String::~String() {
    if (arr != nullptr)
        delete[] arr;
}

// Assignment operator
String &String::operator=(const String &rhs) {
    delete[] arr;
    len = rhs.len;
    arr = new char[len + 1];
    std::copy(rhs.arr, rhs.arr + len + 1, arr);
    return *this;
}

// Move assignment operator
String &String::operator=(String &&rhs) {
    delete[] arr;
    len = rhs.len;
    arr = rhs.arr;
    rhs.arr = nullptr;
    return *this;
}


// Mutator operator[]
char &String::operator[](int index) {
    // check whether the index is within bounds
    if (index > len || index < 0)
        throw std::out_of_range("Index out of range");
    return arr[index];
}

// Accessor operator[]
char String::operator[](int index) const {
    // check whether the index is within bounds
    if (index > len || index < 0)
        throw std::out_of_range("Index out of range");
    return arr[index];
}

// Get the length (number of characters) of a String object
int String::length() const {
    return len;
}

bool operator==(const String &lhs, const String &rhs) {
    if (lhs.judge != rhs.judge) {
        cout << "can't compare";
    }
    return strcmp(lhs.arr, rhs.arr) == 0;
}

bool operator<(const String &lhs, const String &rhs) {
    if (lhs.judge != rhs.judge) {
        cout << "can't compare";
    }
    return strcmp(lhs.arr, rhs.arr) < 0;
}

// Friend functions for > comparison
bool operator>(const String &lhs, const String &rhs) {
    if (lhs.judge != rhs.judge) {
        cout << "can't compare";
    }
    return rhs < lhs;
}

// Friend functions for <= comparison
bool operator<=(const String &lhs, const String &rhs) {
    if (lhs.judge != rhs.judge) {
        cout << "can't compare";
    }
    return !(rhs < lhs);
}

// Friend functions for >= comparison
bool operator>=(const String &lhs, const String &rhs) {
    if (lhs.judge != rhs.judge) {
        cout << "can't compare";
    }
    return !(lhs  < rhs);
}

// Friend functions for != comparison
bool operator!=(const String &lhs, const String &rhs) {
    if (lhs.judge != rhs.judge) {
        cout << "can't compare";
    }
    return !(lhs == rhs);
}

//  Friend function for string concatination
String operator+(const String &lhs, const String &rhs) {
    if (lhs.judge == rhs.judge && lhs.judge == false) {
        int strLength = lhs.len + rhs.len + 1;
        char *tmpStr = new char[strLength];
        for (auto i = 0; i < lhs.len; ++i)
            tmpStr[i] = lhs.arr[i];
        for (auto i = 0; i <= rhs.len; ++i)
            tmpStr[lhs.len + i] = rhs.arr[i];
        String retStr(tmpStr);
        delete[] tmpStr;
        return retStr;
    }
    else if (lhs.judge == rhs.judge && lhs.judge == true) {
        int strLength = lhs.len + rhs.len + 1;
        char *tmp = new char[strLength];
        for (auto i = 1; i <= lhs.len; ++i)
            tmp[i] = lhs.arr[i];
        for (auto i = 1; i <= rhs.len; ++i)
            tmp[lhs.len + i] = rhs.arr[i];
        tmp[0] = (lhs.len + rhs.len) + '0';
        String retStr(tmp);
        delete[] tmp;
        return retStr;
    }
    else {
        return String("can't do that");
    }
}

// Return C style character string
const char* String::c_str() const {
    return arr;
}

//  Friend function for output
std::ostream& operator<<(std::ostream &out, const String &obj) {
    return out << obj.c_str();
}
Pascal.h
// Pascal Header File

#pragma once
#ifndef __MYSTRING_H__
#define __MYSTRING_H__

#include <iostream>

class String {
public:
    // Usage: String aStringObj; or String aStringObj();
    String();

    // Constructor. Converts a char* object to a String  object
    // Usage: String aStringObj("hello"); or String aStringObj = "hello";
    String(const char *s);

    // Copy and move constructors.
    // Usage: String aStringObject(anotherStringObj); or
    // String aStringObject = anotherStringObj;
    String(const String &s);
    String(const char *str, bool pascal);
    String(String&& obj);

    // Destructor
    ~String();

    // Assignment operator
    // Usage: aStringObject = anotherStringObj; or
    // aStringObject.operator=(anotherStringObj);
    String &operator=(const String &rhsObject);
    String& operator=(String&& rhs);

    // Mutator operator[]
    // Usage: aStringObject[1] = ’M’;
    char &operator[] (int index);

    // Accessor operator[]
    // Usage: char ch = aStringObject[1];
    char operator[] (int index) const;

    // Get the length (number of characters) of a String object
    // Usage: int len = aStringObject.Length();
    int length() const;

    // Friend functions for == comparison
    // Usage: if (aStringObject == anotherStringObj) {...} or
    //        if (aStringObject == "hello") {...} or
    //        if ("hello" == aStringObj) {...} or
    friend bool operator==(const String &lhsObject, const String &rhsObject);

    // The other five comparison operators
    // !=, <, >, <=, >= are similarly handled as in line 13.

    friend bool operator<(const String &lhsObject, const String &rhsObject);
    friend bool operator>(const String &lhsObject, const String &rhsObject);
    friend bool operator<=(const String &lhsObject, const String &rhsObject);
    friend bool operator>=(const String &lhsObject, const String &rhsObject);
    friend bool operator!=(const String &lhsObject, const String &rhsObject);

    // Friend function for string concatenation
    // Usage: StringOne = StringTwo + StringThree  or
    //        StringOne = "hello" + StringTwo  or
    //        StringOne = StringTwo + "hello"
    friend String operator+(const String &lhs, const String &rhs);

    // Return C style character string
    // Usage: const char *str = aStringObj.C_str();
    const char *c_str() const;

    // Friend function for output
    // Usage: cout << aStringObj;
    friend std::ostream &operator<<(std::ostream &out, const String &obj);

private:
    // arr implements the String object as a dynamic array
    char *arr;

    // len keeps track of the length
    int len;

    // judge weather the String is a c_string or a pascal_string
    bool judge;
};

#endif

When compiling I get these warnings and errors:

enter image description here

Severity    Code    Description Project File    Line    Suppression State
Warning C4996   'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'    Pascal Assignment   c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility 2229    

 Severity   Code    Description Project File    Line    Suppression State
Error   LNK1120 1 unresolved externals  Pascal Assignment   C:\Users\Danielle\Documents\Visual Studio 2015\Projects\Pascal Assignment\Debug\Pascal Assignment.exe   1   

Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol _main referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)   Pascal Assignment   C:\Users\Danielle\Documents\Visual Studio 2015\Projects\Pascal Assignment\MSVCRTD.lib(exe_main.obj) 1   

Upvotes: 1

Views: 341

Answers (1)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145359

The lack of a main function is because you haven't defined one, and you're compiling as a program. Either this should be a library project, or there should be a main function. The #endif at the end of your code indicates that this is a header where the start of it just isn't shown. If so then yYou need a separate .cpp file (for example) to put your main in.


In other news:

  • Identifiers that contain two successive underscores, like __MYSTRING_H__, are reserved to the implementation and can therefore cause trouble. Also, an identifier starting with underscore followed by uppercase, is reserved. Use e.g. just MYSTRING_H. But:

  • When you use #pragma once, as you do, then you don't need include guard symbols.

  • I haven't really studied the code, but unless you use operations like <<, or e.g. endl, in the header, then you don't need to include the entire <iostream> in the header. It's sufficient to include <iosfwd>. That's what its for: a lean & mean just declarations of relevant types. You still need to include <iostream> where you use the standard streams, i.e. in your implementation file. But this cost is not charged to client code.

Upvotes: 2

Related Questions