I am relearning C++ after many years of matlab. Here is some code that I wrote
char couts[3][20]={"Area of Rectangle: ","Area of Triangle: ","Area of Ellipse: "};
char C[20];
for (int i = 0; i < 3; i++) {
C=couts[i];
cout << C;
//code that calculates and couts the area
}
clearly this is the wrong way of getting that row of couts to print, but after trying many variations and googling I can't work out what I'm doing wrong. :(
You probbaly should use C++ features and not old C idioms:
#include <iostream>
#include <array>
#include <string>
const std::array<std::string, 3> couts{ "Area of Rectangle: ","Area of Triangle: ","Area of Ellipse: " };
int main()
{
std::string C;
for (int i = 0; i < couts.size(); i++) {
C = couts[i];
std::cout << C << "\n";
//code that calculates and couts the area
}
}
Use strings or even string_views in this case, not char arrays. You are not copying the string in C, so the cout doesn't work. In modern C++ (C++17), this would be instead:
constexpr std::string_view couts[] = {"Area of Rectangle: ","Area of Triangle: ","Area of Ellipse: "};
std::string_view C;
for (auto s: couts) {
std::cout << s << std::endl;
}
This probably the only place I would write a C-style array and not use std::array, as the number of elements may change in the future.
Here's a version using the C++17 deduction guides for std::array combined with std::string_view letting you use range based for-loops etc. on both the std::array and the std::string_views.
#include <iostream>
#include <array>
constexpr std::array couts = {
std::string_view{"Area of Rectangle: "},
std::string_view{"Area of Triangle: "},
std::string_view{"Area of Ellipse: "}
};
int main() {
for(auto& C : couts) {
for(auto ch : C) {
std::cout << ch; // output one char at a time
}
std::cout << "\n";
}
}
Related
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;
}
Here's my code:
#include <iostream>
using namespace std;
string moveString(string t, int index)
{
for (int i=index; t[i]!=NULL;i++)
{
t[i]=t[i+1];
}
return t;
}
string delChars(string t)
{
for (int i=0; t[i]!=NULL; i++)
{
if (t[i]>'a' && t[i]<'z')
{
moveString(t, i);
}
else if (t[i]>'A' && t[i]<'Z')
{
moveString(t, i);
}
}
return t;
}
int main()
{
int numberOfSpaces;
string t;
cout << "Text some word: "; cin>>t;
cout<<delChars(t);
return 0;
}
First function moveString should (in theory) take down every single character from a string by 1 index down (starting from given index) - to remove 1 character. The rest is pretty obvious. But:
Input: abc123def
Output: abc123def
What am I doing wrong?
And a additional mini-question: Acutally, what's the best way to "delete" an element from an array? (array of ints, chars, etc.)
Logic Stuff is right but his answer is not enough. You shouldn't increase i after move. Since the i.th character is removed and i points to the next character now.
string delChars(string t)
{
for (int i=0; t[i]!=NULL; )
{
if (t[i]>'a' && t[i]<'z')
{
t = moveString(t, i);
}
else if (t[i]>'A' && t[i]<'Z')
{
t = moveString(t, i);
}
else
i++;
}
return t;
}
moveString takes t by value and you're not assigning its return value, so it doesn't change t in delChars. So, make sure the next thing you learn are references.
Apart from that, I don't know what to tell about t[i] != NULL (if it is undefined behavior or not), but we have std::string::size to get the length of std::string, e.g. i < t.size(). And if you havet[i + 1], the condition should then be i + 1 < t.size().
Whatever, don't play with it like with char arrays, leaving the string with previous size. You can pop_back the last (duplicate) character after shifting the characters.
It's worth mentioning that it can be done in one line of idiomatic C++ algorithms, but you want to get your code working...
What am I doing wrong?
Not using standard algorithms
Actually, what's the best way to "delete" an element from array? (array of ints, chars, etc.)
By using the standard remove-erase idiom:
#include <iostream>
#include <string>
#include <algorithm>
#include <iomanip>
#include <cstring>
int main()
{
using namespace std;
auto s = "!the 54 quick brown foxes jump over the 21 dogs."s;
cout << "before: " << quoted(s) << endl;
s.erase(std::remove_if(s.begin(),
s.end(),
[](auto c) { return std::isalpha(c); }),
s.end());
cout << "after: " << quoted(s) << endl;
return 0;
}
expected output:
before: "!the 54 quick brown foxes jump over the 21 dogs."
after: "! 54 21 ."
I'm not allowed to use standard algorithms
Then keep it simple:
#include <iostream>
#include <string>
#include <algorithm>
#include <iomanip>
#include <cstring>
std::string remove_letters(const std::string& input)
{
std::string result;
result.reserve(input.size());
for (auto c : input) {
if (!std::isalpha(c)) {
result.push_back(c);
}
}
return result;
}
int main()
{
using namespace std;
auto s = "!the 54 quick brown foxes jump over the 21 dogs."s;
cout << "before: " << quoted(s) << endl;
auto s2 = remove_letters(s);
cout << "after: " << quoted(s2) << endl;
return 0;
}
I have the following example (simplified) using a struct:
#include <iostream>
#include <algorithm>
#include <time.h>
using namespace std;
struct s_str
{
int a=1,b=2,c=3;
};
int main(void)
{
s_str str;
int sel;
srand(time(NULL)); //initialize random seed
sel = rand() % (3); //generate a random number between 0 and 2
cout << "sel: " << sel << endl;
cout << "str: " << str.??? << endl;//I was wondering to output a, b or c
return 0; //depending whether sel=0,1,2respectively.
}
When the struct "str" is defined, we can access to each element by using the opertor "." followed by the name of the element. For instance "str.c" will give us the number 3.
However in this example we don't know the element of "str" to output when programing because it's randomly selected by sel.
I don't know how to output "str.???" from sel number, that is, str.a if sel=0, str.b if sel=1, and str.c if sel=3.
I tried something like "str.[sel]", but it didn't work. Can you help me?
PD: I don't want to bother too much, but how to solve the same problem but now supposing that a,b and c have different variable type. For example:
int a=1,b=2;
string c="hola";
I tried to do it with two operators, but it didn't compile because they were overloaded.
As mentioned you can't do this without providing a certain mapping and indexing operator. The following should work well:
struct s_str
{
int a=1,b=2,c=3;
int& operator[](int index) {
switch(index) {
case 0:
return a;
case 1:
return b;
case 2:
return c;
default:
throw std::out_of_range("s_str: Index out of range.");
break;
}
}
};
int main() {
s_str s;
cout << s[0] << ", " << s[1] << ", " << s[2] << endl;
// cout << s[42] << endl; // Uncomment to see it fail.
return 0;
}
In general, no.
If the only distinguishing feature of the elements of the struct is their index, define a vector or array in the struct.
If you sometimes want to refer to the elements by name and sometimes by position, define an operator []( int ) for the struct.
Te easiest way, if you have only a couple of ints in your structure is:
struct s_str
{
int a = 1, b = 2, c = 3;
int& operator[] (size_t t) {
assert(t<3); // assumption for the following to return a meaningful value
return (t == 0 ? a : (t == 1 ? b : c));
}
};
You'd access with
cout << "str: " << str[sel] << endl;
and you could even use int to assign, because it's by reference:
str[sel] = 9;
cout << "a,b,c=" << str.a << "," << str.b << "," << str.c << endl;
I have written the following code to save in an char * array and print the following content:
band1.txt
band2.txt
...
band3.txt
The code seems right but what is printed on the console is very weird.
Code:
const char ** current_band = new const char * [103];
stringstream sstm;
string str;
for (i=0;i<103;i++){
current_band[i] = new char[11];
}
for (i=0;i<103;i++){
sstm.str("");
sstm << "band" << i+1 << ".txt";
str = sstm.str();
current_band[i] = str.c_str();
cout << current_band[i] << endl;
cout << i << endl;
}
for (i=0;i<103;i++){
cout << current_band[i] << endl;
cout << i << endl;
}
Console:
band1.txt
0
band2.txt
1
...
band103.txt
102
And then for the last loop:
band103.txt
0
band102.txt
1
band103.txt
2
band102.txt
3
...
band102.txt
101
band103.txt
102
How is this even possible?
EDIT: Actually i want the "bands" to be char* in order to call the ifstream current_band_file(current_band) constructor that wants such an argument
You have undefined behavior by using pointers to already destroyed objects.
Simply don't use raw pointers and raw arrays and such stuff yet.
std::string is your friend for strings, std::vector is your friend for arrays.
Example:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
auto main()
-> int
{
vector<string> band_names;
for( int i = 1; i <= 103; ++i )
{
band_names.push_back( "band" + to_string( i ) );
}
for( string const& name : band_names )
{
cout << name << endl;
}
}
As a minimal change to you existing code you can change:
current_band[i] = str.c_str();
to:
strcpy(current_band[i], str.c_str());
However, moving away from this mixed C and C++ to more idiomatic C++ (like Cheers and hth. - Alf's answer) will serve you better for the future.
Sticking with things like char[11] over std::string means you're stuck with:
The arbitrary choice of max length 11 even though probably there is no good technical reason for that limit.
Dealing with handling all the details of memory allocation which a proper C++ implementation hides.
The much less natural to read lower level code style.
As a band-aid you could replace:
current_band[i] = str.c_str();
with
if ( str.size() >= 11 )
throw std::runtime_error("string too long");
std::strcpy(current_band[i], str.c_str());
However it would be a much better idea to replace this whole thing with:
std::vector<std::string> current_band(103);
int i = 0;
for (auto &s : current_band)
{
// your sstm stuff, storing to s
}
Here's an alternative way that's a little more robust, readable and more likely to be correct.
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
vector<string> bands;
bands.reserve(103);
for(size_t i = 1 ; i <= 103 ; ++i) {
ostringstream ss;
ss << "band" << i;
bands.emplace_back( ss.str() );
}
for (size_t index = 0 ; index < bands.size() ; ++index) {
cout << index << " : " << bands[index] << endl;
}
return 0;
}
output:
Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1
Executing the program....
$demo
0 : band1
1 : band2
2 : band3
...
100 : band101
101 : band102
102 : band103
Recently I have found a lot of examples, most of them regards the C++ 98, anyways I have created my simple-array and a loop (codepad):
#include <iostream>
using namespace std;
int main ()
{
string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
{
cout << "value of a: " << texts[a] << endl;
}
return 0;
}
Output:
value of a: Apple
value of a: Banana
value of a: Orange
Segmentation fault
It's working fine, except the segmentation fault at the end.
My question is, does this array/loop through is done a good way? I am using C++ 11 so would like to be sure it fits the standards and couldnt be done a better way?
In C/C++ sizeof. always gives the number of bytes in the entire object, and arrays are treated as one object. Note: sizeof a pointer--to the first element of an array or to a single object--gives the size of the pointer, not the object(s) pointed to. Either way, sizeof does not give the number of elements in the array (its length). To get the length, you need to divide by the size of each element. eg.,
for( unsigned int a = 0; a < sizeof(texts)/sizeof(texts[0]); a = a + 1 )
As for doing it the C++11 way, the best way to do it is probably
for(const string &text : texts)
cout << "value of text: " << text << endl;
This lets the compiler figure out how many iterations you need.
as others have pointed out, std::array is preferred in C++11 over raw arrays; however, none of the other answers addressed why sizeof is failing the way it is, so I still think this is the better answer.
string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
{
cout << "value of a: " << texts[a] << endl;
}
Nope. Totally a wrong way of iterating through an array. sizeof(texts) is not equal to the number of elements in the array!
The modern, C++11 ways would be to:
use std::array if you want an array whose size is known at compile-time; or
use std::vector if its size depends on runtime
Then use range-for when iterating.
#include <iostream>
#include <array>
int main() {
std::array<std::string, 3> texts = {"Apple", "Banana", "Orange"};
// ^ An array of 3 elements with the type std::string
for(const auto& text : texts) { // Range-for!
std::cout << text << std::endl;
}
}
Live example
You may ask, how is std::array better than the ol' C array? The answer is that it has the additional safety and features of other standard library containers, mostly closely resembling std::vector. Further, The answer is that it doesn't have the quirks of decaying to pointers and thus losing type information, which, once you lose the original array type, you can't use range-for or std::begin/end on it.
sizeof tells you the size of a thing, not the number of elements in it. A more C++11 way to do what you are doing would be:
#include <array>
#include <string>
#include <iostream>
int main()
{
std::array<std::string, 3> texts { "Apple", "Banana", "Orange" };
for (auto& text : texts) {
std::cout << text << '\n';
}
return 0;
}
ideone demo: http://ideone.com/6xmSrn
you need to understand difference between std::array::size and sizeof() operator. if you want loop to array elements in conventional way then you could use std::array::size. this will return number of elements in array but if you keen to use C++11 then prefer below code
for(const string &text : texts)
cout << "value of text: " << text << endl;
If you have a very short list of elements you would like to handle, you could use the std::initializer_list introduced in C++11 together with auto:
#include <iostream>
int main(int, char*[])
{
for(const auto& ext : { ".slice", ".socket", ".service", ".target" })
std::cout << "Handling *" << ext << " systemd files" << std::endl;
return 0;
}
How about:
#include <iostream>
#include <array>
#include <algorithm>
int main ()
{
std::array<std::string, 3> text = {"Apple", "Banana", "Orange"};
std::for_each(text.begin(), text.end(), [](std::string &string){ std::cout << string << "\n"; });
return 0;
}
Compiles and works with C++ 11 and has no 'raw' looping :)
sizeof(texts) on my system evaluated to 96: the number of bytes required for the array and its string instances.
As mentioned elsewhere, the sizeof(texts)/sizeof(texts[0]) would give the value of 3 you were expecting.
Add a stopping value to the array:
#include <iostream>
using namespace std;
int main ()
{
string texts[] = {"Apple", "Banana", "Orange", ""};
for( unsigned int a = 0; texts[a].length(); a = a + 1 )
{
cout << "value of a: " << texts[a] << endl;
}
return 0;
}
In my point of view:
It is because the sizeof() operator returns the size
of a type in bytes.
So, Simply we can use size() instead of sizeof(). If
we need or must use sizeof() we have to divide it
with sizeof(dataType):
First way:
#include <iostream>
using namespace std;
int main ()
{
string texts[] = {"Apple", "Banana", "Orange"};
for(int a = 0; a < size(texts); a++){
cout << "value of a: " << texts[a] << endl;
}
return 0;
}
Second way:
#include <iostream>
using namespace std;
int main ()
{
string texts[] = {"Apple", "Banana", "Orange"};
for(int a=0; a<sizeof(texts)/sizeof(string); a++)
{
cout << "value of a: " << texts[a] << endl;
}
return 0;
}
Feels like illegal but this works:
So basically it is dynamic multidimensional array iteration termination case and it differs a bit from one dimensional solution, last element is -1 and it is stop value for cycle (I am new to C++ but this method me likes)
int arr[][3] = {{164, 0, 0}, {124, 0, 0}, {92, 4, 0}, {68, 4, 0}, -1};
for(int i = 0; arr[i][0]!=-1; i++)
{
cout << i << "\n";
}
You can do it as follow:
#include < iostream >
using namespace std;
int main () {
string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts) / 32; a++ ) { // 32 is the size of string data type
cout << "value of a: " << texts[a] << endl;
}
return 0;
}