c++ vector size and capacity outputting same value - c++

when I was researching vectors, I noticed that size() is supposed to give the number of elements in the vector, right? So, when I found c++ does not have a string split() function built-in, I decided to make one. The problem is, vector.size() displays the same value as vector.capacity() as shown in the code:
#include <iostream>
#include <algorithm>
using namespace std;
void split(string input, char chr, vector<string> list) {
string add;
string conv;
int size = 0;
for (int i = 0; i <= input.size(); i++) {
if ((input[i] != char(chr)) && (input[i] != 0)) {
conv = input[i];
add += conv;
}
else {
cout << list.size() << endl;
if (size <= list.capacity()) {
list[size] = add;
add = "";
size++;
}
}
}
}
int main() {
vector<string> list(6);
split("test1,test2", ',', list);
for (int i = 0; i < 2; i++) {
cout << list[i] << endl;
}
}
The output is this:
6
6
<blank line>
<blank line>
whereas it SHOULD be this from my understanding:
1
2
test1
test2
Edit: if this is of any importance, I am compiling with -std=c++11

You initialize the vector with size 6, not capacity 6. It will be constructed with 6 empty elements inside and thus setting values 0 and 1 won't change that.
The reason why you see only blank lines is that you pass the vector by value instead of by reference to you split function.

#include <iostream>
#include <string>
#include <vector>
void split (const std::string& s, char sep, std::vector<std::string>& words)
{
if (s.empty()) return;
std::size_t beg = 0;
std::size_t end = s.find(sep, beg);
while (end != std::string::npos)
{
words.push_back(s.substr(beg, end - beg));
beg = end + 1;
end = s.find(sep, beg);
}
words.push_back(s.substr(beg));
}
int main() {
std::vector<std::string> words;
split("test1,test2", ',', words);
for (std::size_t i = 0; i != words.size(); ++i) {
std::cout << words[i] << std::endl;
}
return 0;
}

Related

How do I extract all the numbers in a string where the numbers are interspersed with letters?

How do I loop through a string consisting of numbers and letters and add only numbers to the vector?
For example if the input is:
e385p336J434Y26C2Z6X5Z2
I want to get a vector of int like this:
number = {385, 336, 434, 26, 2, 6, 5, 2}
The best I got was to iterate over the line and add all the digits like that:
#include <bits/stdc++.h>
int main(){
string f = "e385p336J434Y26C2Z6X5Z2";
vector<int> f_numb;
string sum;
for (int i = 0; i < f.size(); ++i){
if (('0' <= f[i]) && (f[i] <= '9')){
sum += (f[i]);
}
}
//std::cout << sum << std::endl;
vector<int> m_numb;
for (int i = 0; i < sum.size(); ++i){
m_numb.push_back(sum[i] - '0');
}
int sm;
for (int i = 0; i < m_numb.size(); ++i){
sm += m_numb[i];
std::cout << m_numb[i] << " ";
}
std::cout << std::endl;
}
Foregoing the unstated reason you're not using std::isdigit, you can/should simply build each number as you process its digits. Note that the code below does NOT check, nor care, about unsigned overflow, and makes no attempt at processing negative numbers.
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string f = "e385p336J434Y26C2Z6X5Z2";
std::vector<unsigned int> f_numb;
for (auto it = f.begin(); it != f.end();)
{
if ('0' <= *it && *it <= '9')
{
unsigned int sm = 0;
for (;it != f.end() && '0' <= *it && *it <= '9'; ++it)
sm = (sm * 10) + (*it - '0');
f_numb.emplace_back(sm);
}
else
{
++it;
}
}
for (auto x : f_numb)
std::cout << x << ' ';
std::cout << '\n';
}
Output
385 336 434 26 2 6 5 2
That, assuming I understand your question vs. your code, which differ highly in their apparent goals.
Another aproach making more use of standard library functions.
Live demo here : https://onlinegdb.com/8eEgREuEN
I tend to make functions of substeps so I can test them individually
#include <algorithm>
#include <iterator> // back_inserter
#include <string>
#include <vector>
#include <iostream>
#include <string_view>
// I like to make functions for substeps (they tend to be reusable)
std::vector<std::string> get_number_substrings(const std::string& input)
{
static const std::string_view digits{ "0123456789" };
std::vector<std::string> substrings;
auto start_pos = input.find_first_of(digits, 0ul);
auto end_pos = start_pos;
auto max_length = input.length();
while (start_pos < max_length)
{
end_pos = std::min(max_length, input.find_first_not_of(digits, start_pos));
if (end_pos != start_pos)
{
substrings.emplace_back(&input[start_pos], end_pos - start_pos);
start_pos = input.find_first_of(digits, end_pos);
}
}
return substrings;
}
std::vector<int> get_numbers(const std::string& input)
{
auto numbers = get_number_substrings(input);
std::vector<int> output;
// now transform the string to vector<int>
// the back_inserter is needed because output doesn't have allocated memory yet
// and that needs to be build up during the transform.
// https://en.cppreference.com/w/cpp/iterator/back_inserter
// https://en.cppreference.com/w/cpp/algorithm/transform
std::transform(numbers.begin(), numbers.end(), std::back_inserter(output), [](const std::string& string)
{
return std::stoi(string);
});
return output;
}
int main()
{
std::string input{ "e385p336J434Y26C2Z6X5Z2" };
auto output = get_numbers(input); // output will be a std::vector<int>
// Use range based for loop
// https://en.cppreference.com/w/cpp/language/range-for
bool comma = false;
for (const int value : output)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
return 0;
}
Will this work for you?
std::string f = "e385p336J434Y26C2Z6X5Z2";
std::vector<int> f_numb;
std::string sum;
#define MAX_DIGITS 25
char aBuildNumber[MAX_DIGITS];
int aBuildCount=0;
std::vector<int> m_numb;
for (int i = 0; i < f.size(); ++i)
{
if (!isdigit(f[i]) || aBuildCount>=MAX_DIGITS-1)
{
if (aBuildCount>0) m_numb.push_back(atoi(aBuildNumber));
aBuildCount=0;
}
else {aBuildNumber[aBuildCount++]=f[i];aBuildNumber[aBuildCount]=0;}
}
if (aBuildCount>0) m_numb.push_back(atoi(aBuildNumber));
int sm=0;
for (int i = 0; i < m_numb.size(); ++i)
{
sm += m_numb[i];
std::cout << m_numb[i] << " ";
}
std::cout << std::endl;

