I wrote the following code:
#include <iostream>
#include <time.h>
#include <string.h>
int main()
{
std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
std::string word;
unsigned long long int i = 0;
srand(time(NULL));
while(true)
{
int randomIndex = rand() % 27;
word += alphabet[randomIndex];
// If the word might be the desired word, "hi"
if (word.size() == 2)
{
// The word should only be printed if its length is equal to 2
std::cout << i << " : " << word << word.size() << std::endl;
if (word == "hi")
{
break;
}
else // The word isn't "hi". We reset the variable word and continue looping
{
word = "";
}
i += 1;
}
}
return 0;
}
It is supposed to put together random letters until word is equal to "hi".
Until that, only 2-character words should be printed, but for some reason the program seems to be thinking that 1-character words have a length of 2. Therefore it also prints 1-character words.
Can anyone please help me?
Let's change the print debug line as follows.
std::cout << randomIndex << '\t' << i << " : " << word << " --> " << word.size() << std::endl;
Here, when we check the strings that look like a single character but 2 characters, we come across them in a random number of 26.
The length of the string "abcdefghijklmnopqrstuvwxyz" is 26. Since the indices of the arrays start from 0, they must be in the range of random numbers [0, 25] we produce.
Then let's update the line of code where we generate the random number as follows.
int randomIndex = rand() % 26
In the wrong code, the 26th character corresponds to the memory cell at the end of the string. Let's take a different example to understand.
int main()
{
char arr[5];
std::string a = "a";
a+=arr[1];
std::cout << a << " " << a.size() << '\n'; // 2
a+=arr[5];
std::cout << a << " " << a.size() << '\n'; // 3
a+=arr[6];
std::cout << a << " " << a.size() << '\n'; // 4
return 0;
}
Related
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;
}
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.
So i have a c++ vector which contains about 106 thousand words which are stored on vector<string>words i need to find the longest word in this vector and i also need to get the location at which the word is, for example (1,2,3) in my vector. I need this location because i have two other vectors which has the meaning and the type for the words. vector<string>definition, vector<string>type
Please help
My current code
this code is not working at all
copy_if(words.begin(), words.end(), back_inserter(length), [](const string& x) { return x.length() > 40; });// looks for words longer than 7 letters
for (const string& s : length)
{
cout << "found!!" << endl;
auto i = find(words.begin(), words.end(), s);//looks for the word in the words vector
if (i != words.end())
{
auto pos = i - words.begin();
//displays the word, type and the definition of the word that the user has entered
cout << "Word : " << words[pos] << '\n';
cout << "Type : " << definitions[pos] << '\n';
cout << "Definition: " << types[pos] << '\n';
cout << '\n';
}
else
cout << "word not found" << endl;
}
You could use the standard algorithm std::max_element to search through the vector<string>.
Example:
#include <algorithm> // max_element
#include <iostream>
#include <iterator> // distance
#include <string>
#include <vector>
int main() {
std::vector<std::string> words{"a", "bb", "ccc"};
auto it = std::max_element(words.begin(), words.end(),
[](const auto& a, const auto& b) {
return a.size() < b.size();
});
std::cout << "The longest word is " << *it << " at (zero-based) pos "
<< std::distance(words.begin(), it) << '\n';
}
Output:
The longest word is ccc at (zero-based) pos 2
I would prefer thinking simply: just check length of elements according to each indice and update information according to that.
std::vector<std::string> length;
// initialize the vector length
size_t max_length = 0; // the length of longest word(s)
std::vector<size_t> max_indice; // the indice of longest word(s)
for (size_t i = 0; i < length.size(); i++) {
size_t this_len = length[i].length();
if (this_len > max_length) {
// new record
max_length = this_len;
max_indice.clear();
max_indice.push_back(i);
} else if (this_len == max_length) {
// tie
max_indice.push_back(i);
}
}
for (size_t pos : max_indice) {
cout << "Word : " << words[pos] << '\n';
cout << "Type : " << definitions[pos] << '\n';
cout << "Definition: " << types[pos] << '\n';
cout << '\n';
}
I wrote a text cipher program. It seems to works on text strings a few characters long but does not work on a longer ones. It gets the input text by reading from a text file. On longer text strings, it still runs without crashing, but it doesn’t seem to work properly.
Below I have isolated the code that performs that text scrambling. In case it is useful, I am running this in a virtual machine running Ubuntu 19.04. When running the code, enter in auto when prompted. I removed the rest of code so it wasn't too long.
#include <iostream>
#include <string>
#include <sstream>
#include <random>
#include <cmath>
#include <cctype>
#include <chrono>
#include <fstream>
#include <new>
bool run_cypher(char (&a)[27],char (&b)[27],char (&c)[11],char (&aa)[27],char (&bb)[27],char (&cc)[11]) {
//lowercase cypher, uppercase cypher, number cypher, lowercase original sequence, uppercase original sequence, number original sequence
std::ifstream out_buffer("text.txt",std::ios::in);
std::ofstream file_buffer("text_out.txt",std::ios::out);
//out_buffer.open();
out_buffer.seekg(0,out_buffer.end);
std::cout << "size of text: " << out_buffer.tellg() << std::endl;//debug
const int size = out_buffer.tellg();
std::cout << "size: " << size << std::endl;//debug
out_buffer.seekg(0,out_buffer.beg);
char *out_array = new char[size + 1];
std::cout << "size of out array: " << sizeof(out_array) << std::endl;//debug
for (int u = 0;u <= size;u = u + 1) {
out_array[u] = 0;
}
out_buffer.read(out_array,size);
out_buffer.close();
char original[size + 1];//debug
for (int bn = 0;bn <= size;bn = bn + 1) {//debug
original[bn] = out_array[bn];//debug
}//debug
for (int y = 0;y <= size - 1;y = y + 1) {
std::cout << "- - - - - - - -" << std::endl;
std::cout << "out_array[" << y << "]: " << out_array[y] << std::endl;//debug
int match;
int case_n; //0 = lowercase, 1 = uppercase
if (isalpha(out_array[y])) {
if (islower(out_array[y])) {
//std::cout << "out_array[" << y << "]: " << out_array[y] << std::endl;//debug
//int match;
for (int ab = 0;ab <= size - 1;ab = ab + 1) {
if (out_array[y] == aa[ab]) {
match = ab;
case_n = 0;
std::cout << "matched letter: " << aa[match] << std::endl;//debug
std::cout << "letter index: " << match << std::endl;//debug
std::cout << "case_n: " << case_n << std::endl;//debug
}
}
}
if (isupper(out_array[y])) {
for (int cv = 0;cv <= size - 1;cv = cv + 1) {
if (out_array[y] == bb[cv]) {
case_n = 1;
match = cv;
std::cout << "matched letter: " << bb[match] << std::endl;//debug
std::cout << "letter index: " << match << std::endl;//debug
std::cout << "case_n: " << case_n << std::endl;//debug
}
}
}
if (case_n == 0) {
out_array[y] = a[match];
std::cout << "replacement letter: " << a[match] << " | new character: " << out_array[y] << std::endl;//debug
}
if (case_n == 1) {
std::cout << "replacement letter: " << b[match] << " | new character: " << out_array[y] << std::endl;//debug
out_array[y] = b[match];
}
}
if (isdigit(out_array[y])) {
for (int o = 0;o <= size - 1;o = o + 1) {
if (out_array[y] == cc[o]) {
match = o;
std::cout << "matched letter: " << cc[match] << std::endl;//debug
std::cout << "letter index: " << match << std::endl;//debug
}
}
out_array[y] = c[match];
std::cout << "replacement number: " << c[match] << " | new character: " << out_array[y] << std::endl;//debug
}
std::cout << "- - - - - - - -" << std::endl;
}
std::cout << "original text: " << "\n" << original << "\n" << std::endl;
std::cout << "encrypted text: " << "\n" << out_array << std::endl;
delete[] out_array;
return 0;
}
int main() {
const int alpha_size = 27;
const int num_size = 11;
char l_a_set[] = "abcdefghijklmnopqrstuvwxyz";
char cap_a_set[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char n_a_set[] = "0123456789";
std::cout << "sizeof alpha_set: " << std::endl;//debug
char lower[alpha_size] = "mnbvcxzasdfghjklpoiuytrewq";
char upper[alpha_size] = "POIUYTREWQASDFGHJKLMNBVCXZ";
char num[num_size] = "9876543210";
int p_run; //control variable. 1 == running, 0 == not running
int b[alpha_size]; //array with values expressed as index numbers
std::string mode;
int m_set = 1;
while (m_set == 1) {
std::cout << "Enter 'auto' for automatic cypher generation." << std::endl;
std::cout << "Enter 'manual' to manually enter in a cypher. " << std::endl;
std::cin >> mode;
std::cin.ignore(1);
std::cin.clear();
if (mode == "auto") {
p_run = 2;
m_set = 0;
}
if (mode == "manual") {
p_run = 3;
m_set = 0;
}
}
if (p_run == 2) { //automatic mode
std::cout <<"lower cypher: " << lower << "\n" << "upper cypher: " << upper << "\n" << "number cypher: " << num << std::endl;//debug
run_cypher(lower,upper,num,l_a_set,cap_a_set,n_a_set);
return 0;//debug
}
while (p_run == 3) {//manual mode
return 0;//debug
}
return 0;
}
For example, using an array containing “mnbvcxzasdfghjklpoiuytrewq” as the cipher for lower case letters, I get “mnbv” if the input is “abcd”. This is correct.
If the input is “a long word”, I get “m gggz zzzv” as the output when it should be “m gkjz rkov”. Sort of correct but still wrong. If I use “this is a very very long sentence that will result in the program failing” as the input, I get "uas” as the output, which is completely wrong. The program still runs but it fails to function as intended. So as you can see, it does work, but not on any text strings that are remotely long. Is this a memory problem or did I make horrible mistake somewhere?
For your specific code, you should run it through a memory checking tool such as valgrind, or compile with an address sanitizer.
Here are some examples of memory problems that most likely won't crash your program:
Forgetting to delete a small object, which is allocated only once in the program. A memory leak can remain undetected for decades, if it does not make the program run out of memory.
Reading from allocated uninitialized memory. May still crash if the system allocates objects lazily at the first write.
Writing out of bounds slightly after an object that sits on heap, whose size is sizeof(obj) % 8 != 0. This is so, since heap allocation is usually done in multiples of 8 or 16. You can read about it at answers of this SO question.
Dereferencing a nullptr does not crash on some systems. For example AIX used to put zeros at and near address 0x0. Newer AIX might still do it.
On many systems without memory management, address zero is either a regular memory address, or a memory mapped register. This memory can be accessed without crashing.
On any system I have tried (POSIX based), it was possible to allocate valid memory at address zero through memory mapping. Doing so can even make writing through nullptr work without crashing.
This is only a partial list.
Note: these memory problems are undefined behavior. This means that even if the program does not crash in debug mode, the compiler might assume wrong things during optimization. If the compiler assumes wrong things, it might create an optimized code that crashes after optimization.
For example, most compilers will optimize this:
int a = *p; // implies that p != nullptr
if (p)
boom(p);
Into this:
int a = *p;
boom(p);
If a system allows dereferencing nullptr, then this code might crash after optimization. It will not crash due to the dereferencing, but because the optimization did something the programmer did not foresee.
# 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");
}