I searched over the net how to return a vector object but I can't find the simplest one. First of all, I am not expert in C++ and I just started C++ few weeks ago. Is it not okay to return an object vector?
I have something like this.
I pushed it somewhere through this:
MAIN File:
int main()
{
XIniFile *f = new XIniFile();
int result = 0;
int v = 0;
char *val;
result = f->open("doc2.ini");
if (INI_FILE_RES_OK == result) {
}
else
printf("Error[%d]\n", result);
}
CPP File:
XKey::XKey()
{
}
XKey::~XKey()
{
}
XSection::XSection()
{
}
XSection::~XSection()
{
}
XKey *XSection::addKey(const char *k, const char *val)
{
XKey *nk = new XKey;
nk->setName(k);
nk->setValue(val);
m_vkey.push_back(*nk);
return nk;
}
void XSection::showKey()
{
vector<XKey>::iterator ik;
for (ik = m_vkey.begin(); ik != m_vkey.end(); ik++)
printf("%s = %s\n", ik->getName(), ik->getValue());
}
XIniFile::XIniFile()
{
m_modified = false;
}
int XIniFile::open(const char *fn)
{
XSection *cs;
char *sn;
char *kn;
char *val;
int i = 0;
FILE *f;
f = fopen(fn, "r");
if (!f)
return INI_FILE_ERROR;
struct stat file_stat;
stat(fn, &file_stat);
int size = file_stat.st_size;
m_name = strdup(fn);
char *d = (char *)malloc(size * sizeof(char *) + 1);
fread(d, size, 1, f);
while (i < size) {
while (d[i] != '[') i++;
if (d[i] == '[') {
i++;
while (isspace(d[i])) i++;
sn = &d[i];
while (d[i] != ']')
i++;
d[i++] = 0;
cs = addSection(sn);
while (isspace(d[++i]));
while(d[i] != '[') {
while (isspace(d[i])) i++;
kn = &d[i];
while (d[i] != '=') i++;
d[i-1] = 0;
i++;
while (isspace(d[i])) i++;
if (d[i] == '[') {
i++;
val = &d[i];
while (isspace(d[i])) i++;
d[i-1] = 0;
}
else {
val = &d[i];
while (d[i] != '\n') i++;
d[i] = 0;
}
i++;
cs->addKey(kn, val);
while (isspace(d[i])) {
i++;
if (i >= size) break;
}
if (i >= size) break;
}
}
}
free(d);
vector<XSection>::iterator is;
for (is = m_vsection.begin(); is != m_vsection.end(); is++) {
printf("[%s]\n", is->getName());
printf("is->getSize()[%d]\n", is->getSize());
}
fclose(f);
return INI_FILE_RES_OK;
}
XIniFile::~XIniFile()
{
delete m_name;
}
XSection *XIniFile::addSection(const char *s)
{
XSection *ns = new XSection;
ns->setName(s);
m_vsection.push_back(*ns);
return ns;
}
void XIniFile::showSection()
{
vector<XSection>::iterator is;
for (is = m_vsection.begin(); is != m_vsection.end(); is++)
printf("[%s]\n", is->getName());
printf("End\n");
}
Header File:
class XKey
{
public:
XKey();
virtual ~XKey();
void *setName(const char *k) {m_name = strdup(k);}
void *setValue(const char *v) {m_value = strdup(v);}
char *getName(){return m_name;}
char *getValue(){return m_value;}
private:
char *m_name;
char *m_value;
};
class XSection
{
public:
XSection();
virtual ~XSection();
void *setName(const char *n) {m_name = strdup(n);}
char *getName() {return m_name;}
XKey *addKey(const char *k, const char *v);
vector<XKey> getKey() {return m_vkey;}
int getSize() {return m_vkey.size();}
void showKey();
private:
char *m_name;
vector<XKey> m_vkey;
};
class XIniFile
{
public:
XIniFile();
virtual ~XIniFile();
int open(const char *);
int readString(const char *, const char *, char **);
int readInt(const char *, const char *, int *);
XSection *addSection(const char *);
void showSection();
private:
char *m_name;
vector<XSection> m_vsection;
bool m_modified;
};
the problem here is that under CPP file is->getSize() doesn't increase even if I used push_back on m_vkey which could be found on my addKey method.
It's because the object you're modifying is not the same as the one you're storing.
Look here:
XSection *XIniFile::addSection(const char *s)
{
XSection *ns = new XSection; // Create a new XSection
ns->setName(s);
m_vsection.push_back(*ns); // Store a copy of ns
return ns; // Return the original ns
}
Now when you do something with the return value, the object in m_vsection is unaffected.
The quickest fix is to store the pointers you're returning in m_vsection instead, and similar for the section objects.
Although you should probably start using std::shared_ptr (not to mention std::string) if at all possible.
Related
I am getting this error message can anyone help me out.
I am getting the error code 'return' cannot convert from 'clsStack' to 'T' relating the two functions listed below.
Code is as follows
Class
template <class T>
class clsStack //this is the stack class that is used to handle the functions and any data that needs passing between functions
{
private:
clsStack* data;
int iTop;
int iSize;
void resize();
bool needToResize();
string sExpresion;
public:
void stack()
{
iSize = 5;
iTop = 0;
data = new clsStack[iSize];
}
void push(T item);
T peek();
T pop();
bool isEmpty();
};
The two functions I think the issue is related to
template <class T>
T clsStack<T>::peek() //this is used to look at the last number is the array
{
if (iTop <= 0)
throw out_of_range("Attempted to peek an empty stack. \n");
return data[iTop - 1];
}
template <class T>
T clsStack<T>::pop()
{
if (iTop <= 0)
throw out_of_range("Attempted to pop an empty stack. \n");
iTop++;
return data[iTop];
}
The main function where these functions are been called
int evaluate(string sExpresion)
{
clsStack<int> iValues;
clsStack<char> cOperators;
int iValue = 0;
int iPosition = 0;
bool bResult = false;
while (iPosition < sExpresion.length())
{
char cSpot = sExpresion[iPosition];
if (isDigit(cSpot))
{
iValue = (iValue * 10) + (int)(cSpot - '0');
}
else if (isOperator(cSpot))
{
if (cSpot == '(')
{
cOperators.push(cSpot);
iValue = 0;
}
if (cSpot == '-')
{
cOperators.push(cSpot);
iValue = 0;
}
else if (iValues.isEmpty() && cOperators.peek() == '-')
{
int iPrevValue = iValues.pop();
int iPrevOperator = cOperators.pop();
iPrevValue = operation(iValue, iPrevValue, iPrevOperator);
iValues.push(iPrevValue);
cOperators.push(cSpot);
}
else if (iValues.isEmpty())
{
iValues.push(iValue);
cOperators.push(cSpot);
iValue = 0;
}
else if (cSpot == ')')
{
iValues.push(iValue);
while (cOperators.peek() != '(')
{
cSpot = cOperators.pop();
iValue = iValues.pop();
int iPrev = iValues.pop();
iValue = operation(iPrev, iValue, cSpot);
iValues.push(iValue);
}
cOperators.pop();
iValues.pop();
}
else
{
int iPrevValue = iValues.pop();
int iPrevOperator = cOperators.pop();
iPrevValue = operation(iPrevValue, iValue, iPrevOperator);
iValues.push(iPrevValue);
cOperators.push(cSpot);
iValue = 0;
}
}
iPosition++;
}
while (!cOperators.isEmpty())
{
int iPrev = iValues.pop();
char cSpot = cOperators.pop();
iValue = operation(iPrev, iValue, cSpot);
bResult = true;
}
return (sExpresion, iValue, bResult);
}
Any help is much apricated.
I have a function that takes a user entered string and splits it into individual words using a dynamically allocated two-dimensional array. The words are separated by delimiters used as indicators of where one word ends and another begins.
Here is my code:
int countWords(const char * sentence, char * delims)
{
int wordsInArray = 0;
int count = 0;
while(*(sentence + count) != '\0')
{
if(*(sentence + count) == *delims && *(sentence + count + 1) != *delims)
{
wordsInArray++;
}
if(*(sentence + count + 1) == '\0')
{
wordsInArray++;
}
count++;
}
return wordsInArray;
}
int getLength(const char * sentence)
{
const char *p = sentence;
while(*p != '\0')
{
p++;
}
return p-sentence;
}
char ** getWords(const char * sentence, int & wordcount)
{
char delims[] = " .,\t?!";
int sentenceLength = getLength(sentence);
wordcount = countWords(sentence, delims);
char ** words;
words = new char *[wordcount];
int length = 0;
int count = 0;
for (int a = 0; a < sentenceLength; a++)
{
if(*(sentence + a) != *delims)
{
length++;
}
else if ((*(sentence + a) == *delims && *(sentence + a + 1) != *delims) || *(sentence + a) == '\0')
{
*(words + count) = new char[length+1];
for (int z = 0; z < length; z++)
{
*(*(words + count) + z) = *(sentence + z);
}
length = 0;
count++;
}
}
return words;
}
However, my countWords function is not properly counting the words in the string, and I do not know why.
Try something more like this:
int indexOf(const char * sequence, char ch) {
const char *p = sequence;
while (*p != '\0') {
if (*p == ch) {
return p - sequence;
}
}
return -1;
}
const char* findFirstOf(const char * sequence, const char *chars) {
const char *p = sequence;
while (*p != '\0') {
if (indexOf(chars, *p) != -1) {
return p;
}
}
return NULL;
}
const char* findFirstNotOf(const char * sequence, const char *chars) {
const char *p = sequence;
while (*p != '\0') {
if (indexOf(chars, *p) == -1) {
return p;
}
}
return NULL;
}
int countWords(const char * sequence, char * delims) {
int count = 0;
const char *p = sequence;
do {
p = findFirstNotOf(p, delims);
if (p == NULL) break;
++count;
p = findFirstOf(p, delims);
}
while (p != NULL);
return count;
}
int getLength(const char * sequence) {
const char *p = sequence;
while (*p != '\0') {
++p;
}
return p-sequence;
}
char* dupString(const char * sequence, int length = -1) {
if (length == -1) {
length = getLength(sequence);
}
char *result = new char[length+1];
for (int i = 0; i < length; ++i) {
result[i] = sequence[i];
}
result[length] = '\0';
return result;
}
char** getWords(const char * sequence, int & wordcount) {
const char delims[] = " .,\t?!";
int count = countWords(sequence, delims);
char ** words = new char *[count];
if (count > 0) {
count = 0;
const char *p = sequence;
do {
p = findFirstNotOf(p, delims);
if (p == NULL) break;
const char *q = findFirstOf(p, delims);
if (q == NULL) {
words[count++] = dupString(p);
break;
}
words[count++] = dupString(p, q-p);
p = ++q;
}
while (true);
}
wordcount = count;
return words;
}
That being said, the fact you are using new[] means you are using C++, so you should be using the STL to make life easier:
#include <string>
#include <vector>
std::vector<std::string> getWords(const std::string & sequence) {
const char delims[] = " .,\t?!";
std::vector<std::string> words;
std::string::size_type i = 0;
do {
i = sequence.find_first_not_of(delims, i);
if (i == std::string::npos) break;
std::string::size_type j = sequence.find_first_of(delims, i);
if (j == std::string::npos) {
words.push_back(sequence.substr(i));
break;
}
words.push_back(sequence.substr(i, j-i));
i = ++j;
}
while (true);
return words;
}
Basically what the title says. I have been trying to write my own string class using only char arrays and, while my code works when I run it in Visual Studio, I have trouble with it when using gcc .The problem seems to be coming when i try to delete in my getData function(can be seen below) The exception I get is:
Exception thrown at 0x6262436B (ucrtbased.dll) in string.exe: 0xC0000005: Access violation reading location 0xCCCCCCBC. occurred
My code :
Header:
#pragma warning(disable:4996)
#ifndef STRING_STRING_H
#define STRING_STRING_H
#include<iostream>
#include<cstring>
#include<fstream>
class String {
private:
char *data; //holds the text
size_t maxSize; //maximum number of chars in data
size_t currentSize; //current number of chars in data
void getData(const char *, size_t maxSize); //sets currentSize to the other char* size and
// copies the content of the other char* to data
public:
String(); //default constructor
~String(); //destructor
String(const String &); //copy-constructor(from String)
String(const char *); //copy-constructor(from char*)
String operator=(const String &); //operator= (from string)
String operator=(const char *); //operator=(from char*)
size_t length() const; //currentSize getter
void addChar(const char); //adds a char to the data array
void getLine(std::ifstream&,const char); // reads line till deliminator and stores it in this string object(all data previously stored is lost)
size_t find(const char*); //searches for text in the string and if found returns the starting position , if not found returns -1;
void print() const; //prints the string object to console
char* toChar() const; //returns a new allocated char pointer with the text inside (must be deleted afterwards)
};
#endif //STRING_STRING_H
cpp:
#include "String.h"
String::String() {
currentSize = 0;
maxSize = 16;
try {
data = new char[maxSize];
data[0] = '\0';
}
catch (std::bad_alloc &) {
std::cerr << "Not enough memory" << std::endl;
throw;
}
}
String::~String() {
delete[] data;
}
size_t String::length() const {
return currentSize;
}
String::String(const String &other) {
this->maxSize = other.maxSize;
getData(other.data, maxSize);
}
String::String(const char *other) {
this->maxSize = strlen(other) *2;
getData(other, maxSize);
}
void String::getData(const char *dataSource, size_t maxSize) {
currentSize = strlen(dataSource);
try {
char *newData = new char[maxSize];
delete[] data;
data = newData;
strcpy(data, dataSource);
}
catch (std::bad_alloc &) {
std::cerr << "Not enough memory" << std::endl;
throw;
}
}
String String::operator=(const String &other) {
if (this != &other) {
maxSize = other.maxSize;
getData(other.data, maxSize);
}
return *this;
}
String String::operator=(const char *other) {
if (this->data != other) {
maxSize = strlen(other) *2;
getData(other, maxSize);
}
return *this;
}
void String::addChar(const char newChar) {
if (maxSize == currentSize+1) {
maxSize *= 2;
getData(this->data, maxSize);
}
data[currentSize++] = newChar;
}
void String::getLine(std::ifstream & is, const char delim='\n')
{
char temp;
while (!is.eof())
{
is.get(temp);
if (temp == delim)
break;
else
addChar(temp);
}
return;
}
size_t String::find(const char * text)
{
size_t currPos=-1;
bool found = 0;
for (size_t i = 0; i < currentSize; i++)
{
if (data[i] == text[0])
{
for (size_t j = i+1; j < currentSize; j++)
{
if (data[j] == text[j - i])
found = 1;
else
{
found = 0;
break;
}
}
if (found == 1)
{
currPos = i;
break;
}
}
}
return currPos;
}
void String::print() const
{
for (size_t i = 0; i < currentSize; i++)
{
std::cout << data[i];
}
std::cout << std::endl;
}
char * String::toChar() const
{
char* text= new char[currentSize+1];
for (size_t i = 0; i < currentSize; i++)
{
text[i] = data[i];
}
text[currentSize + 1] = 0;
return text;
}
Your problem is caused by calling delete [] on uninitialized memory.
In the copy constructor, the data member is not initialized before calling getData(). In getData(), you are using delete [] data;.
You could initialize data to nullptr in the constructors to avoid the problem.
It's always a good idea to initialize all variables to some sensible value before the body of the constructor. E.g. you can implement the copy constructor as:
String::String(const String &other) : currentSize(0),
maxSize(other.maxSize),
data(nullptr)
{
getData(other.data, maxSize);
}
Similarly, implement the constructor from char const* as:
String::String(const char *other) : currentSize(0),
maxSize(strlen(other) *2),
data(nullptr)
{
getData(other, maxSize);
}
I have a bug with my printf() function im implementing for OS. Basically the problem is, it dosent increment through the list. For example lets say i have:
printf("%d %d",19,58);
what will show on my OS is :
19 19
the 58 for some reason is not going thourgh. I have debugged this for quite some time, but cant find problem :( . Here is the stdio.c++:
#include "stdio.h"
static size_t terminal_row = 0;
static size_t terminal_column = 0;
static uint16_t* VideoMemory =((uint16_t*)0xb8000);
static bool continue_ex = false;
SerialPort sp_std_io;
void printf(char *str, ...)
{
va_list arg;
va_start(arg, str);
for(int32_t i=0;str[i]!='\0'; ++i)
{
putchar(str[i],str[i+1],arg);
}
va_end(arg);
}
void strcat(char *destination, const char *source)
{
int x = 0;
while (destination[x] != '\0')
{
x++;
}
for (int i=0; source[i] != '\0'; i++)
{
destination[x++] = source[i];
}
destination[x] = '\0';
}
void put_char_helper_neg(char chr)
{
const size_t index = (terminal_row * VGA_WIDTH + terminal_column);
terminal_column++;
VideoMemory[index]= (VideoMemory[index] & 0xFF00)|chr;
}
void putstring_t(char str)
{
size_t index = (terminal_row * VGA_WIDTH + terminal_column);
terminal_column++;
VideoMemory[index]= (VideoMemory[index] & 0xFF00)|str;
}
void putchar(char str,char next_str, va_list arg)
{
if(!continue_ex)
{
uint32_t ch_per;
char* str_use,str_use_space;
const char per = '%';
if(str == '\b')
{
terminal_column--;
}
const size_t index = (terminal_row * VGA_WIDTH + terminal_column);
char space = ' ';
switch(str)
{
case '\n':
terminal_row++;
terminal_column = 0;
break;
case '\b':
VideoMemory[index]= (VideoMemory[index] & 0xFF00)|space;
break;
case '%':
switch(next_str)
{
case 'd':
ch_per = va_arg(arg,int);
if(ch_per<0)
{
ch_per = -ch_per;
put_char_helper_neg('-');
}
str_use = itoa(ch_per);
terminal_column++;
for(int32_t i=0;str_use[i]!='\0'; ++i)
{
putstring_t(str_use[i]);
}
// sp_std_io.write_number_serial(ch_per);
// sp_std_io.write_string_serial(str_use);
continue_ex = true;
break;
default:
terminal_column++;
VideoMemory[index]= (VideoMemory[index] & 0xFF00)|per;
}
break;
default:
terminal_column++;
VideoMemory[index]= (VideoMemory[index] & 0xFF00)|str;
break;
}
}
else
{
continue_ex = false;
}
}
int32_t strlen(int8_t* str)
{
int32_t l=0;
while(str[l]!='\0')l++;
return l;
}
char *itoa(int val)
{
uint8_t *ptr;
static uint8_t buffer[16];
ptr = buffer + sizeof(buffer);
*--ptr = '\0';
if (val == 0)
{
*--ptr = '0';
}
else while (val != 0)
{
*--ptr = (val % 10) + '0';
val = val / 10;
}
return((char*)ptr);
}
and stdio.h:
#ifndef _STD_LIB_H_
#pragma once
#define _STD_LIB_H_ 1
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include "math.h"
#include "serial.h"
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;
//static int num_count_viedo_memory = 0;
void printf(char *str,...);
void putchar(char str,char next_str,va_list arg);
int32_t strlen(int8_t *str);
void strcat(char * Dest, char const * Src);
//int8_t* str_cat(int8_t *dest, const int8_t *src);
void reverse(char str[], int32_t length);
char* itoa(int val);
#endif
Like i described above , it is not incrementing through the args for some reason. Help would be appreciated! :)
Pass arg into your putchar function by reference instead of by value:
void putchar(char str,char next_str, va_list& arg)
What's happening is that it gets incremented inside your putchar function, but then the function returns and it has no effect on the variable in printf because putchar is passed a copy rather than a reference to it.
typedef unsigned int uint;
class hash_table {
struct key_line {
bool empty();
string word;
vector<int> lineholder;
bool operator==(const string &key) { return key == word; };
bool operator!=(const string &key) { return key != word; };
};
public:
hash_table();
void insert(const string &, const int &);
const vector<int> find1(const string&);
private:
uint hash(const string &);
int nextprime(int);
int qprobe(const string &);
void resize();
int inusenow;
int num_inuse;
int max_inuse;
vector<key_line> table;
};
uint hash_table::hash(const string &key) {
uint index = 0;
const char *c = key.c_str();
while (*c)
index = ((index << 5) | (index >> 27)) + *c++;
return index % table.size();
}
hash_table::hash_table() {
int N = 41;
table.assign(N, key_line());
inusenow = 0;
num_inuse = 0;
max_inuse = N / 2;
}
void hash_table::insert(const string &key, const int &linenumber) {
int index = qprobe(key);
if (table[index].empty()) {
table[index].word = key;
table[index].lineholder.push_back(linenumber);
if (++num_inuse >= max_inuse) {
resize();
}
return;
}
if (table[index].word == key) {
for (uint i = 0; i < table[index].lineholder.size(); i++) {
if (table[index].lineholder[i] == linenumber) {
return;
}
}
table[index].lineholder.push_back(linenumber);
return;
}
}
int hash_table::qprobe(const string &key) {
int index = hash(key);
int k = 0;
while (!table[index].empty() && table[index].word != key) {
index += 2 * (++k) - 1;
index = index % table.size();
}
return index;
}
void hash_table::resize() {
vector<key_line> tmp_table(table);
//for (int i = 0; i<(int)table.size(); i++) {
//cout << "Word : " << table[i].word << "\n";
//}
//for (int i = 0; i<(int)table.size(); i++) {
// if (table[i].empty())
// tmp_table.push_back(table[i]);
// }
int N = nextprime(2 * table.size());
inusenow = N;
table.assign(N, key_line());
num_inuse = 0;
max_inuse = N / 2;
table = tmp_table;
cout << "resize";
}
int main(int argc, char *argv[]) {
hash_table H;
vector<string> cache; vector<string> token;
vector<int> linenum;
string holder, key, tmp, buf;
string::iterator iv;
stringstream ss;
int count = 0;
int linenumber = 0;
if (argc != 2) {
cout << "Must have an additonal argument giving the name of the file you wish to search\n";
return 0;
}
ifstream file;
file.open(argv[1]);
while (getline(file, holder)) {
cache.push_back(holder);
count = 0;
for (iv = holder.begin(); iv != holder.end(); ++iv) {
if (!isalnum(holder[count])) {
holder[count] = ' ';
}
count++;
}
token.clear();
ss.clear();
stringstream ss(holder);
while (ss >> buf) {
H.insert(buf, linenumber);
//token.push_back(buf);
}
//for (uint i = 0; i<token.size(); i++) {
// H.insert(token[i], linenumber);
//}
linenumber += 1;
}
The purpose of this program is for it to be able to take in any sort of txt file and then hash it into a table.
The resize function is not increasing the size of the table and is overwriting table with the next table.
For example
if the table originally has an word at index 1 when it resizes the original is over written.
The functions empty, nextprime work.