Parsing does not work: terminate called after throwing an instance of "std::invalid argument"

I want to have a function which returns a vector of 2 integers. The input is a string.
The layout of the string that is inserted should always be like this: "COORDINATES 123 456" with the coordinates being integers of any length.
If the string is "COORDINATES 123" or "COORDINATES 123 456 789", the function should return an empty vector.
#include <iostream>
#include <string>
#include <vector>
std::vector<int> getCoordinates(std::string string){
auto count = 0;
std::string coordinates;
int coordinatesInt;
std::vector<int> vector;
int i, j = 0;
for(int i = 0; i < string.size(); i++){
if(string.at(i) == ' '){
count++;
j = 1;
while(string.at(i+j) != ' ' && string.at(i+j) <= string.length()){
coordinates.push_back(string.at(i+j));
j++;
}
coordinatesInt = std::stoi(coordinates);
vector.push_back(coordinatesInt);
}
}
if(count != 2){
vector.clear();
}
std::cout << count << std::endl;
return vector;
}
int main()
{
std::string coordinates = "COORDINATES 123 456";
std::vector<int> vectorWithCoordinates = getCoordinates(coordinates);
std::cout << vectorWithCoordinates[1] << std::endl;
//vectorWithCoordinates should now contain {123, 456}
return 0;
}
However, when I run this code, I get an error message saying:
terminate called after throwing an instance of "std::invalid argument"
#include <iostream>
#include <string>
#include <vector>
std::vector<int> getCoordinates(std::string string){
auto count = 0;
std::string coordinates;
int coordinatesInt;
std::vector<int> vector;
for(unsigned i = 0; i < string.size(); i++){
if(string.at(i) == ' '){
count++;
unsigned j = 1;
while(i+j<string.size() && string.at(i+j) != ' '){ //checks that you do not go out of range before checking the content of the string
coordinates.push_back(string.at(i+j));
j++;
}
coordinatesInt = std::stoi(coordinates);
vector.push_back(coordinatesInt);
}
coordinates.clear();//clears the string in order to have two different integers
}
if(count != 2){
vector.clear();
}
std::cout << count << std::endl;
return vector;
}
int main()
{
std::string coordinates = "COORDINATES 123 456";
std::vector<int> vectorWithCoordinates = getCoordinates(coordinates);
for(auto i : vectorWithCoordinates)
std::cout<<i<<"\n";
//vectorWithCoordinates should now contain {123, 456}
return 0;
}
The problem in the code was that you tried to access the content of the string at position i+j without being sure that that position is not out of range. I made minimal modifications to your code to obtain the right output (I think).

