Array element never successfully added? (C++) - c++

I'm fairly new to C++. I tried implementing a really simple hash table, and then I wanted to see if my hashing algorithm put the element in the correct position. However, apparently the element wasn't even added to the array at all:
void add(string str, array<string, 2000> data) {
int i = makeHash(str) % data.size();
while (data[i++ % data.size()].compare("") != 0)
continue;
data[i % data.size()] = str;
cout << "Added!"; // successfully prints, meaning str was added to data
}
int main() {
array<string, 2000> data;
string str = "The quick brown fox something something";
add(str, data);
for (int i = 0; i < data.size(); i++)
if (data[i].compare(str) == 0)
cout << i; // never prints... so str was never added to data?
return 0;
}

You need to pass data variable as reference -
void add(string str, array<string, 2000> &data)
What you are doing here is pass by value, so as soon as your function ends, value of data is destroyed.

Try passing data by reference, i.e.
void add ( string str, array<string, 2000>& data ){...}
Passing by value will mean a copy of data will be passed into the function.
Also, there's an off by one error. I'm sure you want to have:
data[(i-1) % data.size()] = str;
because i will still be incremented when you exit the while loop.

Related

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.

String manipulation , at a complete loss

I am trying to grab sub-strings out of a larger string and I have got it to work in a small program but when I try to run it into the real program it just goes wrong. I am building off someone else s function and got it to work for my purpose, but cannot get it to work in the main program I need it in. I will limit the program down to where I think error is occurring.
Problem: I pass in same value into function findStats(std::string sString) but get different results.
Case I:
stats = findStats("^9dff9d[Attribute 0% Active Defense 0]\r^f2f3f2Mana: 1411 ^00ff00(+1975)\r^f2f3f2^9dff9d[Attribute 0% Active Mana 0]\r^f2f3f2^ffc000Fortify Level: 12/12\r^f2f3f2^006effIdentified Attribute: + 6% Crit Damage\rIdentified Attribute: + 6 Accuracy\r^f2f3f2^006eff^O053Sacrifice Elapse(6/8)\r^00ff00 ^O041Desollar's Shadow\rÌÌÌÌÌÌÌÌL«");
The above case will output correctly and stores \r offsets correctly.
Case II:
stats = findStats((std::string)((char*)&buffer));
Case II is the case I need to work and has the same value as above Case I at start of function findStats but offsets for \r Are not stored for w.e reason when sString has same value at start of function.
//Function that finds positioning of \r
void calc_z (std::string &s, std::vector<int> & z)
{
int len = s.size();
z.resize (len);
int l = 0, r = 0;
for (int i=1; i<len; ++i)
if (z[i-l]+i <= r)
z[i] = z[i-l];
else
{
l = i;
if (i > r) r = i;
for (z[i] = r-i; r<len; ++r, ++z[i])
if (s[r] != s[z[i]])
break;
--r;
}
}
std::vector<std::string> findStats(std::string sString){
//sString is exactly the same in value for both cases of stats at this point
int offSet = 0;
int sOffsets[100] = {};
std::vector<std::string> t1;
std::string main_string = sString;
std::string substring = "\r";
std::string working_string = substring + main_string;
std::vector<int> z;
calc_z(working_string, z);
for(int i = substring.size(); i < working_string.size(); ++i){
if(z[i] >=substring.size()){
sOffsets[offSet] = i;
offSet++;
}
}
.... code ....problem occurs right above offsets are not stored for \r
}
void main()
{
std::vector<std::string> stats;
std::string buffer[10];
...code...
...code to find string and store in buffer...
stats = findStats((std::string)((char*)&buffer));
//stats = findStats("^9dff9d[Attribute 0% Active Defense 0]\r^f2f3f2Mana: 1411 ^00ff00(+1975)\r^f2f3f2^9dff9d[Attribute 0% Active Mana 0]\r^f2f3f2^ffc000Fortify Level: 12/12\r^f2f3f2^006effIdentified Attribute: + 6% Crit Damage\rIdentified Attribute: + 6 Accuracy\r^f2f3f2^006eff^O053Sacrifice Elapse(6/8)\r^00ff00 ^O041Desollar's Shadow\rÌÌÌÌÌÌÌÌL«");
for( std::vector<std::string>::const_iterator i = stats.begin(); i != stats.end(); ++i)std::cout << *i << ' ' << std::endl;
std::cin.get();
}
This statement: (std::string)((char*)&buffer) does not do what you think it does.
std::vector is not a simple array.
If you take address of std::vector, that won't be the address of the first element within std::vector.
YOu can't just cast const char* or char* into std::string. You can, however, construct new std::string using provided const char* or char * c-style string. const char *str = asdf; std::string s = std::string(str);.
So, to summarize:
If you want to pass several strings at once in std::vector, pass the buffer by const reference
typedef std::vector<std::string> StringVector;
void test(const StringVector& v){
for (StringVector::const_iterator i = v.begin(); i != v.end(); i++)
std::cout << *i << std::endl;
}
...
StringVector strings;
test(strings);
If you want to WRITE something into std::vector, pass it by reference:
typedef std::vector<std::string> StringVector;
void test(const StringVector& out){
out.push_back("test");
}
...
StringVector strings;
test(strings);
If you want to pass a single string from, vector, just pass the element itself (by reference, const reference, or by value, depending on what you want to do with it), without casts.
typedef std::vector<std::string> StringVector;
void test(const std::string& s){
std::cout << s << std::endl;
}
...
StringVector strings;
strings.push_back("test");
test(strings[0]);
--edit--
IN addition to that:
std::vector<std::string> findStats(std::string sString){
//sString is exactly the same in value for both cases of stats at this point
int offSet = 0;
int sOffsets[100] = {};//<<here's a problem
Using array with fixed size in this case is a bad idea. Your array is small, and it WILL overflow on any string larger than 100 bytes, breaking/crashing your program. You can simply store results on std::vectro<std::string>, make vector of structs, or use std::map, depending on your goals.

Grabbing a portion of a string like substr

So I'm making a function that is similar to SubStr. This is an assignment so I cannot use the actual function to do this. So far I have created a function to take a string and then get the desired substring. My problem is returning the substring. In the function when I do Substring[b] = AString[b]; the substring is empty, but if I cout from inside the function I get the desired substring. So what is wrong with my code?
Here is a working demo: http://ideone.com/4f5IpA
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length);
int main() {
char someString[] = "abcdefg";
char someSubString[] = "";
subsec(someString, someSubString, 1, 3);
cout << someSubString << endl;
return 0;
}
void subsec(char AString[], char Substring[], int start, int length) {
for (int b = start; b <= length; b++) {
Substring[b] = AString[b];
}
}
Maybe this does what you're looking for? It's hard to say as your initial implementation used the length parameter as more of an end position.
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length)
{
const int end = start + length;
int pos = 0;
for(int b = start; b < end; ++b)
{
Substring[pos++] = AString[b];
}
Substring[pos] = 0;
}
int main()
{
char someString[50] = "abcdefghijklmnopqrstuvwxyz";
char someSubString[50];
subsec(someString, someSubString, 13, 10);
cout << someSubString << endl;
return 0;
}
There are several problems with the code:
1) The char arraysomeSubString has size 1 which cannot hold the substring.
2) The subsec is not correctly implemented, you should copy to the Substring from index 0.
Also remember to add \0 at the end of the substring.
void subsec(char AString[], char *Substring, int start, int length) {
int ii = 0;
for (int jj = start; jj <= length; jj++, ii++) {
Substring[ii] = AString[jj];
}
Substring[ii] = '\0';
}
You need to allocate more than 1 byte for someSubString i.e.
char someSubString[] = "xxxxxxxxxxxxxxxxxx";
or just
char someSubString[100];
if you know the max size you'll ever need.
Either would allocate enough space for the string you're copying to it. Then, you're not doing anything about the terminating 0 either. At the end of a C-style string there needs to be a terminating null to signify end of string. Otherwise cout will print something like;
abcdefgxxxxxxx
if you initialized with x's as I indicated.
There are a few problems with your code as it stands. Firstly, as your compiler is no doubt warning you, in C++ a string literal has type const char[], not just char[].
Secondly, you need to have enough space to store your substring. A good way to do this is for your function to allocate the space it needs, and then pass back a pointer to this memory. This is the way things are typically done in C code. The only thing is that you have to remember to delete the allocated array when you're done with it. (There are other, better ways to do this in C++, with things like smart pointers and wrapper objects, but those come later :-) ).
Thirdly, you'll have a problem if you request a length which is actually longer than the passed-in string -- you'll run off the end and start copying random memory (or just crash), which is definitely not what you want. C strings are terminated with a "nul byte" -- so you need to check whether you've come across this.
Speaking of the nul, you need to make sure that your substring ends with one.
Lastly, it's not really a problem but there's no need for the start parameter, you can just pass a pointer to the middle of the array if you want to.
char* substring(const char* str, int length)
{
// Allocate memory for substring;
char* subs = new char[length+1];
// Copy characters from given string
int i = 0;
while (i < length && str[i] != '\0') {
subs[i] = str[i];
i++;
}
// Append the nul byte
subs[i] = '\0';
return subs;
}
int main()
{
const char someString[] = "foobarbaz"; // Note -- must be const in C++
char* subs = substring(someString + 3, 3);
assert(strcmp(subs, "bar") == 0);
delete subs;
}

C++ char sequence function always return empty string

Just start learning C++ and trying to make a simple function that do substring with following code:
char* substring(int start, int end, const char* target)
{
size_t length = strlen(target);
char result[(length + 1)];
int iterator = 0;
for(int i = start; i < length; i++)
{
if(i <= end)
{
result[iterator] = target[i];
iterator++;
}
}
result[iterator] = '\0';
cout << result << endl; // This give correct result "aya";
return result;
}
When I use these function on main method:
int main(int argc, char** argv) {
char some_text[] = "Saya Makan";
char* sub = substring(1, 3, some_text); // No string returned
cout << "Substring Result is: " << sub;
return 0;
}
It give output is like this:
aya
Substring Result is:
RUN SUCCESSFUL (total time: 44ms)
As seen on the result, my function isn't returning anything but empty string although a line of code before return, the "result" variable echoed result correctly. Would you please explain to me what is happening inside my function, am I missing something?
You are returning pointer to a local array which is not required to live beyond the function.
You need to make the buffer persist beyond the scope of the function by allocating it dynamically using malloc. And ofcourse remember to free it later.
Oh just noticed its C++.
So drop the idea of malloc and free simply use std::string and not char *.