Split a string inside a class constructor - c++

I have a class with 2 data members: size and an array of ints (dynamically allocated). The purpose of the class is to create an array of a size and fill it with values. The task is to create a constructor that takes a string as its parameter, but the string looks like this: "12|13|14|15" etc. I have searched this but all the solutions are a little too complicated, as they involve vectors and we haven't started with vectors yet. I basically want to put these numbers into the array of ints, 1 by 1 and also find out the size of the array. How can I do that? I tried messing with getline and stringstream but that gave me a load of errors. My code looks like this.
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
class IntArrays {
private:
static int objcount;
int size;
public:
int *arrayints;
const static int objcountf();
IntArrays(int);
IntArrays(const IntArrays &p){
size = p.size;
for (int i = 0;i <size;i++){
arrayints[i] = p.arrayints[i];
}
}
IntArrays(std::string f){
// ignore the other constructors, this is the constructor that is giving me trouble
int counter =0;
istringstream inStream(f);
string newstring;
while (getline(iss,newstring, '|')){
arrayints[counter] = stoi(newstring);
counter++;}
void enternums();
(note that this is only the header file, and that the current string constructor I have there does not work.

This code is my version. I prefer to use a vector rather than a raw array.
Class definition:
class IntArrays {
public:
IntArrays(const string&, const char&);
const vector<int>& data() { return _data; }
const int size() { return _data.size(); }
private:
vector<int> _data;
};
The following is the constructor implementation:
IntArrays::IntArrays(const string& str, const char& delimiter) {
string buff;
for(auto& n:str) {
if(n != delimiter) buff+=n; else
if(n == delimiter && buff != "") {
_data.push_back(stoi(buff));
buff = "";
}
}
if(buff != "") _data.push_back(stoi(buff));
}
And then we just use the class:
IntArrays a("1|4|9|6|69", '|');
vector<int> da = a.data();
IntArrays b("1,4,9,6,69", ',');
vector<int> db = b.data();

I will try to have a recursion for that =p
Sorry that I cannot provide a c++ version =p..
This is a java version i guess.
list parse(string data, list base) {
if (data.length > 0) {
string s = data.subStr(0,1);
if (s == "|") {
base.push(0); //set the initial value for a new value
} else {
int i = parseInt(s);
int result = base.pop()*10 + i; //recalculate the result
base.push(result);
}
return parse(data.subStr(1),base); //recursion
} else {
return base; //return the result
}
}

As Joachim pointed out, you do not initialize the pointer. Unfortunately, you do not have the size of the array before the allocation, so you are left with a few solutions:
process the input twice (really bad if you have a large number of entries); On the first pass, count the inputs. Then allocate the array, then read them again, into the allocated array.
read the inputs into a linked list; Each element in the list would hold a value, and the address of the next element.
Preallocate a block of memory and hope it is large enough to read the entire array. If it is not, reallocate a larger block and copy the already read values into it, then discard the initial block (this is what std::vector does).

Related

How do I reverse a c string without the use of strlen?

I'm trying to implement a void function that takes a c string as its only parameter and reverses it and prints it. Below is my attempt at a solution however I'm not sure how to go about this problem.
void printBackwards(char forward[]) {
int i = 0;
char backwards[];
while (forward[i] != '\0') {
backwards[i] = forward[-i - 1];
i++;
}
cout << backwards;
}
Under such a condition, I guess you are expected to use recursion.
void printBackwards(char forward[]) {
if (!forward[0])
return;
printBackwards(forward + 1);
cout << forward[0];
}
Not being able to use strlen, we'll calculate it ourselves using a simple for loop. Then dynamically allocate a suitable buffer (add one character for the null terminating char, and I "cheated" by using calloc to zero the memory so I don't have to remember to set the null terminator. Then anoher simple loop to copy the original into the result in reverse.
#include <stdlib.h>
#include <stdio.h>
char *rev(char *s) {
size_t i;
char *s2 = s; // A pointer to the beginning as our first loop modifies s
for (i = 0; *s; s++, i++);
char *result = calloc(0, i + 1);
if (!result) return NULL; // In case calloc didn't allocate the requested memory.
for (size_t j = 0; j < i; j++)
result[j] = s2[i - j - 1];
return result;
}
Assuming you want to reverse the string rather than just printing it in reverse order, you first need to find the last character location (actually the position of the null terminator). Pseudo-code below (since this is an educational assignment):
define null_addr(pointer):
while character at pointer is not null terminator:
increment pointer
return pointer
Then you can use that inside a loop where you swap the two characters and move the pointers toward the center of the string. As soon as the pointers become equal or pass each other the string is reversed:
define reverse(left_pointer):
set right_pointer to null_addr(left_pointer)
while right_pointer > left_pointer plus one:
decrement right_pointer
swap character at left_pointer with character at right_pointer
increment left_pointer
Alternatively (and this appears to be the case since your attempt doesn't actually reverse the original string), if you need to print the string in reverse order without modifying it, you still find the last character. Then you run backwards through the string printing each character until you reach the first. That can be done with something like:
define print_reverse(pointer):
set right_pointer to null_addr(pointer)
while right_pointer > pointer:
decrement right_pointer
print character at right_pointer
That's probably better than creating a new string to hold the reverse of the original, and then printing that reverse.
One thing you should keep in mind. This very much appears to be a C-centric question, not a C++ one (it's using C strings rather than C++ strings, and uses C header files). If that's the case, you should probably avoid things like cout.
By using abstractions, like , your code will be much better at communication WHAT it is doing instead of HOW it is doing it.
#include <iostream>
#include <string>
#include <ranges>
int main()
{
std::string hello{ "!dlrow olleH" };
for (const char c : hello | std::views::reverse)
{
std::cout << c;
}
return 0;
}
Use a template
#include <iostream>
template<int N, int I=2>
void printBackwards(char (&forward)[N]) {
std::cout << forward[N-I];
if constexpr (I<N) printBackwards<N, I+1>(forward);
}
int main() {
char test[] = "elephant";
printBackwards(test);
}
While there seems to be several working answers, I thought I'd throw my hat in the stack (pun intended) since none of them take advantage of a FILO data structure (except #273K's answer, which uses a stack implicitly instead of explicitly).
What I would do is simply push everything onto a stack and then print the stack:
#include <stack>
#include <iostream>
void printBackwards(char forward[]) {
// Create a stack to hold our reversed string
std::stack<char> stk;
// Iterate through the string until we hit the null terminator
int i = 0;
while (forward[i] != '\0'){
stk.push(forward[i]);
++i;
}
// Iterate through the stack and print each character as we pop() it
while (stk.size() > 0){
std::cout << stk.top();
stk.pop();
}
// Don't forget the newline (assuming output lines should be separated)
std::cout << '\n';
}
int main(int argc, char* argv[]){
char s[] = "This is a string";
printBackwards(s);
return 0;
}
Hi guys as promised I have come back to add my own answer. This is my own way using array subscripts and using what I currently know.
#include <iostream>
using namespace std;
void printBackwards(char[]);
int main()
{
char word[] = "apples";
printBackwards(word);
return 0;
}
void printBackwards(char word[]) {
char* temp = word;
int count = 0;
while (*temp++ != '\0') {
count++;
}
for (int i = count - 1; i >= 0; i--) {
cout << word[i];
}
}
You can make a fixed-size buffer and create new ones if needed. Fill it reverse by moving the string offset back with every inserted character. Chars exceeding the buffer are returned to be processed later, so you can make a list of such buffers:
template<int SIZE>
struct ReversedCStr
{
static_assert(SIZE > 10); // just some minimal size treshold
// constexpr
ReversedCStr(char const* c_str, char const** tail = nullptr) noexcept
{
for(buffer[offset] = '\0'; *c_str != '\0';)
{
buffer[--offset] = *c_str++;
if(offset == 0) break;
}
if(tail) *tail = c_str;
}
//constexpr
char const* c_str() const noexcept { return buffer.data()+offset;};
private:
size_t offset = SIZE -1;
std::array<char,SIZE> buffer;
};
The tag is 'C++' so I assume you use C++ not C. The following code is C++11 so it should fit in every modern project. I posted the working example on godbolt.org.
It doesn't allocate memory, and is completely exception-free. The maximum memory wasted is {buffer_size + sizeof(char*)*number_of_chunks}, and can be easily turned into a list of reversed chunks like this:
char const* tail;
std::vector<ReversedCStr<11>> vec;
for(vec.emplace_back(str,&tail); *tail != '\0';)
vec.emplace_back(tail,&tail);

C++ Call string into function?

Not sure how to exactly explain this, sorry. I'm creating a function to find the first instance of a char in an array built by a given string. I have the function to create an array from the string and loop through the array, but not sure how to put it the array into the find function.
the tester is built like
stringName("Test test test");
stringName.find("e",0); //where 0 is the starting position, so it would return 1.
int SuperString::find(char c, int start) {
// put array grabber thing here
size = *(&data + 1) - data;
for(int i = start; i < size ; i++){
if(data[i] == c){
return i;
}
}
return -1;
}
This is what I have to make the string into an array.
SuperString::SuperString(std::string str) {
size = str.size();
data = new char[size];
for (int i = 0; i < size; i++) {
data[i] = str.at(i);
}
}
This is probably something easy I'm missing, but any help is appreciated.
You are passing a string literal, specifically a const char[2], where a single char is expected. Use 'e' instead of "e":
stringName.find('e', 0);
More importantly, size = *(&data + 1) - data; will only work when data is a (reference to a) fixed array (see How does *(&arr + 1) - arr give the length in elements of array arr?). It will not work when data is a pointer to an array, as it is in your case since you are allocating the array with new char[]. You will have to keep track of the array's size separately, which you appear to be doing, except that you are not actually using the size you obtained in the SuperString constructor. Just get rid of the line in find() that is trying to re-calculate size, use the value you already have:
int SuperString::find(char c, int start) {
// size = *(&data + 1) - data; // <-- GET RID OF THIS
for(int i = start; i < size; ++i){
if (data[i] == c){
return i;
}
}
return -1;
}
That being said, Your SuperString class can be greatly simplified if you just make its data member be a std::string instead of char*, eg:
#include <string>
class SuperString {
private:
std::string data;
...
public:
SuperString(const std::string &str);
int find(char c, int start = 0);
...
};
SuperString::SuperString(const std::string &str) : data(str) {
}
int SuperString::find(char c, int start) {
return (int) data.find(c, start);
}

Passing the std::string by reference doesn't update the string value in calling function

I am trying to remove duplicates from a string. The code goes like:
#include<iostream>
#include<stdio.h>
#include<string.h>
void removeDup(std::string s, std::string &ex)
{
int hash[256] = {0};
int k = 0;
for (int i = 0; i < s.size(); ++i)
{
if (hash[s[i]] == 0)
{
ex[k++] = s[i];
//std::cout<<ex[k-1];
}
hash[s[i]] = 1;
}
}
int main()
{
std::string s;
std::getline(std::cin, s);
std::string ss;
removeDup(s, ss);
std::cout<<ss<<std::endl;
return 0;
}
Now in main function I have printed the value of ss (which is passed as reference in removeDup function) but it prints nothing. Why is it so? Doesn't the value of string elements gets updated in called function?
Also, when I pass the string by address then I just get the first value printed.
eg :
void removeDup(std::string s, std::string *ex)
{
// same as above body function body
}
int main()
{
......
removeDup(s, &ss);
std::cout<<ss<<std::endl;
return 0;
}
In the output I just get the first letter of whatever is there in s. I can't understand. I am not much familiar with strings in programming languages. Kindly help.
This comes down to the fact that std::string::operator[](size_t index) expects passed index to be lower that string's size().
That means you need to either initialize ss with constructor (variant 2) that will fill it with input's size() worth of ' ''s or, better, use push_back() (ideally in conjunction with reserve() as a way to append elements to the output string.

How to read substring with ifstream C++

This is content of my file txt:
1 Joey 1992
2 Lisa 1996
3 Hary 1998
And I have a struct:
struct MyStruct
{
int ID;
char *Name;
int Old;
};
I have a main () as this:
int main ()
{
MyStruct *List;
int Rows, Columns;
ReadFile (List, Rows, Columns, "file.txt");
return 0;
}
Now, I want to write a function ReadFile to get information from file txt and store into a List, beside store Rows and Colums:
void ReadFile (MyStruct *&List, int &Rows, int &Colums, char const *path)
{
// need help here
}
I know how to use ifstream to read integer from txt, but I don't know how to read substring, such as:
"Joey", "Lisa" and "Hary"
to store each into char *Name.
Please help me. Thanks so much !
You seem to work on old school exercises: you use arrays and c-string to store data elements, with all the hassle of manual memory management.
A first (old-school) approach
I'll use only very basic language features and avoid any modern C++ features
void ReadFile (MyStruct *&List, int &Rows, int &Colums, char const *path)
{
const int maxst=30; // max size of a string
Rows=0; // starting row
ifstream ifs(path);
int id;
while (ifs>>id) {
MyStruct *n=new MyStruct[++Rows]; // Allocate array big enough
for (int i=0; i<Rows-1; i++) // Copy from old array
n[i] = List[i];
if (Rows>1)
delete[] List; // Delete old array
List = n;
List[Rows-1].ID = id; // Fill new element
List[Rows-1].Name = new char[maxst];
ifs.width(maxst); // avoid buffer overflow
ifs>>List[Rows-1].Name; // read into string
ifs>>List[Rows-1].Old;
ifs.ignore(INT_MAX,'\n'); // skip everything else on the line
}
}
This assumes that List and Rows are uninitialized when the function is called. Note that Columns is not used here.
Note that you'll have to clean the mess when you no longer need the List: you have first to delete all the Name and then delete List.
How to do it in more modern C++
Nowadays, you'd no longer use char* but string:
struct MyStruct {
int ID;
string Name;
int Old;
};
And you wouldn't use an array for keeping all the items, but a container such as vector:
int main ()
{
vector<MyStruct> List;
ReadFile (List, "file.txt"); // no nead for Rows. It is replaced by List.size()
return 0;
}
And then you'd read it like this:
void ReadFile (vector<MyStruct>& List, string path)
{
ifstream ifs(path);
MyStruct i;
while (ifs>>i.ID>>i.Name>>i.Old) {
List.push_back(i); // add a new item on list
ifs.ignore(INT_MAX,'\n'); // skip everything else on the line
}
}
No worries about memory management; no worries about maximum size of strings.

How to copy an array of characters to a string C++

I am writing a function that takes in a string through pass by reference and an array of characters and the size of the array. The string already has characters in it. I am trying to erase the characters in the string and copy the characters from the array.
I tried setting up a for loop to copy, but it doesn't work if the string is too small or too big. I can't use strcopy in this function. Need some guidance.
void functionname(string &first, char arr[], int size) {
int i;
(for i = 0; i < size; i++) {
first[i] = arr[i];
}
}
You can use std::string's default assignment operator = and simply do
first = arr;
std::string has function to do it first.assign(arr, size)
The below works as std::string overrides the assignment operator (=) for char* to allow direct assignment to the string from a character pointer.
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
void functionname(string &first, char arr[], int size)
{
first = arr;
}
int main()
{
std::string x = "mystring";
char buff[x.length()];
strcpy(buff, "other");
cout << x << endl;
functionname(x, buff, x.length());
cout << x << endl;
return 0;
}
string has a constructor that copies a character array and takes a count. This will work no matter what contents are inside the arr array, even embedded null characters.
void functionname(string &first, char arr[], int size) {
first = string(arr, size);
}
Again, the contents of arr are copied into the string, you don't need to keep arr around after this if you don't need it anymore.