facing error in converting character storing array to hashmap<int, char> and then to heap. then printing the character and number of their frequency

In this question i assume that. arr = {'a', 'a', 'b', 'c', 'c'}. then unordered_map will convert this into a-> 3, b-> 1, c-> 2. then i append this to max heap 3-> a, 2-> c, 1-> which i supposed to be this but i want to print the result as a b c but i am facing error. Need help!!
code is in the link below. I dont know why my code is not accepting.
https://hastebin.com/mamudogizo.cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
unordered_map<char, int> mp;
priority_queue<pair<int, char>> mheap;
char arr[] = {'a','a','a','b','c','c'};
for (int i = 0; i < 6; ++i)
{
mp[arr[i]]++;
}
for (auto i = mp.begin(); i != mp.end(); i++)
{
mheap.push({i->first, i->second});
}
pair<int, char> curr = mheap.top();
cout<< curr.second;
return 0;
}
If you want to count how many times each character occurred then you can use std::string instead of using " built in arrays and priority_queue<> " as shown below. That is there is no need for priority_queue<>. The program prints the output in the order as you desire.
Version 1: Using std::string
#include <iostream>
#include <map>
int main() {
std::string inputString = "anoopsinghrana";
//std::cout<<"Enter a string: ";
//std::cin>> inputString;
//this map maps the char to their respective count
std::map<char, int> charCount;
for(char &c: inputString)
{
charCount[c]++;
}
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 << c <<"-" << charCount.at(c)<<std::endl;
}
++i;
}
return 0;
}
The output of the above program is as follows:
a-3
n-3
o-2
p-1
s-1
i-1
g-1
h-1
r-1
The above(version 1) program counts small and capital letters separately. So for example the character A and the character a are different.
If you still want to use built in array instead of std::string then you can use the following program. Note that still you don't need priority_queue.
Version 2: Using built in array
#include <iostream>
#include <map>
int myFind(char arr[], int len, int seek)
{
for (int i = 0; i < len; ++i)
{
if (arr[i] == seek) return i;
}
return -1;
}
int main() {
char arr[] = {'a','n','o','o','p','s','i','n','g','h','r','a','n','a'};
std::map<char, int> charCount;
for(int i = 0; i < sizeof(arr) / sizeof(char); ++i)
{
charCount[arr[i]]++;
}
int k = 0;
//just go through the inputString instead of map
for(int i = 0; i < sizeof(arr) / sizeof(char); ++i)
{
//std::size_t index = inputString.find(arr[i]);
int index = myFind(arr,sizeof(arr) / sizeof(char),arr[i]);
if(index != -1 && (index == k)){
std::cout << arr[i] <<"-" << charCount.at(arr[i])<<std::endl;
}
++k;
}
return 0;
}
The ouptut of the above(version 2) program is:
a-3
n-3
o-2
p-1
s-1
i-1
g-1
h-1
r-1
Your map maps from the character to its counter, and the queue is ordered by the counter, so when you push an item from the map to the queue, you need to replace first and second:
for (auto i = mp.begin(); i != mp.end(); i++)
{
mheap.push({ i->second, i->first });
}
Also, note that you're only printing the first element from the queue. If you want to print them all (in order), you'd need to iterate over it. E.g.:
while (!mheap.empty())
{
pair<int, char> curr = mheap.top();
cout << curr.second << endl;
mheap.pop();
}

Getting "Exited with return code -11(SIGSEGV)" when attempting to run my code

