C++ memcpy to char* from c_str - c++

I've done a bit of basic reading and from what I've gathered .c_str() always has a null terminator.
I have a fairly simple C++ program:
int main(int argc, char** argv)
{
std::string from = "hello";
char to[20];
memcpy(to, from.c_str(), strlen(from.c_str())+1);
std::cout<< to << std::endl;
return 0;
}
Will that memcpy ensure that I copy over a null-terminated string to my variable to (provided that my string from is shorter in length)?

You should use std::string to copy strings. However, if you want to do it like that you should use strcpy instead of memcpy
int main(int argc, char** argv)
{
std::string from = "hello";
char to[20];
strcpy(to, from.c_str());
std::cout<< to << std::endl;
return 0;
}

memcpy doesn't know what is a string. you give it a range to copy. it depends on strlen here to provide the termination point of range

Yes, this will work as long as your string in from is shorter than 20. Oh, no, wait, we are also copying the NULL terminator so it must be shorter than 19. I guess you see how that can lead to some confusion.
Which is by the way exactly the reason why this code is dangerous: I am assuming this is demo code and your actual code will get that string from some sort of input. At that moment you will not be able to control how long it is. You can truncate it but you might forget to do that which means that your program will be copying content to memory that possibly does not belong to it. This might lead to a crash but at least to undefined behaviour as you are overwriting memory that might contain other important data.
Using the string class actually helps to avoid such problems by not having to specify the string length. I would suggest using this class and only do operations involving c_str() when absolutely necessary.

The answer to your question is "yes" (as long as you char array is big enough, you should put a verification step).
If you really want to do this, you can do:
int main(int argc, char** argv)
{
std::string from = "hello";
char* to = new char[from.length() + 1];
strcpy(to, from.c_str()); ///Or memcpy(to, from.c_str(), from.length() + 1 );
std::cout<< to << std::endl;
delete[] to;
return 0;
}
Which is safer as long as you are not writing another, longer string into "to"

Related

Simple String Handling sprintf

I couldn't believe that I couldn't get this right! Someone please help!
This says word is being used without being initialised(Is that required?):
int main(int argc, char* argv[])
{
char* word;
sprintf(word,"%d",12);
std::cout << word;
return 0;
}
And if I were to do this, it gives DEBUG ASSERTION FAILED!:
int main(int argc, char* argv[])
{
char* word = NULL; // char* word = nullptr;
sprintf(word,"%d",12);
std::cout << word;
return 0;
}
I have included stdio.h header. It is not making sense how I am fumbling over this.
You need to initialize it with allocated memory.
char word[20];
or
char* word = new char[20];
Initializing it to NULL will make it crash as the function tries to write at this address. Not initializing it will be undefined behavior as well since the address will be garbage.
Both those code snippets are undefined behavior.
In the first, the pointer word is uninitialized, so its value is indeterminate (and will seem to be random), so when using to write data you don't know where it will be written.
The second will always write to address zero, which is also undefined behavior.
The solution to this is to remember that you are using C++, which have std::string:
std::string word;
word = "12";
Or if you have the number as an integer that you want to use, then look at std::ostringstream:
int value = 12;
// ...
std::ostringstream os;
os << value;
std::string word = os.str();
You are declaring word as a pointer: to what?
If you need a string, and you still want to use sprintf, you have to declare its length:
char word[20]; // twenty bytes including string terminator \0
This fixed-length syntax is prone to errors and nowadays obsolete: please refer to #Joachim Pileborg answer for a better use of strings in C++

char pointer parameter different behaviour

