简体   繁体   中英

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

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 (ie 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 delete d 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 << ' ';
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM