Split text using delimiter? - c++

I wanted to create a function that will split a string by a delimiter.. I know there's already a function that does this thing but I wanted to make on my own.. But it doesn't work as it should.
char** Engine::splitString(const char* text, char delimiter)
{
char** splitted;
splitted = (char**)malloc(50 * sizeof(char*));
for (int y = 0; y < 50; y++)
splitted[y] = (char*)malloc((strlen(text) + 2) * sizeof(char));
int delimiterPosition[50];
int arrayLength = 0;
int f = 0;
int g = 0;
for (int x = 0; x < strlen(text); x++)
{
if (text[x] == delimiter)
{
delimiterPosition[f] = x;
f++;
}
}
for (int x = 0; x < 50; x++)
if (delimiterPosition[x] > 0 )
arrayLength++;
while (g < arrayLength) {
if (g == 0) {
for (int y = 0; y < delimiterPosition[0]; y++)
{
splitted[g][y] = text[y];
}
}
else if(g > 0)
{
for (int y = delimiterPosition[g - 1]; y < delimiterPosition[g] - delimiterPosition[g - 1]; y++)
{
splitted[g][y] = text[y];
}
}
g++;
}
return splitted;
}
First of all, I declared a two dimensional char array -> splitted. This was the variable that I should store my results into. Then I allocated a memory for it.. I wanted to have 50 words maximum. After that I created integer array.. this served as a storage for delimiters' positions. I also defined some variables below it for my code. Then I looped through the text to see if there's any delimiter.. if yes, I wanted to store it's position to a certain position in array, starting off from 0. I looped through delimiterPosition's array to how many positions I have stored. Then I made a simple loop using while to take all the characters up to the delimiter's position and store them to splitted[g][y] .. g represents the whole word.. y represents the character in that word. If g was greater than zero, I tok the previous position of a delimiter and then substracted the current from the previous.. and that gave me the distance between the first delimiter and the next..
The main problem here is that the first word is written correctly, the second one is not working, but it has some weird characters behind it when I try to call it.. is the text somehow leaking? the second one isn't being stored at all?:
char** strings = en.splitString("Hello;boy", ';');
printf("%s", strings[1]);
First word:
Second:
Any solutions, guys ? :) Thank you for any comment.

This does not initialize the memory:
int delimiterPosition[50];
So its content is potentially random (and its undefined to read from unless you initialize it first). So here:
if (delimiterPosition[x] > 0 ) // Is potentially invalid if x >= f
Easily solved with:
int delimiterPosition[50] = {0};
Potential for overflow here:
delimiterPosition[f] = x;
f++;
You don't validate that f remains in the correct range (less than 50). Another easy fix:
size_t stringLen = strlen(text); // Don't need to recalculate this each time!
for (int x = 0; f < 50 && x < stringLen; x++)
{
if (text[x] == delimiter)
{
delimiterPosition[f] = x;
f++;
}
}
Here is the problem you are complaining about:
for (int y = 0; y < delimiterPosition[0]; y++)
{
splitted[g][y] = text[y];
}
You copy the string.
But you don't add a terminator to the string. So when you try and print it you see all the extra characters on the end.
for (int y = 0; y < delimiterPosition[0]; y++)
{
splitted[g][y] = text[y];
}
splitted[g][y] = '\0'; // Add string terminator.
For the second a subsequent string you have the null terminator problem. But you also have the issue that you are copying the string to not the beginning.
// After the first string the value of y in an offset into text only
// So when used with `splitted[g]` you are offset from the beginning
// if the string.
splitted[g][y] = text[y];
Also your test for the end of the string is wrong:
Remember you start at:
int y = delimiterPosition[g - 1]
So y is an offset into the string. So as you increase it it will always be an offset not a length.
// So this test is wrong (you are using a length not an offset.
y < delimiterPosition[g] - delimiterPosition[g - 1]
Lets fix both at the same time:
int dstIndex = 0;
for (int y = delimiterPosition[g - 1]; y < delimiterPosition[g]; y++, dstIndex++)
{
splitted[g][dstIndex] = text[y];
}
splitted[g][dstIndex] = '\0';

