c++ Segmentation fault when trying to reverse print an array - c++

I have a array consisting of chars like [1,2,3,4,5,.,..] and I have a loop that looks like
for (size_t i = 0; i < size; ++i)
os << data[i]; // os is std::ostream&
This loop prints the array in the correct order without any errors. But when I use this loop to print it backwards
for (size_t i = (size - 1); i >= 0; --i)
os << data[i];
I get a segmentation fault error. Any reason why this can happen?

The condition i >= 0 is always true (because size_t is an unsigned type). You've written an infinite loop.
Doesn't your compiler warn you about that? I know g++ -Wextra does here.
What you can do instead is this:
for (size_t i = size; i--; ) {
os << data[i];
}
This uses post-decrement to be able to check the old value of i, which allows the loop to stop just after i = 0 (at which point i has wrapped around to SIZE_MAX).

size_t is unsigned int so it always remain positive, so your loop is an infinite loop

You can use a C++ for-in loop to avoid the problem. Example:
#include <iostream>
#include <vector>
#include <boost/range/adaptor/reversed.hpp>
using std::vector;
using std::cout;
using boost::adaptors::reverse;
int main()
{
auto v = vector<char>{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'X' };
char const* sep = "";
for (auto c : v)
{
cout << sep << c;
sep = " ";
}
cout << "\n";
sep = "";
for (auto c : reverse(v))
{
cout << sep << c;
sep = " ";
}
cout << "\n";
}

Related

When Indexing a string, s[i] works yet s.at(i) throws. Why?

Ran across this curious situation where replacing [] with at() failed.
We have a vector of strings some of which have embedded nuls separating subsequent use tags.
The code extracts the initial string up to the first nul in each vector.
Is use of [] undefined behavior that at() is catching?
#include<iostream>
#include <string>
#include <vector>
using namespace std::literals;
using std::string, std::vector, std::cout;
int main()
{
// given a vector of strings with embedded nuls, extract chars until the first nul
vector<string> vs{"item1\0A"s, "item2"s};
// This works fine.
for (const string& s : vs)
{
for (int i = 0; s[i]; i++)
cout << s[i];
cout << "\n";
}
// s.at(i) is a bounds checking version of s[i]
// but fails
for (const string& s : vs)
{
for (int i = 0; s.at(i); i++) // Out of Range Exception thrown here
cout << s.at(i);
cout << "\n";
}
}
No, there is no undefined behavior
https://en.cppreference.com/w/cpp/string/basic_string/operator_at
For operator [], if pos == size(), a reference to the character with value CharT() (the null character) is returned.
However, at(size()), will throw. Something to keep in mind.
// This works.
for (const string& s : vs)
{
for (int i = 0; i < s.length() && s.at(i); i++)
cout << s.at(i);
cout << "\n";
}

Why STL map's method "find" raise "core dumped" with the std::bitset type key? [duplicate]

I have a array consisting of chars like [1,2,3,4,5,.,..] and I have a loop that looks like
for (size_t i = 0; i < size; ++i)
os << data[i]; // os is std::ostream&
This loop prints the array in the correct order without any errors. But when I use this loop to print it backwards
for (size_t i = (size - 1); i >= 0; --i)
os << data[i];
I get a segmentation fault error. Any reason why this can happen?
The condition i >= 0 is always true (because size_t is an unsigned type). You've written an infinite loop.
Doesn't your compiler warn you about that? I know g++ -Wextra does here.
What you can do instead is this:
for (size_t i = size; i--; ) {
os << data[i];
}
This uses post-decrement to be able to check the old value of i, which allows the loop to stop just after i = 0 (at which point i has wrapped around to SIZE_MAX).
size_t is unsigned int so it always remain positive, so your loop is an infinite loop
You can use a C++ for-in loop to avoid the problem. Example:
#include <iostream>
#include <vector>
#include <boost/range/adaptor/reversed.hpp>
using std::vector;
using std::cout;
using boost::adaptors::reverse;
int main()
{
auto v = vector<char>{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'X' };
char const* sep = "";
for (auto c : v)
{
cout << sep << c;
sep = " ";
}
cout << "\n";
sep = "";
for (auto c : reverse(v))
{
cout << sep << c;
sep = " ";
}
cout << "\n";
}

Generate random letter array and count occurences

