Delete first and last 'X' character from character array - c++

I'm trying to delete first 'w' and last 'w' from a string.
I deleted the first 'w', but couldn't delete the last one, and here is my code:
char str1[80], *pstr1, *pstr2;
cout << "Enter a String:\n";
gets_s(str1);
pstr1 = str1;
pstr2 = new char[strlen(str1)];
int n = strlen(str1) + 1, k = 0, i = 0;
bool s = true;
while (k < n+1)
{
if (strncmp((pstr1 + k), "w", 1) != 0)
{
*(pstr2 + i) = *(pstr1 + k);
i++;
k++;
}
else if(s == true)
{
k++;
s = false;
}
else
{
*(pstr2 + i) = *(pstr1 + k);
i++;
k++;
}
}

Make your life easy and use std::string with find_first_of, find_last_of and erase.
#include <string>
void erase_first_of(std::string& s, char c)
{
auto pos = s.find_first_of(c);
if (pos != std::string::npos)
{
s.erase(pos, 1);
}
}
void erase_last_of(std::string& s, char c)
{
auto pos = s.find_last_of(c);
if (pos != std::string::npos)
{
s.erase(pos, 1);
}
}
#include <iostream>
int main()
{
std::string s = "hellow, worldw\n";
erase_first_of(s, 'w');
erase_last_of(s, 'w');
std::cout << s;
}

Related

C++ program to count repeated words in a cstring

