I would like to know whether the following code is "valid":
#include <iostream>
using namespace std;
int main(void) {
string s="Hello World!\n";
for (int i=0;i<s.size();++i) {
for (int j=0;j<s[i];++j) {
cout << "+";
}
cout << ".>\n";
}
}
I made this code but I don't know if I should add some ".c_str" or else, to make it better code.
Thanks to all the contributions, I can now say my code is valid in C++, as the [] operator is part of the string class.
Furthermore, it can be added that
for (char c : s) {
for (int j = 0; j != c; ++j) {
/*..*/
}
}
is short for
for (int i = 0; i < s.size(); ++i) {
for (int j = 0; j < s[i]; ++j) {
/*..*/
}
}
Thank you to all of you!
This code has a potential problem:
for (int j=0;j<s[i];++j) {
The value s[i] is a char, which might be a signed type. If the character value is negative then this loop causes undefined behaviour due to eventual overflow of j.
On an ASCII system this exact code contains no negative characters, but in EBCDIC the newline is 0x85 which would translate to a negative character value if the system had plain char as signed.
To be on the safe side, it should be for (int j = 0; j < (unsigned char)s[i]; ++j). Or in the range-based version, use for (unsigned char c: s).
Related
The Counting sort below sorts elements based on their ASCII value.
The code below works fine but I want to do some I/O modification. The code doesn't take custom input.
I tried to do some changes but getting undefined behavior. My first doubt is why I'm getting undefined behavior. secondly, Please provide me with the code which will make the below code run as expected. The comment portion is what I tried by myself.I want it to take input from user.
#include<bits/stdc++.h>
#include<string.h>
using namespace std;
#define RANGE 255
void countSort(char arr[]) //void countSort(char arr[],int n)
{
char output[strlen(arr)]; //char output[n];
int count[RANGE + 1], i;
memset(count, 0, sizeof(count));
for(i = 0; arr[i]; i++) {
count[arr[i]]++;
}
for (i = 1; i <= RANGE; ++i) {
count[i] += count[i-1];
}
for (i = 0; arr[i]; ++i) {
output[count[arr[i]]-1] = arr[i];
--count[arr[i]];
}
for (i = 0; arr[i]; ++i) {
arr[i] = output[i];
}
}
// Driver code
int main()
{
char arr[] = "geeksforgeeks";
countSort(arr);
cout<< "Sorted character array is "<<arr;
/*
int n;
cin>>n;
char arr[n];
for(int i=0;i<n;i++) {
cin>>arr[i];
}
countSort(arr,n);
for(int i=0;i<n;i++) {
cout<<endl<<arr[i];
}
*/
return 0;
}
So the OP asked, how to take an input from the user and sort this. And not a predefined string in a given char array.
I will give the answer. But the question is tagged with C++, and I will convert it to C++.
By the way. The code in the question is a one to one copy from GeeksforGeeks and tries to code the so called Counting Sort algorithm in C++ that is described here.
Since the code is taken from GeeksforGeeks I unfortunately need to blame user "rathbhupendra" for really bad C++ code. I am truly sorry.
The code is using:
C-Style arrays
Variable Length Arrays (Compiler extension. Not C++ compliant)
strlen
memset
#include<bits/stdc++.h> and #include<string.h>
using namespace std
unusal end conditions in for loops for(i = 0; arr[i]; ++i)
char arrays instead of std::strings
a Macro to define an array size (#define RANGE 255)
So, nothing C++.
And now, the answer.
You need to read the string from the user in a variable of type std::string with the function std::getline.
A std::string can be used like a character array. No difference.
Please see the C++ solution:
EDIT
Edited on the comments of MichaelDorgan
#include <iostream>
#include <string>
#include <vector>
constexpr size_t AsciiRange = 256;
// Convert signed char to unsigned size_t type.
inline size_t char2sizet(char c) { return static_cast<size_t>(static_cast<unsigned char>(c)); }
void countSort(std::string& stringToSort)
{
std::vector<size_t> count(AsciiRange, 0U);
size_t i { 0U };
for (i = 0U; i < stringToSort.size(); i++) {
count[char2sizet(stringToSort[i])]++;
}
for (i = 1U; i < AsciiRange; ++i) {
count[i] += count[i - 1U];
}
std::string output(stringToSort);
for (i = 0U; i < stringToSort.size(); ++i) {
output[count[char2sizet(stringToSort[i])] - 1U] = stringToSort[i];
--count[char2sizet(stringToSort[i])];
}
stringToSort = output;
}
int main()
{
std::cout << "\nPlease enter a string:\n\n";
// Get the string from the user
std::string inputString{};
getline(std::cin, inputString);
// Sort it by characters
countSort(inputString);
// Show result
std::cout << "\n\n\nString sorted by characters is:\n\n" << inputString << '\n';
return 0;
}
Hope this helps . . .
I geuss by 'getting undefined behavior' you meant segmentation fault which sometimes occured. The problem lies in this line
for(i = 0; arr[i]; i++)
instead you should write
for(i = 0; i < n; i++)
You can check that in the first case at the end of each loop arr[i] is sometimes some weird character(this character doesn't belong to the input string) and count[arr[i]] for this char returns negative number which produce segmentation fault here
output[count[arr[i]]-1] = arr[i];
I want to output my histogram using the fewest amount of for loops possible
int* histogram(int size, int* arr)
{
int bin[10] = {};
for (int i = 0; i < size; i++)
{
if (arr[i] >= 0 && arr[i] < 10)
{
bin[0]++;
}
else if (arr[i] >= 10 && arr[i] < 20)
{
bin[1]++;
}
return bin;
}
Currently I am outputting the histogram like this:
cout << "0|";
for (int j = 0; j < bin[0]; j++)
cout << "*";
cout << endl;
But this is long and annoying. Is there a way to achieve the same output in fewer
for loops?
I am going to ignore the bugs in your histogram code, as it isn't really relevant to the question of optimising histogram output.
For information on the bug (returning a local variable), check out this Stack Overflow question.
Also, you are missing a curly brace. Always check that your code compiles and runs in its most minimalist form before posting it.
You state that the problem is that the method you use is "long and annoying", but it isn't clear if you are referring to the design of your code or the speed at which it performs.
Performance
The fastest you can possibly read the histogram is with O(n), where n is the number of bins in the histogram. In this sense your code is about as fast as it can get without micro-optimising it.
If you include the printing out of your histogram, then you have O(n*m), where m is the average number of entries per bin.
Writing a histogram is also O(n*k), where k is the number of entries in your array, because you have to figure out which bin each value belongs in.
Design
If the problem you have is that the code is bloated and unwieldy, then use less magic numbers and add more arguments to the function, like this:
#include <iostream>
void histogram(int const size, int const * const arr, unsigned int const number_of_bins, float const bin_min, float const bin_max, int * output)
{
float const binsize = (bin_max - bin_min)/number_of_bins;
for (int i = 0; i < size; i++)
{
for(int j = 0; j < number_of_bins; ++j)
{
if (arr[i] >= bin_min + binsize*j && arr[i] < bin_min + binsize*(j+1))
{
output[j]++;
}
}
}
}
int main(){
int const number_of_bins = 10;
float const bin_min = 0;
float const bin_max = 100;
int const size = 20;
int const array[size] = {5,6,20,40,44,50,110,6,-1,51,55,56,20,50,60,80,81,0,32,3};
int bin[number_of_bins] = {};
histogram(size, array, number_of_bins, bin_min, bin_max, bin);
for(int i = 0; i < number_of_bins; ++i)
{
std::cout << i << "|";
for (int j = 0; j < bin[i]; j++)
{
std::cout << "*";
}
std::cout << std::endl;
}
}
Compiled with:
g++ main.cc -o Output
Output:
0|*****
1|
2|**
3|*
4|**
5|*****
6|*
7|
8|**
9|
(Bonus, your bugs are fixed)
First of all your program is incorrect since, as pointed out, you return a pointer to a local variable form a function. To correct this you should use either std::array<Type, Size> or std::vector<Type>.
Regarding your question if you want short and compact code try this:
#include <string>
#include <algorithm>
#include <iostream>
#include <array>
std::array<int, 10> bin;
// Fill your array here
int i = 0;
std::for_each(bin.begin(), bin.end(), [&i](auto x)
{
std::cout << i++ << "|" << std::string(x, '*') << std::endl;
});
This code takes advantage of fill constructor of std::string which avoids your for cycle. But since you want to iterate through the array you need to do it in one way or the other. Either by an explicit for or by calling another function.
Note: this code is less efficient than a standard for loop but your question is how to avoid these.
I wrote the following code to convert string of type 'aaadddbbbccc' to 'a3d3b3c3' :
#include <iostream>
#include <string.h>
using namespace std;
void stringCompression(char *str,char *newStr){
int a[256] = {0};
int newCount = 0;
for(int i = 0; i < strlen(str) ; i++){
int j = str[i];
if (a[j] == 0 && strlen(newStr) <= strlen(str)){
a[j] = 1 ;
newStr[newCount] = str[i];
newCount++;
int count = 0;
for (int n = i; n < strlen(str); n++){
if(str[i] == str[n]){
count = count + 1;
}
}
newStr[newCount] =(char) count;
newCount++ ;
} else if (strlen(newStr) > strlen(str)){
strcpy(newStr,str);
}
}
}
int main() {
char str[] = "abcdabcdabcd";
char *newStr = new char[strlen(str)+1];
stringCompression(str,newStr);
cout << newStr;
return 0;
}
My problem is at step
newStr[newCount] =(char) count;
even though it is inserted but the output is not a3b3c3d3 but a*squarebox*b*squarebox*c*squarebox*d*squarebox*. squarebox being 2*2 matrix with one value as the number that is desired. I am using eclipse IDE.
. I would really appreciate your help. How can I correct this. Am I using the correct approach?
Thanks in advance.
The problem is that
newStr[newCount] =(char) count;
converts the number "count" into the character corresponding to that number according to the ascii table (http://www.asciitable.com/), which is "end of text" for "3", that does not correspond to any number.
You should convert "count" into a string instead. See here for example:
Easiest way to convert int to string in C++
However, be aware that it might be longer than one digit, for example if count is "11", it will take two letters in string representation.
Hey you have to use http://www.cplusplus.com/reference/cstdlib/itoa/ to convert integer to char string
I'm trying to create a program that reads in and solves incomplete 9x9 sudoku boards from a text file. One of the boards might look like this:
N
145369287
629785431
783412569
567148392
938527 14
214936758
851 74623
492853 76
376291845
I need to print out the board read in, which I'm doing by just using getline and printing the string, and then store each digit into an array, blanks can be converted to zeroes for the purpose of evaluation. If I tried to read the board in as straight ints then it would try to read all the digits of a row as one int until a space or a newline was reached, and if I try to read it in char by char with get(), I run into problems again with newlines, and I would then have to convert the array of chars to an array of ints for evaluation which I think I will run into problems with as well. This is my code so far, I figured using an istringstream would be convenient but then realized that I would have to have more for loops, so a solution without it would be ideal. Not allowed to use vectors or fancy modules or structs anything like that, it is a class assignment.
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <fstream>
using namespace std;
int main() {
ifstream infile("sudoku_infile.txt");
ofstream outfile("sudoku_outfile.txt");
int board[9][9];
char n;
char c;
string str;
stringstream into;
while (infile >> n){
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++){
getline(infile, str);
cout << str << "\n";
into << str;
}
return 0;
}
EDIT:
Ok, I've devised a solution on my own by trying to convert chars to ints and putting them in an array, but it doesn't seem to be working:
while (infile >> str){
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++){
getline(infile, str);
cout << str << "\n";
for (int z = 0; z < 9; z++){
if (isdigit(str[z])){
d = str[z] - '0';
}
else{
d = 0;
}
board[i][j] = d;
}
}
for (int m = 0; m < 9; m++){
for (int f = 0; f < 9; f++)
cout << board[m][f];
cout << endl;
}
}
I get this as output:
145369287
629785431
783412569
567148392
938527 14
214936758
851 74623
492853 76
376291845
071924836
555555555
555555555
555555555
555555555
555555555
555555555
555555555
555555555
You have to make sure, that your file just contains up to 9*9 characters - otherwise it will run out of bounds this way - but it's easy to add a bounds check in there. Because '0' starts in ASCII at index 48, I'm calculating the char value minus the magic number 48.
However you still have to add a check for ' ' by yourself (otherwise it gets initalized with -16), but I'm sure you can do it!
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
int main(int argc, char **argv) {
std::ifstream infile("sudoku_infile.txt");
std::ofstream outfile("sudoku_outfile.txt");
int board[9][9];
size_t index = 0;
std::string str;
while (std::getline(infile, str)){
//std::cout << str << "\n";
for (size_t i = 0; i < str.size(); i++, index++){
board[index%9][index/9] = str[i] - '0';
}
}
return 0;
}
This can easily be done with one of the standard algorithm functions, namely std::copy. You can use it with iterator helpers like std::istream_inserter and std::back_inserter.
Use the above functions to put the integers into a std::vector.
After you're done with the basics, learning to use the standard library will really help you.
For example, even though you can't use it for this assignment, the above mentioned functions could be used like this:
std::vector<std::string> vs;
std::copy(std::istream_iterator<std::string>(infile),
std::istream_iterator<std::string>(),
std::back_inserter(vs));
After the above, the vector vs will contain all white-space delimited string from the infile stream.
To then get it into a board, you could to like this:
std::array<std::array<int, 9>, 9> board;
int i = 0;
for (const std::string& s : vs)
{
int j = 0;
for (const char& c : s)
board[i][j++] = c - '0';
++i;
}
When I populate the array(doska) all is ok, but when I try to print element(cout<< I get error
#include <iostream>
using namespace std;
struct doskas{
int number;
char ch;
};
int main(){
auto doska= new doskas[8][8];
auto ss="0abcdefgh";
for(int i=1;i<=8;i++){
for(int j=1;j<=8;j++){
doska[i][j].ch=ss[i];
doska[i][j].number=j;
}
}
for(int i=1;i<=8;i++)
for(int j=1;j<=8;j++){
cout<<doska[i][j].ch;//ERROR
cout<<doska[i][j].number;
}
system("pause");
return 0;
}
Try from 0 and strictly less than 8, not from one to eight.
Array indices must always start with 0 and end with N-1 where N is the size of the array. Please change your index variables in all the for loops accordingly. Like this:
for(int i=0;i<8;i++)
{
//etc
}
You just have to enumerate array indices in the half-open range [0, N), and all is well:
for (int i = 0; i < 8; ++i)
{
for (int j = 0; j < 8; ++j)
{
doska[i][j].ch = ss[i];
doska[i][j].number = j;
}
}
See Dijkstra's famous argument on why this is the sanest way to think about ranges.