cin >> writing out of range? - c++

I have a code
char s[5];
cin >> s;
cout << strlen(s);
cout << endl;
cout << s;
It works even if I input more than 5 chars, for example "qwertyui". Does it mean that I am using not allocated memory?

strlen(s)
is something, but has nothing to do with 5. strlen applies to C strings, which are char arrays, but their length is defined as the numbers of characters until the first zero byte happens.
Now, cin in your second line cannot know how long your char[] is, so it just accepts as much input as there is. You must never use char buffers for input you don't know is well-formed. What you're seeing is a buffer overflow in action. Writing over memory that doesn't belong to any variable you allocated results in undefined behaviour, so your program might just work, crash with e.g. a segfault (accessing memory that the OS never gave you), or overwriting existing part's of your processes' memory, or … just do anything, because it's really undefined.
So, you're writing C++, not C. just
string s;
cin >> s;
cout << s.length()
<< endl
<< s;
to avoid dealing with the (very dangerous) C strings.

You're right, it might still echo correctly if you write more than 5 characters. You're simply writing off the end of the buffer, and just blasting the memory that's next to the memory allocated for char s[5]. This is bad for many reasons, including security vulnerabilities. See here for details.
If you can't use string (for whatever reason), use fgets. See here for the documentation on fgets and how it is used. NEVER USE gets. It's almost equivalent to what you've done above, see here for why gets is so dangerous.

Related

Declaration of a String of Dynamic Length Using Pointer

I wanted to declare an array with a pointer in character type, and the length of the array can be determined by my input string.
I wrote it in this way:
char *s;
cout << "Enter a string: " << endl;
cin >> s;
I expected that I can initialize the string by the cin operation, but an error showed up when compiling. The error is about "invalid operands to binary expression".
I'm not sure why the lines I wrote was wrong.
I though not only the built in string class is used for declaring an array.
Isn't the string data type in C++ the same as "a character array"?
Isn't the line char *s means the pointer s points to an character array (or string)?
Thank you!
You should use std::string.
It is a class that represents a string of characters. It is different than an old c style array of characters (although internally might contain one).
In your case:
#include <string>
#include <iostream>
std::string s;
std::cout << "Enter a string: " << endl;
std::cin >> s;
Using std::string means memory is managed automatically for you. Specifically with cin it will also be resized to fit the input.
A side note: better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.
"the cin operation".
cin is really the source. The real work is done by the overloaded operator>>. And the operator>> which reads to a char* expects that the char* is already allocated to the right size. That's of course a problem with cin, where the size is unknown.
The operator>> overload that reads to std::string will resize the std::string to the right size.
The answer to your question is no, as when you create a type pointer you always have to specify in advance how much memory to allocate. We can imagine that this is what happens with strings, that is to go to fetch the data and arrange the occupied cells in memory at a later time.
Now the real problem is, it is true that you have declared a pointer to a character, but you have not specified how much to allocate for it. It is as if you are saying you want to create a box but you are not specifying the size. I show you the correct method:
char *s = new char[10];
Obviously when using pointers, always remember to deallocate them at the end of use so as not to have any memory leaks.
Taking a summary of the situation, you tried to save a data in a box that you intend to create but does not exist. That is, you have named the box called s which will contain a pointer to a character but you have not yet built/created it in its final size.

Purpose of char a[0] in converting integer to string using itoa()

I have this code,
char a[0];
cout << "What is a? " << a << endl;
char *word = itoa(123,a,10);
string yr = string(word);
but i have trouble comprehending the array a[0]. I tried to change its value and see if there is any changes, but it seems to make no differences at all.
example, even if a change a[0] to a[1], or any other integer, the output still make no difference
char a[1];
cout << "What is a? " << a << endl;
char *word = itoa(123,a,10);
string yr = string(word);
What is its purpose here?
Since itoa function is non-standard, this is a discussion of a popular signature itoa(int, char*, int).
Second parameter represents a buffer into which a null-terminated string representing the value is copied. It must provide enough space for the entire string: in your case, that is "123", which takes four characters. Your code passes a[] as the buffer, but the size of a[] is insufficient to accommodate the entire "123" string. Hence, the call causes undefined behavior.
You need to make a large enough to fit the destination string. Passing a buffer of size 12 is sufficient to accommodate the longest decimal number that can be produced by itoa on a 32-bit system (i.e. -2147483648). Replace char a[0] with char a[12] in the declaration.
What is its purpose here?
A zero-length array is an array with no elements in it.
You can't [legally] print or modify its contents, because it doesn't have any.
There are arcane reasons to want to use one, but speaking generally it has no purpose for you. It's not even allowed by the standard (although compilers tend to support it for those arcane reasons).
even if a change a[0] to a[1], or any other integer, the output still make no difference
Well, if you have an array with n elements in it, and you write more than n elements' worth of data to it, that's a "buffer overrun" and has undefined behaviour. It could appear to work as you overwrite somebody else's memory, or your program could crash, or your dog could suddenly turn into a zombie and eat you alive. Best avoided tbh.