I've been working on a C++ program, I've made the logic but I'm unable to execute it. The question is:
Task: Write a program, using functions only, with the following features.
Program reads paragraph(s) from the file and stores in a string.
Then program counts the occurrence of each word in the paragraph(s) and stores all words with their number of occurrences.
If that word has appeared more than one time in whole string, it should store the word only once along its total occurrences.
The output described in above (in part 3) must be stored in a new file.
Sample input:
is the is and the is and the and is and only that is
Sample output:
is 5
the 3
and 4
only 1
that 1
I'll cut short to Occurrence program that I've written,
My logic is to store token into character array and then compare that array with main character array and do the increment:
void occurances() {
char* string = getInputFromFile();
char separators[] = ",.\n\t ";
char* token;
char* nextToken;
char* temp[100];
token = strtok_s(string, separators, &nextToken);
cout << temp;
int counter = 0;
int i = 0;
while ((token != NULL)) {
temp[i] = token;
i++;
for (int i = 0; i < strlen(string); i++) {
for (int j = 0; j < 100; j++) {
if ((strcmp(token, *temp)) == 0) {
counter++;
}
}
cout << temp << " : " << counter << endl;
}
if (token != NULL) {
token = strtok_s(NULL, separators, &nextToken);
}
}
}
This code is preposterous I know that, But please anyone be kind enough to give me a clue, actually I'm new to C++ . Thank you
If you store token into array this array should grow dynamically because the number of tokens is not known at the beginning. And according to the task description, you cannot use C++ standard containers, so, it is necessary to implement dynamic array manually, for example:
#include <iostream>
std::size_t increase_capacity_value(std::size_t capacity) {
if (capacity == 0) {
return 1;
}
else if (capacity < (SIZE_MAX / 2)) {
return capacity * 2;
}
return SIZE_MAX;
}
bool increase_array_capacity(char**& tokens_array, std::size_t*& tokens_count, std::size_t& capacity) {
const std::size_t new_capacity = increase_capacity_value(capacity);
if (new_capacity <= capacity) {
return false;
}
const std::size_t tokens_array_byte_size = new_capacity * sizeof(char*);
char** const new_tokens_array = static_cast<char**>(std::realloc(tokens_array, tokens_array_byte_size));
if (new_tokens_array == nullptr) {
return false;
}
tokens_array = new_tokens_array;
const std::size_t tokens_count_byte_size = new_capacity * sizeof(std::size_t);
std::size_t* const new_tokens_count = static_cast<std::size_t*>(std::realloc(tokens_count, tokens_count_byte_size));
if (new_tokens_count == nullptr) {
return false;
}
tokens_count = new_tokens_count;
capacity = new_capacity;
return true;
}
bool add_token(char* token, char**& tokens_array, std::size_t*& tokens_count, std::size_t& array_size, std::size_t& array_capacity) {
if (array_size == array_capacity) {
if (!increase_array_capacity(tokens_array, tokens_count, array_capacity)) {
return false;
}
}
tokens_array[array_size] = token;
tokens_count[array_size] = 1;
++array_size;
return true;
}
std::size_t* get_token_count_storage(char* token, char** tokens_array, std::size_t* tokens_count, std::size_t array_size) {
for (std::size_t i = 0; i < array_size; ++i) {
if (std::strcmp(token, tokens_array[i]) == 0) {
return tokens_count + i;
}
}
return nullptr;
}
bool process_token(char* token, char**& tokens_array, std::size_t*& tokens_count, std::size_t& array_size, std::size_t& array_capacity) {
std::size_t* token_count_ptr = get_token_count_storage(token, tokens_array, tokens_count, array_size);
if (token_count_ptr == nullptr) {
if (!add_token(token, tokens_array, tokens_count, array_size, array_capacity)) {
return false;
}
}
else {
++(*token_count_ptr);
}
return true;
}
int main() {
char string[] = "is the is and the is and the and is and only that is";
char separators[] = ",.\n\t ";
std::size_t token_array_capacity = 0;
std::size_t token_array_size = 0;
char** tokens_array = nullptr;
std::size_t* tokens_count = nullptr;
char* current_token = std::strtok(string, separators);
while (current_token != nullptr) {
if (!process_token(current_token, tokens_array, tokens_count, token_array_size, token_array_capacity)) {
break;
}
current_token = std::strtok(nullptr, separators);
}
// print the report only if all tokens were processed
if (current_token == nullptr) {
for (std::size_t i = 0; i < token_array_size; ++i) {
std::cout << tokens_array[i] << " : " << tokens_count[i] << std::endl;
}
}
std::free(tokens_array);
std::free(tokens_count);
}
godbolt.org
okay what if i want to store any token once, in an array and then replace it with new word while deleting duplicates in character array
It is also possible solution. But in general case, it is also necessary to allocate the memory dynamically for the current token. Because the lengths of tokens are also not known at the beginning:
void replace_chars(char* str, const char* chars_to_replace) {
while (str && *str != '\0') {
str = std::strpbrk(str, chars_to_replace);
if (str == nullptr) {
break;
}
const std::size_t number_of_delimiters = std::strspn(str, chars_to_replace);
for (std::size_t i = 0; i < number_of_delimiters; ++i) {
str[i] = '\0';
}
str += number_of_delimiters;
}
}
bool keep_token(char*& token_storage, const char* new_token) {
if (new_token == nullptr) {
return false;
}
const std::size_t current_token_len = token_storage ? std::strlen(token_storage) : 0;
const std::size_t requried_token_len = std::strlen(new_token);
if (token_storage == nullptr || current_token_len < requried_token_len) {
token_storage =
static_cast<char*>(std::realloc(token_storage, (requried_token_len + 1) * sizeof(char)));
if (token_storage == nullptr) {
return false;
}
}
std::strcpy(token_storage, new_token);
return true;
}
std::size_t count_tokens_and_replace(char* str, std::size_t str_len, const char* token) {
std::size_t number_of_tokens = 0;
std::size_t i = 0;
while (i < str_len) {
while (str[i] == '\0') ++i;
if (std::strcmp(str + i, token) == 0) {
replace_chars(str + i, token);
++number_of_tokens;
}
i += std::strlen(str + i);
}
return number_of_tokens;
}
int main() {
char string[] = "is the is and the is and the and is and only that is";
char separators[] = ",.\n\t ";
const std::size_t string_len = std::strlen(string);
replace_chars(string, separators);
std::size_t i = 0;
char* token = nullptr;
while (true) {
while (i < string_len && string[i] == '\0') ++i;
if (i == string_len || !keep_token(token, string + i)) break;
std::cout << token << " : " << count_tokens_and_replace(string + i, string_len - i, token) << std::endl;
}
std::free(token);
}
godbolt.org
But if it is known that the token length cannot be greater than N, it is possible to use the static array of chars to keep the current token. And it will allow to remove dynamic memory allocation from the code.