Hello I am trying to generate a random array of the length that the user inputs. My array should then print and display the occurences of those letters in the array. So far this only prints up to the letter g and the occurences are incorrect. If someone could tell me what I am doing wrong it would help alot. Thank you.
#include <iostream>
#include <cstring>
#include <ctime>
#include <cstdlib>
using namespace std;
int main()
{
srand(time(0));
int i, num;
char ch;
char chars[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int freq[26]={0};
cout << "How many letters do you want in your string? ";
cin >> num;
for (i=0; i < num; i++)
{
ch = chars[rand()%26];
chars[i]=ch;
freq[i] +=1;
cout << ch;
}
for (char lower = 'a'; lower <='z'; lower++)
{
cout << "\nLetter" << lower << "is " << freq[lower] << "times";
}
}
Problem 1
The lines
chars[i]=ch;
freq[i] +=1;
are not right. You need to use:
int index = ch - 'a';
freq[index] += 1;
Problem 2
The index in the for loop for printing the data is not correct either.
You need to use:
for (char lower = 'a'; lower <='z'; lower++)
{
int index = lower - 'a';
cout << "\nLetter" << lower << "is " << freq[index] << "times";
}
Important Note
It is worth noting that the C++ standard does not guarantee that lower case letters are contiguous. (Thanks #MartinBonner). For instance, if your system uses EBCDIC encoding your program won't work.
To make your code robust, it will be better to use a std::map.
int main()
{
srand(time(0));
int i, num;
char ch;
char chars[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
std::map<char, int> freq;
// Initialize freq.
for ( ch : chars )
{
freq[ch] = 0;
}
cout << "How many letters do you want in your string? ";
cin >> num;
for (i=0; i < num; i++)
{
ch = chars[rand()%26];
freq[ch] +=1;
}
for (auto item : freq )
{
cout << "\nLetter" << item.first << "is " << item.second << "times";
}
}
You might wanna give a look to C++11 Pseudo-random number generation here is a short way of generating the range that you want using this:
#include <algorithm>
#include <array>
#include <random>
#include <vector>
using namespace std;
int main()
{
int arraySize = 35;
mt19937 engine{random_device{}()};
uniform_int_distribution<> dist{'a', 'z'};
vector<char> vec;
generate_n(back_inserter(vec), arraySize, [&]() { return static_cast<char>(dist(engine); }));
//To count occurrences
array<int, 26> freq;
for (auto c : vec) { ++freq[c-'a']; }
return 0;
}
You should not write into chars, and freq should be extended to cover the a...z range (the ASCII codes), which it does not. Also, increase at index ch, not at i.
I do not even know that range from the top of my head, but it could be modified to track all possible bytes instead (0...255), see result on https://ideone.com/xPGls7
List of changes:
int freq[256]={0}; // instead of int freq[26]={0};
// chars[i]=ch; is removed
freq[ch] +=1; // instead of freq[i] +=1;
Then it works.
Using lambda functions to do most of the work.
#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <numeric>
#include <ostream>
#include <random>
#include <string>
#include <utility>
#include <vector>
using namespace std::string_literals;
int main()
{
std::mt19937::result_type seed = std::random_device{}();
auto engine = std::mt19937(seed);
auto dist = std::uniform_int_distribution<>('a', 'z');
auto random_letter = [&engine, &dist]() { return static_cast<char>(dist(engine)); };
std::cout << "How many letters do you want to generate? "s;
int n;
if (!(std::cin >> n)) { return EXIT_FAILURE; }
auto letters = std::vector<char>();
std::generate_n(std::back_inserter(letters), n, random_letter);
auto zero = std::map<char, int>();
auto const frequencies = std::accumulate(std::cbegin(letters), std::cend(letters), zero,
[](auto& acc, auto c)
{
++acc[c];
return acc;
});
for (auto const [c, freq] : frequencies)
{
std::cout << "The letter '"s << c << "' appeared "s << freq << " times." << std::endl;
}
return 0;
}

How to truncate a string array? C++

Let's say I have a string array with 5 words and I want to only output the first 3 letters of each word. How do I go upon doing this? I know how to do it with one string but with an array of strings I get lost.
This is how to do it with one string
std::string test = "hello";
std::cout << test << std::endl;
test = test.substr(0,3);
std::cout << test << std::endl;
What I want to do is this
std::string test[5] = {"hello", "pumpkin", "friday", "snowboard", "snacks"};
I want to cout the first 3 letters of each word. I tried test[5] = test[5].substr(0,3); and that did not work.
test[5] doesn't work because you only have 5 items in your array, only indexes 0 to 4 are valid.
Generally with arrays you need to write a loop to go through each array item in turn, for instance
for (int i = 0; i < 5; ++i)
test[i] = test[i].substr(0,3);
for (int i = 0; i < 5; ++i)
cout << test[i] << endl;
With test[5] you are reading out of bounds thus invoking undefined behavior. Arrays in C++ are zero indexed so the last element would be test[4]. Create a function that utilizes for example the std::next function or string's substr member function. Call inside a range based loop:
#include <iostream>
#include <string>
void foo(const std::string& s) {
if (s.size() >= 3) {
std::cout << std::string(s.begin(), std::next(s.begin(), 3)) << '\n';
// or simply:
std::cout << s.substr(0, 3) << '\n';
}
}
int main() {
std::string test[5] = { "hello", "pumpkin", "friday", "snowboard", "snacks" };
for (const auto& el : test) {
foo(el);
}
}
test[5] = test[5].substr(0,3); won't work and more over you don't have `test[5]`, index starts from `0`.
you may want to do like this
for(int i=0 ; i<5; i++) {
test[i] = test[i].substr(0,3);
cout << test[i] << endl;
}
substr is what you are looking for. Here is my implementation.
#include <array>
#include <string>
#include <iostream>
int main () {
std::array<std::string,5> list {"hello", "pumpkin", "friday", "snowboard", "snacks"};
for (const auto &word : list){
std::cout << word << std::endl;
}
for (auto &word : list){
word = word.substr(0,3);
}
for (const auto &word : list){
std::cout << word << std::endl;
}
}
Use the standard library.
std::for_each(std::begin(test), std::end(test), [] (auto& s) { s.erase(3); });
Or even a simple range-based for loop:
for (auto&& s : test) {
s.erase(3); // Erase from index 3 to end of string.
}
Or maybe even create another container with views of the original strings:
auto test2 = std::accumulate(std::begin(test), std::end(test),
std::vector<std::string_view>{},
[] (auto& prev, std::string_view sv) -> decltype(prev)& {
prev.push_back(sv.substr(0, 3));
return prev;
});

Can the Duplicate Characters in a string be Identified and Quantified in O(n)?

This comment suggests that there is a O(n) alternative to my O(n log n) solution to this problem:
Given string str("helloWorld") the expected output is:
l = 3
o = 2
My solution was to do this:
sort(begin(str), end(str));
for(auto start = adjacent_find(cbegin(str), cend(str)), finish = upper_bound(start, cend(str), *start); start != cend(str); start = adjacent_find(finish, cend(str)), finish = upper_bound(start, cend(str), *start)) {
cout << *start << " = " << distance(start, finish) << endl;
}
Which is obviously limited by the sorting of str. I think this would require a bucket sort solution? Is there anything more clever that I'm missing?
Here's one way, which is O(N) at the expense of maintaining storage for every possible char value.
#include <string>
#include <limits.h> // for CHAR_MIN and CHAR_MAX. Old habits die hard.
int main()
{
std::string s("Hello World");
int storage[CHAR_MAX - CHAR_MIN + 1] = {};
for (auto c : s){
++storage[c - CHAR_MIN];
}
for (int c = CHAR_MIN; c <= CHAR_MAX; ++c){
if (storage[c - CHAR_MIN] > 1){
std::cout << (char)c << " " << storage[c - CHAR_MIN] << "\n";
}
}
}
This portable solution is complicated by the fact that char can be signed or unsigned.
Here is what #bathsheba mentioned and with improvements by #Holt:
#include <string>
#include <climits>
#include <iostream>
void show_dup(const std::string& str) {
const int sz = CHAR_MAX - CHAR_MIN + 1;
int all_chars[sz] = { 0 };
// O(N), N - the length of input string
for(char c : str) {
int idx = (int)c;
all_chars[idx]++;
}
// O(sz) - constant. For ASCII char it will be 256
for(int i = 0; i < sz; i++) {
if (all_chars[i] > 1) {
std::cout << (char)i << " = " << all_chars[i] << std::endl;
}
}
}
int main()
{
std::string str("helloWorld");
show_dup(str);
}