Related

Converting grid-based level in string form into a 2D array in C++?

I've been completely lost on this one for the past day or so so I hope some of you may be able to figure it out.
So basically I have a string of a grid-based level that I want to convert to a 2D array of numbers, but the conversion is not working properly. Now I do know a two things:
I am reading the txt file correctly and
Through some testing I know that when I manually set the values, objects render where they should so it can't be that (I use OpenGL if in any way that's relevant).
Any and all help/feedback would be appreciated and thanks in advance!
The level txt file looks like this:
0
0
0
0
0
0
0
00000000
But this is the output (it should align with the zero-es in the txt file).
This is the code I use for the conversion (keep in mind that both xSize and ySize are 8):
levelDat = new char* [xSize];
int atIndex = 0;
for (int x = 0; x < xSize; x++) {
levelDat[x] = new char[ySize];
for (int y = 0; y < ySize; y++) {
if (level[atIndex] != '\n') {
levelDat[x][y] = level[atIndex];
}
atIndex++;
}
}
for (int x = 0; x < xSize; x++) {
for (int y = 0; y < ySize; y++) {
if (levelDat[x][y] != AIR) {
blockDat.push_back(x * BLOCK_SIZE);
blockDat.push_back(y * BLOCK_SIZE);
switch (levelDat[x][y]) {
case DIRT:
blockDat.push_back(1);
break;
default:
blockDat.push_back(0);
break;
}
}
}
}
Okay I fixed it. I changed level[atIndex] to row.push_back(level[y*xSize+x]) since I wasn't reading the level array in the correct order.

stoi() terminate after throwing and instance of 'std::invalid argument in c++-- What am I doing wrong?

Fairly new to coding. Trying some of the easy projects at LeetCode, and failing... Ha! I am trying to take an integer and convert it to a string so I can reverse it, then re-convert the reversed string back into a integer.
This code is throwing the "terminate after throwing and instance of 'std::invalid argument' what(): stoi" error. I've spent an hour searching google and other questions here on SO, but can't figure out why it's not working.
bool isPalindrome(int x) {
std::string backwards ="";
std::string NumString = std::to_string(x);
for (int i = NumString.size(); i >= 0 ; i--) {
backwards += NumString[i];
}
int check = std::stoi(backwards);
if (check == x) {
return true;
}
else {
return false;
}
}
EDIT: I think I figured it out. It was adding the null character to the end of the string upon first conversion, then adding it to the beginning of the string when I reversed it. Spaces can't be converted to integers.
So... I changed this line and it works:
for (int i = NumString.size() - 1; i >= 0 ; i--)
you can also reverse number without using string.
bool isPalindrome(int x) {
long long rev = 0;
int cur = x;
while( cur > 0) {
rev *= 10;
rev += cur % 10;
cur /=10;
}
return rev == x;
}
Its simpler than your answer that you edited in. YOu have
for (int i = NumString.size(); i >= 0 ; i--) {
backwards += NumString[i];
}
Imagine that Numstring has length 3 (no matter what spaces, digits,....)
So now you are efectively doing
for (int i = 3; i >= 0 ; i--) {
backwards += NumString[i];
}
So first loop goes
backwards += NumString[3];
well the indexes of things in an array of length 3 in c++ are 0,1,2. YOu are going one off the end
This is why you see loops doing
for(int i = 0; i < len; i++){}
Note the i < len not i <= len

Recursion loses solution in array while unwinding