getting "_throw_bad_array_new_lengthv" when trying to use std::vector::push_back inside a class

I'm creating a custom language parser in C++, I'm struggling with a runtime error, where I have a std::vector<std::string> member of a class with a constructor.
The full error is:
The procedure entry point
_ZSt28__throw_bad_array_new_lengthv could no be located
in the dynamic link library
"path_to_executable"
This error is throw whenever I try to use std::vector::push_back in my code, but shouldn't std::vector be a dynamically sized data container? Why is this error occurring?
Some of my codes:
//"lib/cursor.h"
#ifndef T_CURSOR
#define T_CURSOR
#include <iostream>
struct Cursor
{
private:
std::string input;
int inputLength;
char getChar(int p);
public:
char character;
int pos;
int line;
int column;
bool eof;
bool lineBreak;
Cursor(std::string i);
void walk(bool back = false);
void walkTimes(int times, bool back = false);
void move(int toPos);
void skipIgnore();
std::string toString();
};
#endif
//"lib/cursor.cpp"
#include <sstream>
#include "cursor.h"
Cursor::Cursor(std::string i)
{
this->input = i;
this->inputLength = i.length();
this->character = i.at(0);
this->pos = 0;
this->line = 0;
this->column = 0;
this->eof = false;
this->lineBreak = false;
}
char Cursor::getChar(int pos)
{
if (pos < 0 || pos >= this->inputLength)
{
return EOF;
}
return this->input.at(pos);
}
void Cursor::walk(bool back)
{
if (back)
{
this->pos--;
this->column--;
if (this->lineBreak)
{
this->line--;
this->column = 0;
for (int i = this->pos - 1; i >= 0; i--)
{
if (this->getChar(i) == '\n')
break;
this->column++;
}
}
}
else
{
this->pos++;
this->column++;
if (this->lineBreak)
{
this->line++;
this->column = 0;
}
}
this->character = this->getChar(this->pos);
this->eof = this->character == EOF;
this->lineBreak = this->character == '\n';
}
void Cursor::walkTimes(int times, bool back)
{
for (int i = 0; i < times; i++)
{
this->walk(back);
}
}
void Cursor::move(int pos)
{
if (pos < 0)
pos = 0;
if (pos > this->inputLength - 1)
pos = this->inputLength - 1;
this->pos = 0;
this->character = this->input.at(0);
this->line = 0;
this->column = 0;
this->eof = false;
this->lineBreak = this->character == '\n';
while (this->pos < pos)
this->walk();
}
void Cursor::skipIgnore()
{
while (this->character == ' ' ||
this->character == '\n' ||
this->character == '\t')
this->walk();
if (this->character == '#')
{
while (!this->eof && this->character != '\n')
this->walk();
}
while (this->character == ' ' ||
this->character == '\n' ||
this->character == '\t')
this->walk();
}
std::string Cursor::toString()
{
std::stringstream ss("");
ss << "(P:" << this->pos;
ss << " L:" << this->line;
ss << " C:" << this->column;
ss << " \"" << this->character << "\")";
return ss.str();
}
//"lib/lexer.h"
#ifndef T_LEXER
#define T_LEXER
#include <iostream>
#include <vector>
#include "cursor.h"
class Lexer
{
private:
std::string input;
protected:
Cursor cursor;
std::vector<std::string> matchStack;
std::vector<std::vector<Cursor>> cursorStack;
public:
Lexer(std::string input);
std::string getStr(int pos);
void setStr(int pos, std::string str);
Cursor getCursorStart(int pos);
Cursor getCursorEnd(int pos);
bool match(std::string str);
};
#endif
//"lib/lexer.cpp"
#include "lexer.h"
Lexer::Lexer(std::string input) : cursor(input)
{
this->input = input;
}
std::string Lexer::getStr(int pos)
{
if (this->matchStack.size() == 0)
return this->input;
while (pos < 0)
pos += this->matchStack.size();
while (pos >= this->matchStack.size())
pos -= this->matchStack.size();
return this->matchStack[pos];
}
void Lexer::setStr(int pos, std::string str)
{
if (this->matchStack.size() == 0)
return;
while (pos < 0)
pos += this->matchStack.size();
while (pos >= this->matchStack.size())
pos -= this->matchStack.size();
this->matchStack[pos] = str;
}
Cursor Lexer::getCursorStart(int pos)
{
if (this->cursorStack.size() == 0)
return Cursor(this->input);
while (pos < 0)
pos += this->cursorStack.size();
while (pos >= this->cursorStack.size())
pos -= this->cursorStack.size();
return this->cursorStack[pos][0];
}
Cursor Lexer::getCursorEnd(int pos)
{
if (this->cursorStack.size() == 0)
return Cursor(this->input);
while (pos < 0)
pos += this->cursorStack.size();
while (pos >= this->cursorStack.size())
pos -= this->cursorStack.size();
return this->cursorStack[pos][1];
}
bool Lexer::match(std::string str)
{
this->cursor.skipIgnore();
const std::string ss = this->input.substr(this->cursor.pos, str.length());
if (ss == str)
{
this->matchStack.push_back(ss); // Getting error if I include this line
const Cursor startCursor = this->cursor;
this->cursor.walkTimes(str.length());
const Cursor endCursor = this->cursor;
this->cursorStack.push_back({startCursor, endCursor});
return true;
}
return false;
}
//"test.cpp"
#include "lib/cursor.h"
#include "lib/lexer.h"
#include <iostream>
using namespace std;
int main()
{
string input = "Something to test";
Lexer lexer = Lexer(input);
cout << "Start" << endl;
cout << lexer.match("Something") << endl;
return 0;
}
I'm compiling my program with g++ on Windows: g++ test.cpp lib/cursor.cpp lib/lexer.cpp -o test.exe
I got the same error when compiling in command line using g++. But it works well in code blocks. To solve this problem try compiling with -static-libstdc++. It should solve the problem.

