Why can't I directly read from cin into an array index? - c++

I'm trying to learn C++ on HackerRank, but I've encountered a weird situation in one of the exercises given.
The exercise is to read in a list of numbers and print them out reversed. However, my code appears to spit out garbage values for one of the test cases.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int n;
int temp;
int *arr = new int[n]();
cin >> n;
for (int i = 0; i < n; i++) {
// This works
/*
cin >> temp;
arr[i] = temp;
*/
cin >> arr[i]; // But this doesn't
}
for (int j = n - 1; j >= 0; j--) {
cout << arr[j] << " ";
}
return 0;
}
The input for the offending test case was a bit long, so I put it into a pastebin: https://pastebin.com/VCjciUet
When reading directly from cin (i.e. cin >> arr[i]), the output was as follows:
6002 {...truncated...} 8084 3909 5426 808465952 942682421 540227121 824194360 909189169 959526176 825243441 540619576 891304241 842539056 825374240 960050744 540619575 958412851 892805173 808722489 960050720 959460408 540553528 891302967 926425141 909718304 859189816 540226104 941634871 842342452 808662048 809054519 540160311 891303224 875634745 808466464 876034355 540423990 958412593 925966391 892613920 808662321 540422194 958411319 840972592 876159030 825374752 926364977 540553273 874526514 924858416 876093495 875770144 858928434 540030771 941634360 875831350 959788576 842413112 540095796 874525239 959651892 959723040 842018869 540096056 874525751 540424244 908079412 859185206 960051232 875901235 540028978 924857392 926228532 808925216 959526195 540095028 908079408 960045108 825308448 942684471 540096306 840971065 858857522 892739637 926103072 842150707 540291892 941634608 875700275 876033824 909457721 540160822 824194100 859250740 825766688 875706678 540356912 840972345 875962418 808923936 825242421 540226869 924856887 892608560 825439520 909130037 540620083 857749813 943267896 943011360 925972531 540094773 840971319 825368627 808728608 808728374 540161588 908079666 842080313 909652512 876032561 540554040 941635895 808788017 808858144 825505842 540555320 840972344 892870710 825832480 842150450 540422199 874526264 909713464 892482592 926366005 540094769 924857396 842407992 892811040 875705656 540619320 908080177 857748528 875962423 909652256 892745779 540226866 540423479 540554291 540619064 540096820 891302709 926294071 808597792 892679200 909522745 540555315 924858417 891303988 909451315 859054128 909523232 942684473 540031287 857748019 808984630 959591456 925971510 540619057 958411316 909385783 825506080 858927392 808597810 540357168 908080176 909385778 858993440 875705632 892679737 540422960 924858672 875896883 875967520 842283065 540358967 908079669 859381815 943273248 825439288 540422969 908081465 926162994 925905440 959591735 540094512 824193335 859054130 875896889 876098848 959459892 540358706 540028977 2139 7277 9113 6303 924 7608 749 6043
However, the output was accurate (the entire list of numbers reversed) when I used a temporary variable first.
Why is this so?

It's so because you didn't listen to your compiler:
main.cpp: In function 'int main()':
main.cpp:13:27: warning: 'n' is used uninitialized in this function [-Wuninitialized]
int *arr = new int[n]();
^
Writing low-level code is prone to mistakes like those. Prefer high-level library features that prevent them. If your goal was to read a collection of numbers and print them out, it can be done without any loops at all:
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> v;
std::copy(
std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(v)
);
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout));
}
This code will simply read until the numbers end. If you want to read the count of them first, you still should check whether they don't end beforehand. One issue with learning via things like HackerRank is that they completely omit learning input sanitization and error handling, which are crucial in real-world coding.

