String is out of range - c++

The task is interchange two parts of a word, which contains the dash (i.e we have 1237-456 but should transform it into 456-1237). Here`s my code, it runs but doesnt shows results as a string is out of range and i dk why. It happens in the 1st for, the second iteration ends in the error+ it happens when strlen is 5 and more. The code:
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
int main()
{
int u = 0, y = 0;
string first, second;
int i = 0;
string word;
cout << "Enter the text: " << endl;
getline(cin, word);
int l = size(word);
int f = word.find('-');
cout << "The word has " << l << " characters" << endl << endl;
for (int i = 0; i < f; i++) {
first[i] = word[i];
}
for (int i = f + 1; i < l; i++) {
second[y] = word[i];
y++;
}
cout << endl << second << " - " << first << endl;
}

first and second will not have memory allocated to them. They are initialized as strings of size 0. And for this case I would just use iterators instead of indices (though they could work too, but then you need more manual work to allocate enough room for the target strings and all).
All in all I think your code is mixing 'c' and 'c++' style a bit so here is my example:
#include <algorithm> // for find
#include <iostream>
// #include <cstdlib> // <<== this is "c" not C++
// using namespace std; <<== unlearn this
int main()
{
std::string word{ "Mississippi-delta"};
// std::string has a lenght function use that
std::cout << "The word has " << word.length() << " characters\n";
// "it" will be an iterator to the location of '-' (if any)
auto it = std::find(word.begin(), word.end(), '-');
// it points (beyond) the end of the word if no '-' is found
if (it == word.end())
{
std::cout << "no '-' found in word";
}
else
{
std::string first{ word.begin(),it };
++it; // skip '-'
std::string second{ it,word.end() };
std::cout << second << "-" << first << "\n";
}
return 0;
}

Instead of accessing the elements of first and second, just try using .push_back() to add characters from word.

Related

How to convert a string to a dictionary of letters?

I need to convert letters into a dictionary of characters.
Here's an example:
letter
l: 1
e: 2
t: 2
r: 1
I did some research and found this helpful answer, but that was using getline() and separating words by spaces. Since I am trying to split by character I don't think I can use getline() since '' isn't a valid split character. I could convert to a char* array but I wasn't sure where that would get me.
This is fairly easy in other languages so I thought it wouldn't be too bad in C++. I was hoping there would be something like a my_map[key]++ or something. In Go I would write this as
// Word map of string: int values
var wordMap = make(map[string]int)
// For each letter, add to that key
for i := 0; i < len(word); i++ {
wordMap[string(word[i])]++
}
// In the end you have a map of each letter.
How could I apply this in C++?
How could I apply this in C++?
It could look rather similar to your Go code.
// Word map of char: int values
// (strings would be overkill, since you know they are a single character)
auto wordMap = std::map<char,int>{};
// For each letter, add to that key
for ( char c : word )
wordMap[c]++;
}
Here is the unicode version of Drew Dormann's answer:
#include <locale>
#include <codecvt>
std::string word = "some unicode: こんにちは世界";
std::map<char32_t, uint> wordMap;
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
for (auto c : converter.from_bytes(word)) {
wordMap[c]++;
}
for (const auto [c, v] : wordMap) {
std::cout << converter.to_bytes(c) << " : " << v << std::endl;
}
I wrote an article about this which can be checked out here. Below i have given 2 versions of the program. Version 1 keeps track of the character count in alphabetical order. But sometimes(in case) you want the character count in insertion order for which you can use Version 2.
Version 1: Get character count in ͟a͟l͟p͟h͟a͟b͟e͟t͟i͟c͟a͟l͟ ͟o͟r͟d͟e͟r͟
#include <iostream> //needed for std::cout, std::cin
#include <map> //needed for std::map
#include <iomanip> //needed for formating the output (std::setw)
int main()
{
std::string inputString; //user input will be read into this string variable
std::cout << "Enter a string: " << std::endl;
std::getline(std::cin, inputString);
//this map maps the char to their respective count
std::map < char, int > charCount;
//iterate through the inputString
for (char & c: inputString)
{
charCount[c]++;//increment the count for character c
}
std::cout << "Total unique characters are: " << charCount.size() << std::endl;
std::cout << "------------------------------------" << std::endl;
std::cout << "Character" << std::setw(10) << "Count" << std::endl;
std::cout << "------------------------------------" << std::endl;
for (std::pair < char, int > pairElement: charCount)
{
std::cout << std::setw(4) << pairElement.first << std::setw(13) << pairElement.second << std::endl;
}
return 0;
}
Version 2: Get character count in i͟n͟s͟e͟r͟t͟i͟o͟n͟ ͟o͟r͟d͟e͟r͟
#include <iostream>
#include <map>
#include <iomanip>
int main()
{
std::string inputString;
std::cout << "Enter a string: " << std::endl;
std::getline(std::cin, inputString);
std::map < char, int > charCount;
for (char & c: inputString)
{
charCount[c]++;
}
std::cout << "Total unique characters are: " << charCount.size() << std::endl;
std::cout << "------------------------------------" << std::endl;
std::cout << "Character" << std::setw(10) << "Count" << std::endl;
std::cout << "------------------------------------" << std::endl;
std::size_t i = 0;
//just go through the inputString instead of map
for(char &c: inputString)
{
std::size_t index = inputString.find(c);
if(index != inputString.npos && (index == i)){
std::cout << std::setw(4) << c << std::setw(13) << charCount.at(c)<<std::endl;
}
++i;
}
return 0;
}

Why does my vector::erase call throw "vector subscript out of range"?

I'm writing a program that saves words from a .txt file in vector words, calculates how many words are there (num_elements) and prints these words randomly to the screen (no duplicates).
It all works fine up until rw.erase line, which just spits out the error "vector subscript out of range".
Why is my erase call throwing "vector subscript out of range"?
#include <iostream>
#include <string>
#include <fstream>
#include <Windows.h>
#include <direct.h>
#include <filesystem>
#include <time.h>
#include <random>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
void path_to_main_dir() {
string path = "C:/Randomizer/";
for (const auto& entry : experimental::filesystem::directory_iterator(path)) {
cout << entry.path() << endl;
}
}
int main() {
path_to_main_dir();
string dateread;
printf("Which file do you want to open? ");
cout << "---------------------------------------------------------------------------------------------------------" << endl;
path_to_main_dir();
cout << endl;
cout << "---------------------------------------------------------------------------------------------------------" << endl;
cout << "User: ";
getline(cin, dateread);
string path_to_file = "C:/Randomizer/" + dateread + ".txt";
ifstream readfile(path_to_file.c_str());
vector<string> words;
string word;
while (getline(readfile, word))
{
words.push_back(word);
}
readfile.close();
srand(time(NULL));
string randomword;
vector<string> rw = { words };
int num_elements = size(words);
cout << endl;
cout << "Number of words in the file: ";
cout << num_elements;
cout << endl;
for (unsigned int a = 0; a < num_elements; a = a + 1)
{
randomword = rw[rand() % num_elements];
cout << randomword << endl;
rw.erase(remove(rw.begin(), rw.end(), randomword), rw.end());
num_elements -= 1;
system("pause");
}
goto firstline;
return 0;
}
If the error only happens in the case where there are duplicates, it could be because the num_elements is wrong. The remove/erase call will have deleted as many duplicates as there are, but num_elements has only been reduced by one.
Fortunatly, vectors know their own size, so rather than trying to remember its internal information for it, you can just ask!
int main()
{
//...
//Code to read words from file
//...
cout << "Number of words in file: " << words.size() << endl;
while(!words.empty())
{
string randomWord = words[rand() % words.size()];
cout << randomWord << endl;
words.erase(remove(words.begin(), words.end(), randomWord), words.end());
}
return 0;
}
From what I can see, you only use words to create rw, so we could just use words directly instead.

C++ Trouble Modifying A String

So in this program I'm trying to go through word by word and make it only lowercase letters, no whitespace or anything else. However, my string "temp" isn't holding anything in it. Is it because of the way I'm trying to modify it? Maybe I should try using a char * instead? Sorry if this is a stupid question, I'm brand new to c++, but I've been trying to debug it for hours and can't find much searching for this.
#include <string>
#include <iostream>
#include <fstream>
#include <ctype.h>
using namespace std;
int main(int argc, char* argv[]) {
/*if (argc != 3) {
cout << "Error: wrong number of arguments." << endl;
}*/
ifstream infile(argv[1]);
//infile.open(argv[1]);
string content((std::istreambuf_iterator<char>(infile)),
(std::istreambuf_iterator<char>()));
string final;
string temp;
string distinct[5000];
int distinctnum[5000] = { 0 };
int numdist = 0;
int wordcount = 0;
int i = 0;
int j = 0;
int k = 0;
int isdistinct = 0;
int len = content.length();
//cout << "test 1" << endl;
cout << "length of string: " << len << endl;
cout << "content entered: " << content << endl;
while (i < len) {
temp.clear();
//cout << "test 2" << endl;
if (isalpha(content[i])) {
//cout << "test 3" << endl;
if (isupper(content[i])) {
//cout << "test 4" << endl;
temp[j] = tolower(content[i]);
++j;
}
else {
//cout << "test 5" << endl;
temp[j] = content[i];
++j;
}
}
else {
cout << temp << endl;
//cout << "test 6" << endl;
++wordcount;
final = final + temp;
j = 0;
for (k = 0;k < numdist;k++) {
//cout << "test 7" << endl;
if (distinct[k] == temp) {
++distinctnum[k];
isdistinct = 1;
break;
}
}
if (isdistinct == 0) {
//cout << "test 8" << endl;
distinct[numdist] = temp;
++numdist;
}
}
//cout << temp << endl;
++i;
}
cout << wordcount+1 << " words total." << endl << numdist << " distinct words." << endl;
cout << "New output: " << final << endl;
return 0;
}
You can't add to a string with operator[]. You can only modify what's already there. Since temp is created empty and routinely cleared, using [] is undefined. The string length is zero, so any indexing is out of bounds. There may be nothing there at all. Even if the program manages to survive this abuse, the string length is likely to still be zero, and operations on the string will result in nothing happening.
In keeping with what OP currently has, I see two easy options:
Treat the string the same way you would a std::vector and push_back
temp.push_back(tolower(content[i]));
or
Build up a std::stringstream
stream << tolower(content[i])
and convert the result into a string when finished
string temp = stream.str();
Either approach eliminates the need for a j counter as strings know how long they are.
However, OP can pull and endrun around this whole problem and use std::transform
std::transform(content.begin(), content.end(), content.begin(), ::tolower);
to convert the whole string in one shot and then concentrate on splitting the lower case string with substring. The colons in front of ::tolower are there to prevent confusion with other tolowers since proper namespacing of the standard library has been switched off with using namespace std;
Off topic, it looks like OP is performing a frequency count on words. Look into std::map<string, int> distinct;. You can reduce the gathering and comparison testing to
distinct[temp]++;

Program crashing in C++

I am just starting to learn C++ and this is a program I'm writing for an exercise:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
int uppercase=0, lowercase=0, digits=0, other=0, i=0;
int character;
char* string;
cout << "Enter a string!\n";
cin.getline(string, 20);
while(true)
{
character = int(*(string+i));
if (character==0)
{
break;
}
if (character > 64 && character < 91)
{
uppercase++;
}
if (character > 96 && character < 122)
{
lowercase++;
}
if (character > 47 && character <58)
{
digits++;
}
else
{
other++;
}
i++;
}
cout << "Upper case " << uppercase << "\n";
cout << "Lower case " << lowercase << "\n";
cout << "Digits " << digits << "\n";
cout << "Others " << other << "\n";
return 0;
}
The program crashes after it finishes printing the results. Am I missing something really obvious here?
Side question: The variable 'other' is always increased even if it shouldn't be. Am I using the else statement wrong?
You have not allocated memory for string
Try this (allocate on stack):
char string[256];
or (allocate on heap):
char* string = new char[256];
delete[] string;
UPDATE
Using std and predefined isdigit(), isalpha(), etc, the code can be rewritten as follows:
#include <iostream>
#include <string>
int main ()
{
int uppercase=0, lowercase=0, digits=0, other=0;
std::cout << "Enter a string!\n";
std::string myline;
std::getline(std::cin, myline);
for (std::string::iterator i = myline.begin(); i != myline.end(); ++i)
{
if (isdigit(*i))
{
digits++;
}
else if (isalpha(*i))
{
isupper(*i) ? uppercase++
: lowercase++;
}
else
{
other++;
}
}
std::cout << "Upper case " << uppercase << "\n";
std::cout << "Lower case " << lowercase << "\n";
std::cout << "Digits " << digits << "\n";
std::cout << "Others " << other << "\n";
return 0;
}
The else statement is executed if the preceding if statement is false. In your case, other is increased when (character > 47 && character <58) is false. You probably want to be using else-if's instead:
if(){
...
}else if{
...
}else if{
...
}else{
...
}
Try char string[256] instead of char* string;. I guess getline requires a pointer to allocated memory as input.
You have not allocated memory for string and using that name is probably not a good idea:
char* string ;
and alternative declaration that would work and not shadow std::string since you are have using namespace std:
char str[21] ;
In your code if you want to use std::string you have to do this:
std::string someStringVar ;
since using this won't work after you declare char *string:
string someStringVar ;
which seems to defeat the purpose of using namespace std.
You should use char instead of int to represent character. It's because int is usually 4 bytes and char is only 1 byte (so just enough to represent one character).

I wrote a c++ code to strip out the spaces of a sentence but when i try to print it it won't print past the first word

# include <iostream>
# include <ctime>
using namespace std;
int stripWhite(char *str);
int main ()
{
char str[50];
cout << "Enter a sentence . " << endl;
cin >>str;
cout << "Your sentence without spaces is : " << endl;
cout << (str) << endl; // This is my problem. The sentence only prints the first word
stripWhite(str);
cout << "There were " << stripWhite(str) << " spaces." << endl;
return 0;
}
int stripWhite(char *str)
{
char *p = str;
int count = 0;
while (*p)
{
if (*p != ' ')
count++;
{
*p++;
}
}
return count;
If you don't want to replace your function with the C++ string type, you can use cin.getline to get a c string (char array)
cin.getline(str, 50);
std::cin treats spaces as end of string indicators.
In order to get the full sentence use std::getline. since this expects a std::string as one of its parameters, you will have to adjust your stripWhite-function accordingly:
# include <iostream>
# include <string>
using namespace std;
int stripWhite(string str); //change the formal parameter's type
int main ()
{
string str;
cout << "Enter a sentence . " << endl;
getline(cin, str,'\n'); //use getline to read everything that has been entered till the press of enter
cout << "Your sentence without spaces is : " << endl;
cout << (str) << endl; // This is my problem. The sentence only prints the first word
stripWhite(str);
cout << "There were " << stripWhite(str) << " spaces." << endl;
system("pause");
return 0;
}
int stripWhite(string str)
{
int count = 0;
char* p = str.c_str;
while (*p)
{
if (*p != ' ')
count++;
{
*p++;
}
}
return count;
}
As pointed out by others, you should use std::getline instead of cin >> str.
However, there are multiple other problems in the code you provided.
Why use char array when you could use std::string ? Why are you so sure that 50 characters will be enough ?
Your stripWhite function doesn't seem to strip anything : you count the number of non-space characters, but you are not actually removing anything. Note that if you switch to std::string instead of plain of char arrays, you could use a standard algorithm to do the job (on the top of my head, I guess std::remove would be appropriate)
Assuming that stripWhite did actually modify the input string, why would you want to call it twice from your main ? If the goal is to strip the string in the first place, and then print the number of removed space, make stripWhite return the number of removed spaces and store this result in the main.
For example :
const int nbSpacesStripped = stripWhite(str);
cout << "There were " << nbSpacesStripped << "spaces." << endl;
Behold Boost String Algorithms and more particularly the replace/erase routines.
# include <iostream>
# include <string>
size_t stripWhiteSpaces(std::string& str)
{
size_t const originalSize = str.size();
boost::erase_all(str, ' ');
return originalSize - str.size();
}
int main ()
{
std::string str;
std::cout << "Enter a sentence . \n";
getline(std::cin, str);
size_t const removed = stripWhiteSpaces(str);
std::cout << "Your sentence without spaces is :\n";
std::cout << (str) << '\n';
std::cout << "There were " << removed << " spaces.\n";
system("pause");
}