pattern matching (codejam round 1A previous year) solution not working

I am trying previous year's codejam question of round 1A
link to question
i have submitted this code(start reading from main method, for ease)-
#include <bits/stdc++.h>
using namespace std;
#define range(t) for (int i = 0; i < t; i++)
#define rangeG(i, t) for (i = 0; i < t; i++)
#define printVec(vec) \
for (auto c : vec) \
{ \
cout << c << endl; \
}
vector<string> separate(string s)
{
vector<string> result;
range(s.size())
{
if (s[i] == '*')
{
string temp = s.substr(0, i + 1);
if (temp.size() > 1)
{
result.push_back(temp);
}
s = s.substr(i, s.size());
i = 0;
}
else if (i == (s.size() - 1))
{
string temp = s.substr(0, i + 1);
result.push_back(temp);
s = s.substr(i, s.size());
}
}
return result;
}
void removeAsterisk(string &s)
{
s.erase(remove(s.begin(), s.end(), '*'), s.end());
}
bool setStart(string s, string &start)
{
bool possible = 1;
removeAsterisk(s);
range(min(s.size(), start.size()))
{
if (s[i] != start[i])
{
possible = 0;
}
}
if (possible)
{
if (s.size() >= start.size())
{
start = s;
}
}
return possible;
}
bool setEnd(string s, string &end)
{
bool possible = 1;
removeAsterisk(s);
range(min(s.size(), end.size()))
{
if (s[s.size() - 1 - i] != end[end.size() - 1 - i])
{
possible = 0;
}
}
if (possible)
{
if (s.size() >= end.size())
{
end = s;
}
}
return possible;
}
void solve()
{
int n;
cin >> n;
vector<string> allS;
bool possible = 1;
string start = "";
string end = "";
string middle = "";
string result = "";
while (n--)
{
string str;
cin >> str;
if (count(str.begin(), str.end(), '*') == 0)
{
result = str;
}
vector<string> temp = separate(str);
for (string s : temp)
{
if (s[0] != '*')
{
possible = setStart(s, start);
}
if (s[s.size() - 1] != '*')
{
possible = setEnd(s, end);
}
if (possible && count(s.begin(), s.end(), '*') == 0)
{
result = s;
break;
}
if (s[0] == '*' && s[s.size() - 1] == '*')
{
removeAsterisk(s);
middle += s;
}
}
}
if (possible)
{
if (result.size() == 0)
{
result = start + middle + end;
}
cout << result << "\n";
}
else
{
cout << "*\n";
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t = 0;
cin >> t;
range(t)
{
cout << "Case #" << i + 1 << ": ";
solve();
}
return 0;
}
it seems correct to me and i have tested many times for many examples, but it is losing in test set-1(exactly one * (asterisk) character and and always the first character of string). Can anyone tell what's wrong?
you can consider code of first ranked here (it has all solutions,check only for "pattern matching" task) for help. I know that the wrong answer is an edge case and if it passes test set 1 then it will pass others.

How do I find the size of a char array?

How should I go about finding the length of a char array in C++? I've tried two methods already, but they both have resulted in the wrong number of characters in the array. I've used strlen and the sizeof operator so far, to no avail.
void countOccurences(char *str, string word)
{
char *p;
string t = "true";
string f = "false";
vector<string> a;
p = strtok(str, " ");
while (p != NULL)
{
a.push_back(p);
p = strtok(NULL, " ");
}
int c = 0;
for (int i = 0; i < a.size(); i++)
{
if (word == a[i])
{
c++;
}
}
int length = sizeof(str); //This is where I'm having the problem
string result;
cout << length << "\n";
if (length % 2 != 0)
{
if (c % 2 == 0)
{
result = "False";
}
else
{
result = "True";
}
}
else
{
if (c % 2 == 0)
{
result = "True";
}
else
{
result = "False";
}
}
if (strlen(str) != 0)
{
cout << result;
}
}
int boolean()
{
char str[1000];
cin.getline(str, sizeof(str));
string word = "not";
countOccurences(str, word);
return 0;
}
sizeof(str) is wrong. It gives you the size of a pointer (str is a pointer), which is a fixed number, normally either 4 or 8 depending at your platform.
std::strlen(str) is correct, but strtok inserts a bunch of \0 into your array before you try to obtain the size. strlen will stop at the first \0, and give you the number of characters preceeding it.
Call strlen before strtok and save its return value to a variable.
Here you can find a modern c++ solution:
#include <iostream>
#include <string_view>
#include <string>
#include <type_traits>
template<typename String>
inline std::size_t StrLength(String&& str)
{
using PureString = std::remove_reference_t<std::remove_const_t<String>>;
if constexpr(std::is_same_v<char, PureString>){
return 1;
}
else
if constexpr(std::is_same_v<char*, PureString>){
return strlen(str);
}
else{
return str.length();
}
}
template<
typename String,
typename Lambda,
typename Delim = char
>
void ForEachWord(String&& str, Lambda&& lambda, Delim&& delim = ' ')
{
using PureStr = std::remove_reference_t<std::remove_reference_t<String>>;
using View = std::basic_string_view<typename PureStr::value_type>;
auto start = 0;
auto view = View(str);
while(true)
{
auto wordEndPos = view.find_first_of(delim, start);
auto word = view.substr(start, wordEndPos-start);
if (word.length() > 0){
lambda(word);
}
if (wordEndPos == PureStr::npos)
{
break;
}
start = wordEndPos + StrLength(delim);
}
}
int main() {
std::string text = "This is not a good sentence.";
auto cnt = 0;
ForEachWord(
text,
[&](auto word)
{
//some code for every word... like counting or printing
if (word == "not" ){
++cnt;
}
},
' '
);
std::cout << cnt << "\n";
}
The "end of a string" is the char '\0' check for that character to stop the search.

I keep getting a segfault every time I run this program, but I cannot understand why

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;
}