trying to get string to char array, help me get just the required characters in array

i'm trying to convert a string to char array; it goes fine for 3 letters, but some weird chars come for longer strings.
the script works fine till i print the whole array at once...
std::string word;
std::cout<< "enter word: ";
cin>>word;
cin.ignore();
//std::cout<< word ":"<<word.length();
int len=word.length();
char char1[len-1];
cout<<"\n";
for (int a=0;a<len;a++)
{
char1[a]=word.at(a);
std::cout<<char1[a];
}
cout<<"\ncheckline: "<<char1;
for input "abcd"
output is "abcdπ"
You have four problems.
Firstly, the size of an array must be compile time constant. len is not a compile time constant, so the program is ill-formed according to the standard. Henceforth, I shall assume that your compiler supports "Variable Length Array" language extension. In standard C++, you must allocate dynamic memory if the size is determined at run time.
Secondly, you allocate too little memory, and overflow your buffer. If you allocate memory for len - 1 characters, then the last valid index is len - 1 - 1. Writing to char1[len - 1] as you do, has undefined behaviour. char1[len] would be required for len characters.
Thirdly, you didn't terminate the string with null. The standard requires that any string inserted into a stream must be null terminated. However, you pass char1 into std::cout even though it does not contain a null terminated string. The behaviour is undefined. Note, that would have to also remember to allocate memory for this null termination character: char1[len + 1]; ... char1[len] = '\0'.
Lastly, what you're attempting is probably pointless. Re-view the reasons why you think you need to do this. I suspect that those reasons are misguided.

Why does the cin extraction operator cause a segfault?

#include <iostream>
using namespace std;
int main() {
char * c;
cin >> c;
return 0;
}
I'm trying to get a C string line from the user whose length is not known. I know that if I declared c as char c[80] instead of char * c then it wouldn't cause a segfault.
However what if I didn't want to restrict the user to 80 - 1 characters? I could use a really big number but that would just waste space.
I would also really like to know why the above program causes a segfault. From what I understand the cin extraction operator (>>) knows to NULL terminate a C string. What exactly is causing the problem?
The program segfaults because the pointer c is not initialized. You need to allocate memory for the buffer before reading the data into it:
char * c = new char[80];
cin >> c;
cout << c << endl;
delete[] c; // Now you need to delete the memory that you have allocated.
To avoid restricting your input to N characters, use strings. They resize dynamically as you need:
string c;
cin >> c;
cout << c;
// You do not need to manage string's memory - it is done automatically
You've allocated no space at all for the string when you use only char *c;. The variable declaration creates a pointer to char which is uninitialized. Then you use cin to read a string into that space. c could point to anything, and in any case will point to memory that doesn't belong to you.
You'll need to allocate space for the string before you try to fill it from cin.
If you don't want to assume a limit on the string length, you can loop and realloc more space until the input is completely read, but as has been mentioned, if you use std::string instead of C strings, then this will be handled for you.
That is because you did not allocate memory for your string.

Why does this C++ char array seem to be able to hold more than its size?

#include <iostream>
using namespace std;
typedef struct
{
char streetName[5];
} RECORD;
int main()
{
RECORD r;
cin >> r.streetName;
cout << r.streetName << endl;
}
When I run this program, if I enter in more than 5 characters, the output will show the whole string I entered. It does not truncate at 5 characters. Why is that?
How can I get this to work correctly?
You are overflowing the buffer. Put another char array after streetName and you will likely find that it gets the rest of the characters. Right now you are just corrupting some memory on your stack.
In order to limit the input to the size of the receiving array you need to use the length-limiting facilities provided by your input method. In your case you are using cin, which means that you can specify the limit by using its width method
cin.width(5);
cin >> r.streetName;
Because cin sees streetName as a char * and writes to memory and there is nothing to stop writing to *(streetName + 6) and further. This is a form of buffer overrun
The best code in this case is define streetName as a std::string
i.e.
typedef struct
{
std::string streetName;
} RECORD;
Because you're overruning the end of your buffer and in this particular case you're getting away with it. C and C++ make it very easy to "shoot yourself in the foot", but that doesn't mean that you should.
It's a buffer overrun.
C++ does not perform bounds checking on array accesses, and memory does not simply stop at the end of the array. You are writing data to memory that is not part of the array, the consequences of which are non-deterministic, and may sometimes even appear to work.
It is quite likely that if you placed that code into a function, the program would crash when you tried to return from the function, because one likely possibility is that you will have dumped on the function return address on the stack. You may also have corrupted data belonging to the calling function.
The way to do this correctly in c++ is to use a std::string.
#include<iostream>
#include<string>
....
std::string r;
getline(cin, r);
std::cout << r <<std::endl;
For truncated input(with suitably defined and inited values).
while(cin.peek() != EOF && i < len)
{
cin >> arr[i];
++i;
}
You will want to do something after this to flush the buffer and not leave the rest of the line sitting on the input stream if you plan on doing other things with it.