Turn on the compiler warnings:
source>:13:24: error: 'n' is used uninitialized in this function [-Werror=uninitialized]
13 | int *arr = new int[n]();
|
n was uninitallized when you used it. Also, you never deleted the array. Yes, the OS will clean up after you, but it is best to free the memory you allocated. Here's the fixed version:
#include <iostream>
int main() {
int n;
std::cin >> n;
int *arr = new int[n]();
for (int i = 0; i < n; i++) {
std::cin >> arr[i];
}
for (int j = n - 1; j >= 0; j--) {
std::cout << arr[j] << " ";
}
delete[] arr;
return 0;
}
Having said that, it's probably a better idea to use std::vector and std::size_t. Here's how you go about doing that:
#include <iostream>
#include <vector>
int main() {
std::size_t n{};
std::vector<int> vec{};
std::cin >> n;
vec.resize(n);
for (auto&& elm : vec)
std::cin >> elm;
for (auto rit = vec.crbegin(), rend = vec.crend(); rit != rend; ++rit)
std::cout << *rit << ' ';
return 0;
}
With a little help from Boost this example can be shorter.
#include <iostream>
#include <vector>
#include <boost/range/adaptor/reversed.hpp>
int main() {
std::size_t n{};
std::vector<int> vec{};
std::cin >> n;
vec.resize(n);
for (auto&& elm : vec)
std::cin >> elm;
for (auto&& elm : boost::adaptors::reverse(vec))
std::cout << elm << ' ';
}

Related

std::cin string to int array with variable length input

I have a task where i need to revert a list of variable length numbers. This could be "1 2 3" or "5 6 7 8 9 10".
The sorting itself works fine.
But I can't figure out how to read the user input (with variable length) and then only execute the reverseSort once.
How can I read the user input into an array where each index is based on the space between the numbers?
Here is my code:
#include <iostream>
#include <string>
using namespace std;
bool sorted = true;
int temp;
int * arr;
int arrLength = 5;
int arrs;
// int arr = {1,2,3,4,5};
void reverseSort(int arr[], int n){
sorted = true;
for (int i = 0; i < n-1; i++){
if (arr[(i + 1)] > arr[i]){
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
sorted = false;
}
}
if (!sorted){
reverseSort(arr,n);
}
}
int main(void){
// get user input !?!?!?!?!
cin >> arrs;
cout << arrs;
reverseSort(arr,arrLength);
for (int i = 0; i < arrLength; i++){
std::cout << arr[i] << " ";
}
return 0;
}
If you don't know number of inputs you need struct that can be resized. std::vector is good for it. For adding new data you can use member function push_back.
You can read the input line as std::string (by std::getline) and you can open new stream with read data (std::istringstream). Further one can read values from new stream.
And I think you can use std::sort instead of reverseSort (but for 'reverse' you need use std::greater as comparator).
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
int main(void){
std::vector<int> arrs;
// read only one line
std::string input;
std::getline(std::cin, input);
std::istringstream row(input);
int x;
while (row >> x)
{
arrs.push_back(x);
}
//like your reverseSort
std::sort(arrs.begin(), arrs.end(), std::greater<int>{});
for (auto var : arrs) {
std::cout << var << "; ";
}
return 0;
}

"No match for operator>>" but I don't understand why. Could you explain me, please?