I am trying to design a recursive solution to Lewis Carroll's 'Word Ladder' game
The game attempts to link a starting word, for example 'WET' to an ending word, e.g. 'DRY' using a chain of words where between any 2 words just 1 letter is different. There is a limit on how many words can be used to make the chain.
For example for WET - DRY the solution is WET - bet - bat - bay - day - DRY
I am using the below recursive C function
exit condition: word is 1 step away from the 'target word' - i.e. if it sees DAY (= 1 step away from DRY), it returns true
It finds the solution, however, the problem is: it does not pass the solution back to original function. With each return call, the chain shaves off one word - i.e. the function's innermost call correctly solves 'bet - bat - bay - day' and stores it in the answer_chain - however once calls unwind - this array somehow gets passed as 'bet - bat - bay' (=loses 1 word), and so on, and as a result the original outermost function call gets no information about the solution.
I've tried:
Copying 'by value' by creating a c-style string first, assigning it back later
Copying the array item-by-item only when the first return is reached, and just assigning one array to the other otherwise (answer_chain = answer_chain_temp)
I've unfortunately not been able to figure out what the issue actually is.
Any help would be greatly appreciated.
bool find_chain(const char* start_word, const char* target_word, const char* answer_chain[], int max_steps){
if (answer_chain[0] == NULL) {} // This is to zero out incoming answer_chain
else if (!valid_step(start_word,answer_chain[0])){
delete[] answer_chain;
for (unsigned int i = 0; i < sizeof(answer_chain)/sizeof(answer_chain[0]);++i){
answer_chain[i] = NULL;
}
}
int filled_words = find_sz_of_char_arrays(answer_chain); // Looks for null-terminator
string previous_word, try_new_word;
bool is_solved = false;
if (valid_chain(answer_chain) && valid_step(answer_chain[filled_words-1],target_word) ) {
is_solved = true;
}
if (is_solved) {return true;}
if (max_steps == 0 && !is_solved) {return false;}
if (filled_words > 0) { previous_word = answer_chain[filled_words-1];} else {previous_word = start_word;}
for (unsigned int j = 0; j < strlen(start_word); ++j){
try_new_word = previous_word;
for (unsigned int i = 0; i < 26; ++i){
char new_char = i + 'A';
if (try_new_word.at(j) != new_char) { // has to be different from character already in place
try_new_word.at(j) = new_char;
if (valid_step(previous_word.c_str(),try_new_word.c_str()) && !is_word_already_in_chain(try_new_word.c_str(),answer_chain) ) {
const char** answer_chain_temp = new const char*[15]; // append 'try' word to answer array
for (int k = 0; k < filled_words;++k){
answer_chain_temp[k] = answer_chain[k];}
answer_chain_temp[filled_words] = try_new_word.c_str();
answer_chain_temp[filled_words+1] = NULL;
if (find_chain(start_word,target_word,answer_chain_temp,max_steps-1)){
delete[] answer_chain;
answer_chain = new const char*[15];
for (int kk = 0; kk < 15;++kk) {
if (answer_chain_temp[kk]!=NULL){
answer_chain[kk] = answer_chain_temp[kk];
}
}
delete[] answer_chain_temp;
return true;
} // if successful - append the word
} // if valid step
} // if letter is differerent
} // for i
} // for j
return false;
}
EDIT:
I've now changed the middle part to copy the .s_str() by value, however the issue still seems to persist. I believe something is off with how I am copying and deleting after the solution has been found:
const char** answer_chain_temp = new const char*[15]; // append 'try' word to answer array
for (int k = 0; k < filled_words;++k){answer_chain_temp[k] = answer_chain[k];}
char * writable = new char[try_new_word.size() + 1];
std::copy(try_new_word.begin(), try_new_word.end(), writable);
writable[try_new_word.size()] = '\0';
answer_chain_temp[filled_words] = writable;
answer_chain_temp[filled_words+1] = NULL;
if (find_chain(start_word,target_word,answer_chain_temp,max_steps-1)){
delete[] answer_chain;
answer_chain = new const char*[15];
for (int kk = 0; kk < 15;++kk) {
if (answer_chain_temp[kk] != NULL){
answer_chain[kk] = answer_chain_temp[kk]; // <<<<<< I believe the problem is here
}
}
display_chain(answer_chain,cout); cout << endl;
delete[] answer_chain_temp;
return true;```

Array of pointers remaining null despite being directly set

I have a list of 'cell' objects in a 2d array of length [sizeX][sizeY]. These Cell objects contain an array of type *Cell, which should point to each of the given cell's adjacent cells in the format North, East, South, West (Never Eat Soggy Waffles).
This array is called compass, and is defined with a length of 4. After the cells have been initialized (at which time all values of compass are set to nullptr), I have a loop which attempts to fill Cell.compass with pointers to the appropriate nearby cells.
However, I have found that despite all this, in each cell I have found that compass still is full of null values.
In this loop, I also run a function Cell::computeTopology() which populates a vector (which is a property of Cell) of the valid non-null indexes of compass. This is similarly empty.
I have made a breakpoint both before and after this function has been called to the exact same effect. Regardless I will include this function as well. I'm utterly perplexed and some help here would be greatly appreciated.
Problem area:
const int sizeX = SCREEN_WIDTH / SCALE;
const int sizeY = SCREEN_HEIGHT / SCALE;
Cell cells[sizeX][sizeY];
for (int x = 0; x < sizeX; x++){
for (int y = 0; y < sizeY; y++){
cells[x][y].setPos(x, y);
cells[x][y] = Cell();
//cells[x][y].setColor(rand() % 255, rand() % 255, rand() % 255);
}
}
for (int x = 0; x < sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
Cell c = cells[x][y];
if (x - 1 >= 0) {
c.compass[3] = &cells[x - 1][y];
}
if (x + 1 < (SCREEN_WIDTH / SCALE)) {
c.compass[1] = &cells[x + 1][y];
}
if (y - 1 >= 0) {
c.compass[0] = &cells[x][y - 1];
}
if (y + 1 < (SCREEN_HEIGHT / SCALE)) {
c.compass[2] = &cells[x][y + 1];
}
c.computeTopology();
}
}
And the computeTopology() function
void Cell::computeTopology()
{
int i = 0;
for (Cell *c : compass) {
if (c != nullptr) {
notNull.push_back(i);
i++;
}
}
}
Change
Cell c = cells[x][y]; // make a copy
to
Cell& c = cells[x][y];
you want to modify item of array, not copy.
Another issue
cells[x][y].setPos(x, y);
cells[x][y] = Cell(); // ?
you are setting some members of cells[x][y] by calling setPos and after it you are overwriting cells[x][y] by default constructed Cell object. I think the second line in above code should be removed.
Your words
which populates a vector (which is a property of Cell) of the valid
non-null indexes of compass
so i index should be advanced with every iteration of for loop:
int i = 0;
for (Cell *c : compass) {
if (c != nullptr) {
notNull.push_back(i);
}
++i; // moved
}

C++ Read Access Violation

The title says it all. I am having trouble figuring out what that error could mean, as I've never heard of it prior to now.
string Cracker_Functions::Loop(string Password, char fullset[]) {
int x = 0;
char word[32] = "";
int Passwordlen = Password.length();
for (int a = 0; a < Passwordlen; a++) {
for (int b = 0; b < 92; b++) {
for (int c = 0; c < 92; c++) {
word[b] = fullset[c];
if (word == Password) {
return word;
}
}
word[b] = fullset[a];
continue;
}
word[a] = fullset[x];
x += 1;
}
return "";
}
The program throws an exception at:
word[a] = fullset[x];
Notes on the function:
All necessary files are included.
The function is predefined in another file.
The number 32 is the maximum size of password the computer will try to guess.
The number 92 is the total amount of characters that the computer can cycle through.
fullset is all the characters in one list.
word represents what the program is currently cycling through. For example the current combination of characters is "h#(u?"
x is the counter for when the first loop is done with the other 2, and needs to reassign a new letter to begin again with.