#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> separate(string str){
string build = "";
vector<string> temp;
for(int i = 0;i < str.size(); i++){
if(str[i] != ' '){
build += str[i];
} else if(str[i] == ' '){
temp.push_back(build);
build = "";
}
}
return temp;
}
int main() {
int count;
string sentence;
vector<int> numTimes;
getline(cin, sentence);
vector<string> words = separate(sentence);
for(int i = 0; i < words.size(); i++){
for(int j = 0; j < words.size(); i++){
if(words[i] == words[j]){
count++;
}
}
numTimes.push_back(count);
}
for(int k = 0; k < words.size(); k++){
cout << words[k] << " - " << numTimes[k] << endl;
}
return 0;
}
The code is supposed to receive a string, separate it into the individual words, place those words into a vector and finally output the number of times the word occurs in the sentence. However when running my code, I get a message saying that the program was exited with code -11. I have looked a bit online but do not fully understand what this means or where it is occurring in my code.
Changed signed counter variables (i, j) to unsigned (size_t) as you compare the two. In separate(..) changed if-else-if to just if-else, and fixed the loop per #user4581301 to use the right loop variable. Also fixed last word not being added. Minor reformat to use tab/8 space for indent.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> separate(string str) {
string build = "";
vector<string> temp;
for(size_t i = 0; i < str.size(); i++) {
if(str[i] == ' ') {
temp.push_back(build);
build = "";
} else {
build += str[i];
}
}
if(build.size()) {
temp.push_back(build);
}
return temp;
}
int main() {
int count = 0;
string sentence;
vector<int> numTimes;
getline(cin, sentence);
vector<string> words = separate(sentence);
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < words.size(); j++) {
if(words[i] == words[j]) {
count++;
}
}
numTimes.push_back(count);
}
for(size_t k = 0; k < words.size(); k++) {
cout << words[k] << " - " << numTimes[k] << endl;
}
return 0;
}
This seems to fix the segfault which answers question posed.
You haven't provided sample input and output but the counts clearly seems wrong. What do you mean with sentence? There is no notion of English sentences ending with '.' or whatever:
./a.out
a bc d
a - 1
bc - 2
d - 3
./a.out
a a b
a - 2
a - 4
b - 5
Suggest you work on that and open new question if you need further help.
#Allan Wind is right, but to offer an alternate solution using the C++17 standard.
Iterating
Rather than use indexes, let's use a more modern for loop.
for (const char &ch : s)
Rather than:
for (size_t i = 0; i < str.size(); i++)
After all, the index is not important in this situation.
Dealing with multiple spaces
Right now, both the OP's code and Allan's will push an empty string onto the output vector whenever they encounter more than one contiguous space. We can correct that by resetting the string to empty when a space is encountered, but when a space is encountered and the string is empty, don't take any action.
We also need to check if the string is non-empty when the loop is finished. If so, we need to push that onto the output vector. We may not get a trailing space to trigger pushing that last word.
vector<string> separate(string s) {
vector<string> output;
string current = "";
for (const char &ch : s) {
if (current != "" && ch == ' ') {
output.push_back(current);
current = "";
}
else if (ch == ' ') {
// Do nothing!
}
else {
current += ch;
}
}
if (current != "") {
output.push_back(current);
}
return output;
}
Putting it together so far
#include <string>
#include <vector>
#include <iostream>
using namespace std;
vector<string> separate(string s);
int main() {
auto v = separate("hello world foo");
for (auto i : v) {
cout << i << endl;
}
}
vector<string> separate(string s) {
vector<string> output;
string current = "";
for (const char &ch : s) {
if (current != "" && ch == ' ') {
output.push_back(current);
current = "";
}
else if (ch == ' ') {
// Do nothing!
}
else {
current += ch;
}
}
if (current != "") {
output.push_back(current);
}
return output;
}
Counting words
We can use a map to count the occurrences of words. We use a map<string, int> where each word is the key, and the val is the occurrences. As we iterate over the words, if the word already exists as a key in the map, we increment it by `. If not, we set it to 1.
int main() {
auto v = separate("hello world hello world foo");
map<string, int> m;
for (auto i : v) {
if (m[i]) {
m[i] += 1;
}
else {
m[i] = 1;
}
}
for (auto const& [key, val] : m) {
cout << "The word \"" << key << "\" occurs "
<< val << " times." << endl;
}
}

Reverse n characters in the string (there is no spaces in string) without using built-in functions in c++

I have a string like str="ABCDEFGHIJK";
need o/p like this str="CBAFEDIHGJK"
am getting "CBA" correctly after that its not printing anything.
can anyone check the following code and let me know where is the problem?
int main()
{
string str="ABCDEFGHIJK";
char str1[10],rev[10];
int n=str.length(),count=0,c=3,k=0,j=0;
for(int i=0;i<n;i++)
{
str1[i]=str[i];
count++;
cout<<str1[i]<<" and "<<count<<"and "<<c<<endl;
if(count==c)
{
cout<<"Entered into if loop"<<count<<"and"<<c<<"and "<<k<<endl;
cout<<c<<" and "<<k<<endl;
while(j<c)
{
rev[j]=str1[c-k-1];
cout<<rev[j]<<" and "<<str1[c-k-1]<<endl;
j++;
k++;
}
count=0;
}
/*else
{
if(count < c && str[i]=='\0')
{
for(int k=0;k<count;k++)
{
rev[k]=str1[count-1];
count--;
count=0;
}
}
}*/
}
cout<<"The string is: "<<rev<<endl;
return 0;
}
Please help me on this.
No need to use a c++ string object for this use-case; just use a normal char *.
Also, always make sure you store enough room for the string null-terminator character ('\0'). This is required as c string functions assume your string is terminated in this way.
Following will reverse string in ansi C89
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void reverse(char *in, char *rev)
{
int i, n;
n = strlen(in);
for(i = n-1; i>=0; i--)
{
rev[n-i-1] = in[i];
}
/* add the null-terminator */
rev[n] = '\0';
}
int main()
{
char *str = "ABCDEFGHIJK";
char str1[12], temp;
char triplet[4];
char rev_triplet[4];
int index;
triplet[3] = '\0';
rev_triplet[3] = '\0';
str1[0] = '\0';
for(index = 0; index < strlen(str); index += 3)
{
memcpy(triplet, str + index, 3 * sizeof(char));
reverse(triplet, rev_triplet);
strcat(str1, rev_triplet);
}
printf("Initial string is: %s\n", str);
printf("Reverse string is: %s\n", str1);
return 0;
}
Outputs
$ ./test
Initial string is: ABCDEFGHIJK
Reverse string is: CBAFEDIHGKJ
If you intend to use C++ (and not C) for this:
#include <algorithm>
#include <iostream>
#include <string>
std::string reverse_triples(std::string s)
{
const unsigned int N = 3;
for (int i = 0, j = N - 1; i < s.length() - (s.length() % N); i += N, j += N)
{
std::swap(s[i], s[j]);
}
return s;
}
int main()
{
std::string s = "ABCDEFGHIJK";
std::string rs = reverse_triples(s);
std::cout << "Reversed Triples: " << rs << std::endl;
return 0;
}
Whatever value of N you need can be modified (and even supplied as a function parameter if you want). You only need to swap the outer characters (so all the elements below N / 2 will be swapped with the elements above N / 2). For N == 3, it is just a single swap. If you want to do it more generically:
#include <algorithm>
#include <iostream>
#include <string>
std::string reverse_substrings(std::string s, unsigned int substring_size)
{
for (int i = 0, j = substring_size - 1; i < s.length() - (s.length() % substring_size); i += substring_size, j += substring_size)
{
std::reverse(s.begin() + i, s.begin() + j + 1);
}
return s;
}
int main()
{
std::string s = "ABCDEFGHIJK";
std::string rs = reverse_triples(s, 4); // passing 3 gets you the same results as before
std::cout << "Reversed Triples: " << rs << std::endl;
return 0;
}
First, let us examine how std::reverse might be implemented. It uses iterators.
template <class BidirectionalIterator>
void reverse (BidirectionalIterator first, BidirectionalIterator last)
{
while ((first!=last)&&(first!=--last)) {
std::iter_swap (first,last);
++first;
}
}
We can extend the logic to use indices instead of iterators, where i and j represent iterators (positions) and s[i] and s[j] represent the data pointed to by the iterators.
void reverse(std::string& s)
{
int i = 0;
int j = s.size();
while ((i != j) && (i != (--j)))
{
std::swap(s[i], s[j]);
++i;
}
}
Now you want to reverse "chunks" rather than the entire string.
void reverse(int n, std::string& s)
{
int beg = 0;
int end = beg + n;
int size = s.size();
// We're going to modify s in place
// So store a copy
std::string copy = s;
s = "";
// Add + 1 to avoid the loop cutting off short
// Or do i <= size / n;
for (int i = 0; i < size / n + 1; i++)
{
std::string chunk(copy.begin() + beg, copy.begin() + end);
// If there's no n sized chunks left
// don't reverse
if (end < size)
reverse(chunk);
s += chunk;
beg += n;
// Don't go past the size of the string
end += (end + n > size ? size - end : n);
}
}
int main()
{
std::string s("ABCDEFGHIJK");
std::string target("CBAFEDIHGJK");
reverse(3, s);
std::cout << s << "|" << target <<"|\n";
std::cout << s.size() << " " << target.size() << "\n"; // 11 11
std::cout << std::boolalpha << (s == target); // true
return 0;
}