I have got the following code:
#include <iostream>
#include <vector>
using namespace std;
vector<int> Reversed(const vector<int>& v){
//vector<int> v; //[Error] declaration of 'std::vector<int> v' shadows a parameter
int z; vector<int> copy; vector<int> working;
working = v;
z = working.size();
int i;
for (i = 0; i<=z; i++){
working[i] = working[z];
copy.push_back(working[i]);
}
return copy;
}
int main() {
vector<int> v;
cin >> v; /*[Error] no match for 'operator>>' (operand types are 'std::istream'
{aka 'std::basic_istream<char>'} and 'std::vector<int>')*/
cout << Reversed(v);
return 0;
}
Please, explain to me why I am getting this error on line 18:
no match for operator >>`
P.s.: const & i is a prerequisite task, I cannot change it. I just need an upside-down copy of this vector.
It looks like you are asking the user to enter a list of numbers. std::cin (or just cin, since you've got use namespace std;) doesn't know how to receive a list of integers and turn that into a vector<int> for you.
If you want to receive a vector from user input, I would suggest you ask the user for a list of numbers, something like:
// replace VECTOR_LENGTH
for (int i = 0; i < VECTOR_LENGTH; i++) {
int num;
cin >> num;
v.push_back(num);
}
You are trying to read the whole vector in one go when you do this cin >> v;. You probably want to read one element at a time, like:
#include <iostream>
#include <vector>
using namespace std;
int main(void)
{
// read five integers from stdin
const int n = 5;
vector<int> v(n);
for(int i = 0; i < n; ++i)
cin >> v[i];
for(int i = 0; i < n; ++i)
cout << v[i] << "\n";
return 0;
}
Output:
0
1
2
3
4
Or use std::vector::push_back as in #ajm answer.

Displaying all prefixes of a word in C++

I am trying to do is display all the suffixes of a word as such:
word: house
print:
h
ho
hou
hous
house
What I did is:
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char cuvant[100];
int i,k;
cin>>cuvant;
for(i=0;i<strlen(cuvant);i++)
{
for(k=0;k<i;k++)
{
if(k==0)
{
cout<<cuvant[k]<<endl;
}else
{
for(k=1;k<=i;k++){
if(k==i) cout<<endl;
cout<<cuvant[k];
}
}
}
}
}
What am I doing wrong?
You're over-complicating it. Here's a simpler way:
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s;
std::cin >> s;
for (std::string::size_type i = 0, size = s.size(); i != size; ++i)
std::cout << std::string_view{s.c_str(), i + 1} << '\n';
}
If you don't have access to a C++17 compiler, you can use this one:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
int main() {
std::string s;
std::cin >> s;
for (auto const& ch : s) {
std::copy(s.c_str(), (&ch + 1),
std::ostream_iterator<decltype(ch)>(std::cout));
std::cout << '\n';
}
}
Even so, I think it would be better for your learning progress to use a debugger to finger out the problem yourself. Here the problems with your code:
For the i=0 (the first iteration of your outer loop) the for(k=0;k<i;k++) will not be executed at all, as k<0 evaluates to false.
And having a running variable (k) that you change in two for loops that are nested, is most of the time also an indication that something is wrong.
So what you want to do: You want to create each possible prefix, so you want to create n strings with the length of 1 to n. So your first idea with the outer loop is correct. But you overcomplicate the inner part.
For the inner part, you want to print all chars from the index 0 up to i.
int main() {
char cuvant[100];
std::cin >> cuvant;
// loop over the length of the string
for (int i = 0, size = strlen(cuvant); i < size; i++) {
// print all chars from 0 upto to i (k<=0)
for (int k = 0; k <= i; k++) {
std::cout << cuvant[k];
}
// print a new line after that
std::cout << std::endl;
}
}
But instead of reinventing the wheel I would use the functions the std provides:
int main() {
std::string s;
std::cin >> s;
for (std::size_t i = 0, size = s.size(); i < size; i++) {
std::cout << s.substr(0, i + 1) << std::endl;
}
}
For this very simple string suffix task you can just use:
void main()
{
std::string s = "house";
std::string s2;
for(char c : s)
{
s2 += c;
cout << s2 << endl;
}
}
For more complicated problems you may be interested to read about Suffix Tree
Your code is wrong, the following code can fulfill your requirements
#include <iostream>
using namespace std;
int main()
{
char cuvant[100];
int i,k;
cin>>cuvant;
for(i=0;i<strlen(cuvant);i++)
{
for (k = 0; k <= i; ++k)
{
cout<<cuvant[k];
}
cout<<endl;
}
}

Show me a way to sort a char vector in c++

I'm doing this exercise from DCoder, and I'm trying to solve it in C++. But I need a little help. Although I know this should be simple, I just seem to miss something.
I'm given 2 inputs, the first one is the number of letters that will follow, and the second input is these letters. I need to write a code that will give an output of the letter array in alphabetically sorted order.
Example input:
5
Z k a P b
Expected output:
a b k P Z
Can any of you guys show me what the simplest way is to solve my problem?
I tried the std::sort() function in many ways, but it's not helping me much.
Is the std::sort() function even a good way to sort something like this?
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
//Compiler version g++ 6.3.0
int main() {
int n;
cin >> n;
char s;
vector<char> vec;
while (cin >> s){
vec.push_back(s);
}
sort(vec.begin(), vec.end());
for (int i = 0; i <= vec.size(); i++){
cout << vec[i] << " " ;
}
}
My code is supposed to output a c D M, but it's giving D M a c instead.
std::sort() will work fine, but note that it orders values in ascending order by default, and in ASCII uppercase letters appear before lowercase letters. To get around that, you can give std::sort() a custom comparator that performs a case-insensitive comparison, eg:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cctype>
int main() {
int n;
char c;
std::vector<char> vec;
std::cin >> n;
for (int i = 0; (i < n) && (std::cin >> c); ++i) {
vec.push_back(c);
}
/* alternatively:
std::copy_n(std::istream_iterator<char>(std::cin), n, std::back_inserter(vec));
*/
std::sort(vec.begin(), vec.end(),
[](unsigned char c1, unsigned char c2){ return std::tolower(c1) < std::tolower(c2); }
);
for (size_t i = 0; i < vec.size(); ++i){
std::cout << vec[i] << " ";
}
/* alternatively:
for (char c : vec){
std::cout << c << " ";
}
*/
}
Live Demo
This is the code that worked for me:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
//Compiler version g++ 6.3.0
char my_tolower(char ch)
{
return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
}
int main() {
int n;
cin >> n;
char c;
vector<char> vec;
for (int i = 0; (i < n) && (cin >> c); ++i){
vec.push_back(c);
}
sort(vec.begin(), vec.end(),
[](char c1, char c2){ return my_tolower(c1) < my_tolower(c2); }
);
for (auto &&c : vec){
cout << c << " ";
}
}

C++ determinable array input in one line

I'm pretty new to c++ and can't seem to find correct way to code this. I have array of n digits, my code now:
int main()
{
int n,i;
cin >> n;
int a[n];
for (i=1;i<=n;i++)
{
cin >> a[i];
}
return 0;
}
This way every element of array has to be input in different line, is it possible to put all elements of a array in one line, with space between them.
I am assuming your question is "what is the correct way to do this?"
I would do it this way:
#include <iostream>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
int main()
{
int n;
cin >> n;
vector<int> v;
int i = 0;
int value;
while (i++ < n && cin >> value)
{
v.push_back(value);
}
char const* sep = "";
for (auto item : v)
{
cout << sep << item;
sep = " ";
}
cout << endl;
}
Note that this code is making assumptions that the input is well formed. If you need something that is more robust in handling possibly malicious input, that would require extra effort. This code, as given, will give-up-trying-and-continue which may or may not be suitable for your purposes.
The following code snippet of your program is a Variable Length Array(VLA) and this is only supported in C since ISO C99.
cin >> n;
int a[n];
And as previously pointed out, you can also use std::vector instead.
int main()
{
int size;
std::cin >> size;
int *array = new int[size];
delete [] array;
return 0;
}
References:
http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
How to create a dynamic array of integers
Without using stl container , one can implement like so:
#include <iostream>
#include <string>
#include "stdlib.h"
void GetInput(int* inputs, int n)
{
// store the entered numbers in a char[]
std::string word;
std::cout << "enter numbers (separate by space) ";
std::getline(std::cin, word);
char ch[100];
strcpy_s(ch, word.c_str());
char *temp = ch;
// parse the char[] for integers
for (int i = 0; strcmpi(temp, "") != 0 && i <= n; temp++,i++) {
*(inputs +i) = std::strtol(temp, &temp, 10);
}
}
int main()
{
int n = 3;
int inputs[10];
GetInput(inputs,n);
for (int j = 0; j < n; j++)
std::cout << inputs[j] << " \n";
return 0;
}
Output: