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];
Related
I am new in programming,
basically in this program, it takes input from user and storing in array, 5 elements. After loop ends it should give the elements back but it seems that the last line is not working.
include<iostream>
using namespace std;
int main(){
int size=5;
string guess[size];
for (int i=0; i<size;i++){
cin>>guess[size];
}
cout<<guess[size];
return 0;
}
guess[size] is out of bounds. The last valid index in an array with size elements is size-1. Further, string guess[size]; is not valid C++ when size is not a constant expression. At the very least it should be const int size = 5;. You wrote a loop to take input and you also need a loop to print all elements.
This is the correct loop to read the input:
const int size=5;
std::string guess[size];
for (int i=0; i < size; i++){
std::cin >> guess[i];
}
You can modify it so that both input and output should use i as the loop subscript.
//cover #
#include<iostream>
using namespace std;
int main(){
int size=5;
string guess[size];
for (int i=0; i<size;i++){
cin>>guess[i];
}
for (int i = 0; i < size; ++i) {
cout<<guess[i];
}
return 0;
}
Use Range based Loops when You want to Print whole array, so you won't get an "Out-Of-Bounds" error. Because the Index in array are Zero Based Always remember the last index is (length_of_array - 1)
using namespace std;
int main()
{
int size = 5;
string guess[size];
for (int i=0; i<size;i++)
{
cin >> guess[i];
}
// range based loop
for (int i : guess)
{
cout << i << endl;
}
return 0;
}
I am self-teaching myself data-structures using Malik's "Data Structures and Algorithm Desgin using c++". The first exercise is to make an object of type numeralType and encapsulate in it all the necessary operations to take in a string a return its value in the roman numeral system.
DISCALIMER 1: Please assume that there is data validation and everything is done except the function that converts the string into its value in the roman numeral system. Also, I am using VS17.
I will not post the original "conversion" function. Instead, I will post a generic version of the algorithm used in the function.
here it is:
#include <iostream>
#include <string>
#include<map>
int main()
{
int result = 0;
std::map<char, int> charMap = { {'f',1},{'h',2},{'x',3},{'b',4},{'l',5} };
std::string testString = "lbxhf";
for (unsigned int i = 0; i < testString.length(); i++)
{
if (charMap.at(testString.at(i)) >= charMap.at(testString.at(i + 1)))
result = charMap.at(testString.at(i)) +
charMap.at(testString.at(i + 1));
}
system("pause");
return 0;
}
This code automatically calls abort() but compiles fine.
Using VS's debugger, i have singled out that the cause is string based, but I don't know exactly why.
Using a try/catch block I get that an invalid string position error. Here is the try/catch version:
int main()
{
int result = 0;
std::map<char, int> charMap = { {'f',1},{'h',2},{'x',3},{'b',4},{'l',5} };
std::string testString = "lbxhf";
try
{
for (unsigned int i = 0; i < testString.length(); i++)
{
if (charMap.at(testString.at(i)) >= charMap.at(testString.at(i + 1)))
result = charMap.at(testString.at(i)) + charMap.at(testString.at(i + 1));
}
}
catch(const std::out_of_range& e)
{
std::cout << e.what() << std::endl;
}
system("pause");
return 0;
}
I have been scratching my head around this for a whole day now and would like a few tips on how to solve this problem.
Again, this is a generic version of an algorithm that takes in a string of roman numerals and returns it value as an integer.
DISCLAIMER 2: This algorithm implies addition only, based on the rules of addition/subtraction of the roman numeral system.
DISCALIMER 3: it is important to me that I use std::map, I know it can be done using an array/vector type, but I also wish to practice using stl containers.
Thank you in advance (no need to be terribly mean guys!!)
You are accessing testString.at(i + 1), but i may be up to testString.length()-1 because of the loop condition
for (unsigned int i = 0; i < testString.length(); i++)
This is the reason for the out-of-bounds exception. (testString.length()-1 is the last index of testString and going one higher will be out-of-bounds.)
Not sure about your intentions, but maybe you want the loop condition to be
for (unsigned int i = 0; i+1 < testString.length(); i++)
to only compare neighboring elements of the string.
Here's what I came up with to solve the problem and achieve my goal:
#include<iostream>
#include<string>
#include<map>
int main()
{
int result = 0;
std::map<char, int> charMap = { {'f',1},{'h',2},{'x',3},{'b',4},{'l',5} };
std::string testString("lbxhf");
char lastChar = testString.back();
for (unsigned int i = 0; i+1 < testString.length(); i++)
{
if(charMap.at(testString.at(i)) >= charMap.at(testString.at(i+1)))
result += charMap.at(testString.at(i));
}
result += charMap.at(lastChar);
printf("%i\n", result);
system("pause");
return 0;
}
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).
I am trying to write a sudoku solver.
I got the input almost done, but something strange started happening. On the index [i][9] of int sudoku[i][9], there are numbers present that I have never put there.
For example, when I run the code below with the input that is commented below using namespace std;, the output is:
410270805
085146097
070580040
927451386
538697412
164328759
852704900
090802574
740965028
Of course, I only need 0 through 8, but I was wondering what is causing integers to appear at the 9th index.
This is the code:
#include <iostream>
#include <math.h>
#include <cstdlib>
using namespace std;
/*
410270805
085146097
070580040
927451386
538697412
164328759
852704900
090802574
740965028
*/
int main()
{
int sudoku[9][9];
int solving[9][9][9];
int input;
for (int i=0; i<=8; i++) {
cin >> input;
int j;
int k;
for (j=8, k=1; j>=0; j--, k++) {
int asdf = input/pow(10,k-1);
sudoku[i][j] = asdf % 10;
}
}
cout << endl;
for (int i=0; i<=8; i++) {
for (int j=0; j<=9; j++) {
cout << sudoku[i][j];
}
cout << endl;
}
return 0;
}
Accessing elements outside of the defined region of an array is Undefined Behavior (UB).
That means it could:
Allow you to access uninitialized space (what yours is doing hence the random numbers)
Segfault
Any number of other random things.
Basically don't do it.
In fact stop yourself from being able to do it. Replace those arrays with std::vectors and use the .at() call.
for example:
std::vector<std::vector<int>> sudoku(9, std::vector<int>(9, 0));
for (int i=0; i<=8; i++) {
for (int j=0; j<=9; j++) {
cout << sudoku.at(i).at(j);
}
cout << endl;
}
Then you will get a thrown runtime exception that explains your problem instead of random integers or segfaults.
I think I found your problem, at your very last for loop you used j <= 9 instead of j <= 8. You then tried to write (j) leaving the possibility of it writing 9 wide open. Try replacing that 9 with 8.
I'm doing some basic input parsing in c/c++.
format: number of values, followed by space separated values:
3
5 2 4
The problem here is the lack of a space after the first line. This causes cin and scanf to read 35 into the first variable, instead of 3.
int num;
scanf("%d", &num);
int array[num];
for (int i = 1; i <= num; i++) {
scanf("%d", &array[i]);
}
How do I get cin, or scanf, to stop parsing at a newline?
Edit:
Is it bad not to init variables even if they are written to later, before being read? (int num)
It works if I type the input in, but not if I paste it. Any clue?
std::cin interprets newline characters as spaces so there is the possibility the file you are working with contains something other than a newline. You are also using a non-standard extension to declare the array. This is not portable and not guaranteed to be supported by all compilers. I suggest you switch to using std::vector instead.
Your for loop is also incorrect. Array's used zero based indexing to access their elements. Because of this you end up accessing the array out of bounds which is undefined behavior. This means your program might crash, it may overwrite other variables or you might not notice any symptoms at all. This may also cause the symptom you are experiencing if it overwrites other variables.
The example below uses C++ input streams instead of scanf to provide better error checking.
#include <istream>
#include <vector>
std::vector<int> load(std::istream& in)
{
std::size_t count;
std::vector<int> data;
// If the user does not enter a number "in >> count" will fail.
if (in >> count)
{
int value;
while (count-- && in >> value)
data.push_back(value);
}
return data;
}
#include <iostream>
int main()
{
auto data = load(std::cin);
for (auto i : data)
std::cout << i << std::endl;
}
You can test this without reading from a file by using std::stringstream as the input.
#include <iostream>
#include <sstream>
int main()
{
std::stringstream text("3\n5 2 4");
auto data = load(text);
for (auto i : data)
std::cout << i << std::endl;
}
Within the for loop you started the array at position 1 and not 0. Which would cause going out of bounds, as you wanted to write to element 2 of the array. If you allocate an array of 2 elements the valid elements are going to be 0 and 1. This code works:
int num;
scanf("%d", &num);
int array[num];
for (int i = 0; i < num; i++)
{
scanf( "%d", &array[i] );
}
Start array from 0 as array indexes start from 0 - like:
for (int i = 0; i < num; i++)
You are starting first element from 1 that makes it undefined. Moreover, you should make dynamic array.
I liked Lidong Guo's code, and have modified it to run with Microsoft's C Compiler.
The only change was to move all of the data definitions ahead of any executable code, plus I added a space between the printed numbers.
#include <stdio.h>
#include <stdlib.h>
main()
{
int num;
int *array; //[num];
int i;
scanf("%d\n", &num);//here deal with the newlinw
array= malloc(sizeof(int) *num);//[num];
for (i = 0; i < num; i++)
{//the loop .start 0 end num -1
scanf("%d", &array[i]);
}
for (i = 0; i < num; i++)
{
printf("%d ", array[i]);
}
free(array);
}
[Edit: The Answere is specific to C++, as the Question also have a C++ tag]
Well first thing first.
You array defination is wrong .
int array[num]; // Super wrong way
You are not supposed to pass a variable as index while defining an array, its not allowed. Else, it will cause "nasal demon".
int * array = new int[num] //correct way
The code might be working correctly now but the array definition given by you lies under the category of UB.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
scanf("%d", &num);
int *array= malloc(sizeof(int) *num); // num is known at runtime
int i;
for (i = 0; i < num; i++) { //starts at 0, ends at num - 1
scanf("%d", &array[i]);
}
for (i = 0;i< num; i++) {
printf("%d", array[i]);
}
free(array);
}
Change the
scanf
statement to
scanf("%d", &array[i]);
Also array indexing starts from 0 and ends at num-1
Start your loop from 0 and end it at num-1,i.e
for (int i = 0; i < num - 1; i++)
scanf("%d", &array[i]);
And the reason for pasted input does not work is that it doesn't contain newline between two lines