Take the following program:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a[8] = "Hello, ";
char b[7] = "world!";
strcat(a, b);
cout << a;
return 0;
}
Notice that a and b have the same size as their assigned strings.
The documentation states that for strcat(a, b) to work, a needs to be large enough to contain the concatenated resulting string.
Nevertheless, cout << a displays "Hello, world!". Am I entering undefined behavior?
"Am I entering undefined behavior?"
Yes. A region at the end of a[] has been written over. It worked, this time, but might have belonged to something else.
Here I use a struct to control memory layout, and demonstrate it:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
struct S {
char a[8];
char b[5];
char c[7];
};
S s;
strcpy( s.a , "Hello, " );
strcpy( s.b , "Foo!" );
strcpy( s.c , "world!" );
strcat(s.a, s.c);
cout << s.a << endl;
cout << s.b << endl;
cin.get();
return 0;
}
This outputs:
Hello, world!
orld!
Instead of:
Hello, world!
Foo!
The strcat() has stomped all over b[].
Please note that in a real life example such bugs may be far more subtle, and lead you to wondering why perfectly innocent function calls 250 lines later crash and burn horribly. ;-)
EDIT: May I also recommend that you use strcat_s, instead? Or, even better, std::strings:
#include <string>
#include <iostream>
using namespace std;
int main()
{
string a = "Hello, ";
string b = "world!";
a = a + b;
cout << a;
}
Am I entering undefined behavior?
Yes.
If the documentation says "a needs to be large enough to contain the concatenated resulting string", why don't you simply believe it? What is there to doubt?
In your program, array a is not large enough to contain the result. Therefore, your code is wrong and should be fixed. In the words of the standard, you are indeed entering undefined behavior, which means it may work or it may not...
strcat does what is says on the tin viz. copies b onto the end of a without any care as to what data is already there. Since both variables are on the stack one after the other things work. But try
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a[8] = "Hello, ";
int i = 10;
char b[7] = "world!";
strcat(a, b);
cout << a << i;
return 0;
}
And you will probably get an unexpected result since your stack has been corrupted by strcat
That is correct.... The behavior is undefined. Just because you got that answer does not mean that it will not crash next time since the array a is too small.
Related
#include <iostream>
using namespace std;
int main() {
int age = 20;
const char* pDept = "electronics";
cout << age << " " << pDept;
}
The above code is normal.
Why shouldn't I use cout << *pDept instead of cout << pDept above?
Both of them are legal in C++. Which one to use depends on what you want to print.
In your case, pDept is a pointer that points to a char in memory. It also can be used as a char[] terminated with \0. So std::cout << pDept; prints the string the pointer is pointing to.
*pDept is the content that pDept points to, which is the first character of the string. So std::cout << *pDept; prints the first character only.
I was programming some test cases an noticed an odd behaviour.
An move assignment to a string did not erase the value of the first string, but assigned the value of the target string.
sample code:
#include <utility>
#include <string>
#include <iostream>
int main(void) {
std::string a = "foo";
std::string b = "bar";
std::cout << a << std::endl;
b = std::move(a);
std::cout << a << std::endl;
return 0;
}
result:
$ ./string.exe
foo
bar
expected result:
$ ./string.exe
foo
So to my questions:
Is that intentional?
Does this happen only with strings and/or STL objects?
Does this happen with custom objects (as in user defined)?
Environment:
Win10 64bit
msys2
g++ 5.2
EDIT
After reading the possible duplicate answer and the answer by #OMGtechy
i extended the test to check for small string optimizations.
#include <utility>
#include <string>
#include <iostream>
#include <cinttypes>
#include <sstream>
int main(void) {
std::ostringstream oss1;
oss1 << "foo ";
std::ostringstream oss2;
oss2 << "bar ";
for (std::uint64_t i(0);;++i) {
oss1 << i % 10;
oss2 << i % 10;
std::string a = oss1.str();
std::string b = oss2.str();
b = std::move(a);
if (a.size() < i) {
std::cout << "move operation origin was cleared at: " << i << std::endl;
break;
}
if (0 == i % 1000)
std::cout << i << std::endl;
}
return 0;
}
This ran on my machine up to 1 MB, which is not a small string anymore.
And it just stopped, so i could paste the source here (Read: i stopped it).
This is likely due to short string optimization; i.e. there's no internal pointer to "move" over, so it ends up acting just like a copy.
I suggest you try this with a string large number of characters; this should be enough to get around short string optimization and exhibit the behaviour you expected.
This is perfectly valid, because the C++ standard states that moved from objects (with some exceptions, strings are not one of them as of C++11) shall be in a valid but unspecified state.
If I declare a string array in c++ such as
char name[10]
how would you error handle if the input is over the character limit?
Edit: My assignment says to use cstring rather than string. Input will be the person's full name.
Here is an example where setName checks the size is OK before assigning the char[10] attribute.
Note char[10] can only store a 9-characters name, because you need one character to store the end-of-string.
Maybe that's what you want:
#include <iostream>
#include <cstring>
using namespace std;
#define FIXED_SIZE 10
class Dummy
{
public:
bool setName( const char* newName )
{
if ( strlen( newName ) + 1 > FIXED_SIZE )
return false;
strcpy( name, newName );
return true;
}
private:
char name[FIXED_SIZE];
};
int main()
{
Dummy foo;
if ( foo.setName( "ok" ) )
std::cout << "short works" << std::endl;
if ( foo.setName( "012345678" ) )
std::cout << "9 chars OK,leavs space for \0" << std::endl;
if ( !foo.setName( "0123456789" ) )
std::cout << "10 chars not OK, needs space for \0" << std::endl;
if ( !foo.setName( "not ok because too long" ) )
std::cout << "long does not work" << std::endl;
// your code goes here
return 0;
}
I'm piecing together that your instructions say to use <cstring> so you can use strlen to check the length of the string prior to "assigning" it to your name array.
so something like...
const int MAX_NAME_LEN = 10;
char name[MAX_NAME_LEN];
// ...
// ...
if (strlen(input)+1 >= MAX_NAME_LEN) {
// can't save it, too big to store w/ null char
}
else {
// good to go
}
First of all your question is not clear. Anyway I assume you want to ask for a way to ensure array index does not get out of bound.
Anything outside of that range causes undefined behavior. If the index was near the range, most probably you read your own program's memory. If the index was largely out of range, most probably your program will be killed by the operating system.
That means undefined behaviour could mean program crash, correct output etc.
Since others mentioned how to do this with a predefined input string, here's a solution which reads a c-string from input:
#include <iostream>
#define BUF_SIZE 10
using namespace std;
int main()
{
char name[BUF_SIZE];
cin.get(name, BUF_SIZE-1);
if (cin) //No eof
if (cin.get() != '\n')
cerr << "Name may not exceed " << BUF_SIZE-1 << " characters";
}
I was experimenting with C++ and I decided to try the is_big_endian code, in much the same way I would do it in C. However I am getting no output when I try to print out the value of the pointer. I tried both the C and C++ style casts. What am I doing wrong?
#include <iostream>
using namespace std;
int main (void){
int num = 1;
char *ptr = (char *)#
//char *ptr = reinterpret_cast<char *>(&num);
cout << "Value is: " << *ptr << endl;
}
operator<< sees that you are outputting a char, so it prints it as a character, not as a number (it's as if in C you wrote %c instead of %d in a printf); and since *ptr will either be 0 or 1, you'll end up in both cases with a non-printable character.
To fix this, cast explicitly *ptr to int:
cout << "Value is: " << int(*ptr) << endl;
I wrote this short program
int main(){
char * c = "abcd";
c[1] = '\0';
cout << c << endl;
}
and it doesn't work... actually it compiles the program but in the runtime an error occures...
Why? I thought it will print an "a" as the "string" now looks like this: "a0cd" so after a zero it is supposed to detect an end of the string, right? So where is the problem?
Thank you!
You can't modify string literals like that.
Try this instead:
int main(){
char c[] = "abcd";
c[1] = '\0';
cout << c << endl;
}
The reason behind this is that string literals are stored in global memory (often in a read-only segment). Modifying them is undefined behavior. However, if you initialize it as an array char c[] = "abcd" it will be on the stack (as opposed to global memory), so you can freely modify it.
if you use C++ why not use std::string::substr?
#include <iostream>
#include <string>
int main () {
std::string c = "abcd";
std::string d = c.substr(0,2);
std::cout << d << std::endl;
return 0;
}
the output of the program:
ab