I have the following code:
void uppercase(char *sir)
{
for(int i=0;i<strlen(sir);i++)
{
sir[i]=(char)toupper(sir[i]);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
//char lower[]="u forgot the funny"; this works
//char *lower="u forgot the funny"; this gives me a runtime error
uppercase(lower);
cout<<lower<<"\n\n";
system("PAUSE");
return 0;
}
I have noted that if I run with the char vector it works.
When I try to run with the second method it generates a runtime error.
I would like to know the reason for this behaviour please.
You cannot modify string literals; doing so (as in your second case) is undefined behaviour.
char x[] = "foo";
creates a character array containing the characters f,o,o,\0. It's basically a mutable copy of the string.
char *x = "foo";
creates a string pointer pointing to the "foo" string literal. The literal may live in some read-only memory, in the program memory, or in a constant pool. Writing to it is undefined behaviour. Also, not that the type of a string literal is always const char[], so assigning it to a char * is violating const-correctness.
The former creates a character array which can be mutated, the latter is a pointer to fixed memory (which cannot be manipulated)

Inputting into a char* declared earlier crashes the program while doing that into a 'just-declared' char* doesn't. Why?

This code crashes the program
#include <cstdio>
int main()
{
char *name1;
char *name2 = "Mark";
gets(name1);
puts(name1);
return 0;
}
whereas this doesn't
#include <cstdio>
int main()
{
char *name1 = "Mark";
char *name2;
gets(name2);
puts(name2);
return 0;
}
Why ?
I am using MinGW with Code::Blocks IDE.
You are just lucky that one crashes and other doesn't.
Both of the programs produce undefined behavior.
char *name2;
gets(name2);
You need to point the pointer to a valid and big enough memory to be able to write to it. You are just writing to a uninitialized pointer. This results in Undefined behavior. Undefined behavior does not mandate a crash, it literally means any behavior is possible, as in your case it might crash sometimes and may not but nevertheless it is a incorrect program.
Ideal Solution is to simply use std::string.
If you insist on using char * you need to point this pointer to a valid memory. For e.g.
char myArr[256];
char *name2 = &myArr;
Both are Undefined Behavior, will it crash or not, is rather matter of luck.
You have to provide the memory for your input, but you don't. If you want to stick at gets and puts you should change char *name to char name[100] or allocate memory:
char *name = new char[100];
...
delete name;
If you need more than 100 chars (including the \0 char at the end of the string) you have to increase the size accordingly.
In C++ using std::string is most likely the better alternative.

c++: write a char at a given char* causes segfault

I want to copy a char to an address where a given char* points to.
it's in a function which is called by main:
char data = " ";
myfunction(data, somethingelse);
...
inside the function i have something like
void myfunction(char* data, short somethingelse) {
...
char byte = 0;
inputfilestream.read(&byte, 1);
*data = byte; // here i get the segfault
data++;
...
}
the segfault also comes when i to the copy using strncpy:
strncpy(data, byte, 1);
why is there a segfault? data isn't const and the address where i actually write to is exactly the same as the one where i allocated the data-array. i've tested that multiple times.
thanks in advance.
String literals are readonly. If you want a modifyable string, you must use an array, e.g.:
char data[10];
Or:
char *data = new char[10];
To elaborate a bit more: the type of a string literal is actually const char*. Assigning a string literal to a non-const char* is therefore technically invalid, but most compilers allow it anyway for legacy reasons. Many modern compilers will at least issue a warning when you try to do that.
data is assigned a string literal. String literals are ready only, and writing to them will cause segfaults.
Try this:
char data[10]; // or whatever size you want.
instead.
why is there a segfault? data isn't const and the address where i actually write to is exactly the same as the one where i allocated the data-array.
You didn't allocate anything. char *data = " "; shouldn't even compile in C++. You are assigning a constant string to a non-constant.
char byte = 0;
inputfilestream.read(&byte, 1);
*data = byte; // here i get the segfault
data++; // << How many times?
No problem
#include <stdio.h>
int main(int argc, char **argv)
{
char *data = "Yello"; // or char data[] = "Yello";
*data = 'H';
puts(data); // Hello
}

Why is main() argument argv of type char*[] rather than const char*[]?

When I wrote the following code and executed it, the compiler said
deprecated conversion from string constant to char*
int main()
{
char *p;
p=new char[5];
p="how are you";
cout<< p;
return 0;
}
It means that I should have written const char *.
But when we pass arguments into main using char* argv[] we don't write const char* argv[].
Why?
Because ... argv[] isn't const. And it certainly isn't a (static) string literal since it's being created at runtime.
You're declaring a char * pointer then assigning a string literal to it, which is by definition constant; the actual data is in read-only memory.
int main(int argc, char **argv) {
// Yes, I know I'm not checking anything - just a demo
argv[1][0] = 'f';
std::cout << argv[1] << std::endl;
}
Input:
g++ -o test test.cc
./test hoo
Output:
foo
This is not a comment on why you'd want to change argv, but it certainly is possible.
Historical reasons. Changing the signature of main() would break too much existing code. And it is possible that some implementations allow you to change the parameters to main from your code. However code like this:
char * p = "helllo";
* p = 'x';
is always illegal, because you are not allowed to mess with string literals like that, so the pointer should be to a const char.
why is it required for char* to be constant while assigning it to a string
Because such literal strings (like "hi", "hello what's going on", etc), are stored in the read-only segment of your exe. As such, the pointers that point to them need to point to constant characters (eg, can't change them).
You are assigning a string constant (const char*) to a pointer to a non-constant string (char *p). This would allow you to modify the string constant, e.g. by doing p[0] = 'n'.
Anyway, why don't you use std::string instead ? (you seem to be using C++).
If you look at execution functions like execve, you will see that they actually don't accept const char* as parameters, but do indeed require char*, therefore you can't use a string constant to invoke main.