0

please take a look at this code

#include <iostream>

int main(int argc, char** argv) {
    char ch[10];
    int i = 0;
    std::cout << "Enter a number: \n";
    std::cin >>ch;


    std::cout << "i = "<<i;

}

output:

Enter a number:
123456789123456789
i = 926299444

why this is happend and what is the best way to prevent this ?

where can i learn more about this kind of unsafety ?

Rhathin
  • 1,176
  • 2
  • 14
  • 20

1 Answers1

4

Your program has undefined behavior, because you are writing out-of-bounds of ch. One possible manifestation of this is that your program behaves as if an unrelated variable was overwritten. This particular kind of undefined behavior is known as a stack buffer overflow.

The >> only gets a pointer to the first element of the ch array as argument and so it doesn't know how long the array is and will just keep writing no matter how long the user's input is. This behavior known as array-to-pointer decay is normal for raw arrays (but unintuitive). This is why you should avoid using them.

It is never safe to use a char pointer or array with cin >> if you don't know apriori the maximum length of the input. As mentioned in a comment below, this is why this overload will be removed in the upcoming C++20 standard, so that you will get a compile-time error, rather than the undefined behavior at runtime that you are observing.

The solution is simple: Don't use char arrays. Use std::string instead.

#include <iostream>
#include <string>

int main(int argc, char** argv) {
    std::string ch;
    int i = 0;
    std::cout << "Enter a number: \n";
    std::cin >> ch;

    std::cout << "i = " << i;
}

std::string can hold any length of string and will allocate and manage the required memory itself.


Also note that you can read numbers directly into integers (which seems to be what you actually want to do):

#include <iostream>

int main(int argc, char** argv) {
    int i = 0;
    std::cout << "Enter a number: \n";
    std::cin >> i;

    std::cout << "i = " << i;
}

This will fail if the number is too large for int to hold it or if the user tries to input something that isn't a number, so you should check whether it failed. You should always check the input functions for failure, like this:

#include <iostream>

int main(int argc, char** argv) {
    int i = 0;
    std::cout << "Enter a number: \n";
    if(!(std::cin >> i)) {
        // handle error here
        std::cout << "You must insert a valid number in the range of int!\n";
        return 1; // exit `main` with return value indicating error
    }

    std::cout << "i = " << i;
}
walnut
  • 21,629
  • 4
  • 23
  • 59
  • 2
    Good news: since C++20 the overload of `operator>>` OP has used is [gone](https://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt2), now we have one that takes the array by reference, so it knows the array size and won't write out of bounds. – HolyBlackCat Dec 22 '19 at 13:46
  • if the cin fails , will the next value be modfied again? – saeed mahmoodi Dec 22 '19 at 13:52
  • @saeedmahmoodi (Since C++11) if the `cin >> i` fails, `i` will be assigned value `0` and nothing else happens. It will not cause undefined behavior or anything else to be overwritten. Note that you will need to clear the failbit flag if you want to continue reading after a failed input operation. See e.g. [this question](https://stackoverflow.com/questions/5131647/why-would-we-call-cin-clear-and-cin-ignore-after-reading-input) – walnut Dec 22 '19 at 13:54
  • I just tested it now, even if I check the cin , if user write more than 10 characters, I will be modified; I want a way to let the user input as many characters as he wants but the program must read only 10 of them without any undefined behavior – saeed mahmoodi Dec 22 '19 at 14:02
  • 1
    @saeedmahmoodi https://stackoverflow.com/questions/15883553/reading-a-specific-number-of-characters-from-c-stream-into-stdstring But are you sure you actually want that? The other characters that the user typed will be read as input in your next `cin` read or maybe you just want to cut of the other characters from `ch` after you read it. (`std::string` has a `substr` method for that). Or you may simply want to check whether `i` is strictly between `-10'000'000'000` and `10'000'000'000`? – walnut Dec 22 '19 at 14:09