As part of a small program i need to convert a string to a char array. I want to use the strncpy_s() method but I keep getting an assertation saying that the "buffer is too small".
This is what my code looks like:
char* ostr = new char[sizeof(str)+1];
strncpy_s(ostr, sizeof(ostr), str.c_str(), sizeof(ostr));
Hope someone can help me.
The variable str is, it seems, a std::string object. The size of the object is the size of its member variables, which for std::string commonly is a pointer (to the actual string) and variable for the length of the string.
If you want to get the length of the wrapped string you need to use the length function.
Furthermore, there is another problem with your call to strncpy_s: You do sizeof(ostr), which is the size of the pointer, not the size of the memory it points to.
Lastly, if you want to pass a pointer to the string to a C function, then either use str.c_str() directly in the call. Or if the C function needs to modify the string (but not reallocate it) then use e.g. str.data() or &str[0].
If the C function needs to reallocate the data then you can't use new[] to allocate it. You need to use malloc (or possibly strdup if your system have it).
Related
I am looking for something which give me size which taken by str character pointer.
int main()
{
char * str = (char *) malloc(sizeof(char) * 100);
int size = 0;
size = /* library function or anything use to find size */
printf("Total size of str array - %d\n", size);
}
I want prove that give memory is 100 bytes.
Is any one have any idea about this ?
A raw pointer only knows it points to a single element of it's type. If that thing it points to happens to be part of an array, the pointer doesn't know and there's no way to get that information from it.
You want to instead use types that do know their size, like for example; std::string, std::array or std::vector.
The C and C++ standards do not provide a way to get, from an address, the amount of memory that was requested in the call to malloc that returned that address.
Some C or C++ implementations provide a way to get the amount of memory that was provided at the given address, such as malloc_size. The amount provided may be greater than the amount that was requested.
If the memory contains a string, which is an array of characters terminated by a null character, then you can determine the length of the string by counting characters up to the null character. This function is provided by the standard strlen function. This length is different from the space allocated unless, of course, the string happens to fill the space.
There is no (good, standard, portable) way to tell from a pointer value alone whether it's the first element of an array or not, nor how many elements follow it. That information has to be tracked separately.
If you're writing in C++, don't do your own memory management if you can help it. Use a standard container type like std::vector or std::map (or std::string for text). If you must do your own memory management, use the new and delete operators instead of the *alloc and free library functions, and wrap a class around those operations that also keeps track of how many elements have been allocated (which, like std::vector and std::map, is returned via a read-only size() method).
I want to use the gets() function for std::string str. But I get an error:
invalid conversion from 'const char*' to 'char*'
The strlen() function on the other hand doesn't give any error when I write
int len = strlen(str.c_str())
but gets(NUM.c_str()) gives the error.
Any suggestions? I need to use std::string and gets() as my character size is unknown.
c_str() returns a const pointer to the string contents, so you cannot use that to modify the string.
Even if you did circumvent that (which you really shouldn't), it would be impossible to change the size of the string (as you're trying to do), since that's managed by the string object. The best you could do is write over memory that may not be owned by the string, causing crashes or other undefined behaviour.
Even if you did have a suitable array to write to, don't use gets. There is no way to prevent it from overflowing the buffer, if the input line is too long. It's been deprecated in C since at least 1999.
Any suggestions?
std::getline(std::cin, NUM);
Where to begin...
(1) Firstly, gets expects a char*, but std::string::c_str() returns const char*. The purpose of std::string::c_str() is merely to provide a C-string representation of the string data - it is NOT meant to provide a writable buffer. The function gets needs a writable character buffer.
(2) Secondly, you can use std::string as a writable character buffer using the [] operator, by saying:
std::string s(100); // create a buffer of size 100
char* buf = &s[0];
This is guaranteed to work properly in C++11, however in earlier versions of C++, it is not necessarily guaranteed that std::string provide a contiguous memory buffer. (Although, in practice, it almost always does.) Still, if you want a buffer, it's better to use std::vector<char>.
(3) Finally, don't use gets, EVER. It's ridiculously dangerous and makes your program prone to buffer overflow and shellcode injection attacks. The problem is that gets doesn't include a size parameter, so in practice the program will read any arbitrary amount of bytes into the buffer, potentially overflowing the buffer and resulting in undefined behavior. This has historically been an attack vector for many hackers, especially when gets is used with a stack array. The function fgets should be used instead in C, because it lets you specify a maximum read size parameter. In C++, it's better to use std::getline, because it works directly with an std::string object and therefore you don't need to worry about the size of the buffer.
I want to use gets() function
gets() is C. When possible it is better using C++ features
Instead try getline like this:-
std::getline(std::cin, NUM);
And as Jrok mentioned in the comments:-
Make the world a better place - don't use gets
In addition to the problems with trying to use gets in the first place, you cannot use it on a buffer returned from c_str() as the buffer is a const char* (which points to the string buffer held by the std::string object. If you insist on using gets(), you would need to create your own buffer to read into:
char buffer[1024] = {0}; // temporary buffer
gets(buffer); // read from stdin into the buffer
std::string s(buffer); // store the contents of the buffer in a std::string
For an explanation and example of why you should never use gets: http://www.gidnetwork.com/b-56.html
A much better approach is to
std::string s; // the std::string you are using
std::getline(std::cin, s); // read the line
I am new to C++, and haven't quite grasped all the concepts yet, so i am perplexed at why this function does not work. I am currently not at home, so i cannot post the compiler error just yet, i will do it as soon as i get home.
Here is the function.
const char * ConvertToChar(std::string input1, std::string input2) {
// Create a string that you want converted
std::stringstream ss;
// Streams the two strings together
ss << input1 << input2;
// outputs it into a string
std::string msg = ss.str();
//Creating the character the string will go in; be sure it is large enough so you don't overflow the array
cont char * cstr[80];
//Copies the string into the char array. Thus allowing it to be used elsewhere.
strcpy(cstr, msg.c_str());
return * cstr;
}
It is made to concatenate and convert two strings together to return a const char *. That is because the function i want to use it with requires a const char pointer to be passed through.
The code returns a pointer to a local (stack) variable. When the caller gets this pointer that local variable doesn't exist any more. This is often called dangling reference.
If you want to convert std::string to a c-style string use std::string::c_str().
So, to concatenate two strings and get a c-style string do:
std::string input1 = ...;
std::string input2 = ...;
// concatenate
std::string s = input1 + input2;
// get a c-style string
char const* cstr = s.c_str();
// cstr becomes invalid when s is changed or destroyed
Without knowing what the error is, it's hard to say, but this
line:
const char* cstr[80];
seems wrong: it creates an array of 80 pointers; when it
implicitly converts to a pointer, the type will be char
const**, which should give an error when it is passed as an
argument to strcpy, and the dereference in the return
statement is the same as if you wrote cstr[0], and returns the
first pointer in the array—since the contents of the array
have never been initialized, this is undefined behavior.
Before you go any further, you have to define what the function
should return—not only its type, but where the pointed to
memory will reside. There are three possible solutions to this:
Use a local static for the buffer:
This solution was
frequently used in early C, and is still present in a number of
functions in the C library. It has two major defects: 1)
successive calls will overwrite the results, so the client code
must make its own copy before calling the function again, and 2)
it isn't thread safe. (The second issue can be avoided by using
thread local storage.) In cases like yours, it also has the
problem that the buffer must be big enough for the data, which
probably requires dynamic allocation, which adds to the
complexity.
Return a pointer to dynamically allocated memory:
This works well in theory, but requires the client code to free
the memory. This must be rigorously documented, and is
extremely error prone.
Require the client code to provide the buffer:
This is probably the best solution in modern code, but it does
mean that you need extra parameters for the address and the
length of the buffer.
In addition to this: there's no need to use std::ostringstream
if all you're doing is concatenating; just add the two strings.
Whatever solution you use, verify that the results will fit.
As I understood the correct programming style tells that if you want to get string (char []) from another function is best to create char * by caller and pass it to string formating function together with created string length. In my case string formating function is "getss".
void getss(char *ss, int& l)
{
sprintf (ss,"aaaaaaaaaa%d",1);
l=11;
}
int _tmain(int argc, _TCHAR* argv[])
{
char *f = new char [1];
int l =0;
getss(f,l);
cout<<f;
char d[50] ;
cin>> d;
return 0;
}
"getss" formats string and returns it to ss*. I thought that getss is not allowed to got outside string length that was created by caller. By my understanding callers tells length by variable "l" and "getcc" returns back length in case buffer is not filled comleatly but it is not allowed go outside array range defined by caller.
But reality told me that really it is not so important what size of buffer was created by caller. It is ok, if you create size of 1, and getss fills with 11 characters long. In output I will get all characters that "getss" has filled.
So what is reason to pass length variable - you will always get string that is zero terminated and you will find the end according that.
What is the reason to create buffer with specified length if getss can expand it?
How it is done in real world - to get string from another function?
Actually, the caller is the one that has allocated the buffer and knows the maximum size of the string that can fit inside. It passes that size to the function, and the function has to use it to avoid overflowing the passed buffer.
In your example, it means calling snprintf() rather than sprintf():
void getss(char *ss, int& l)
{
l = snprintf(ss, l, "aaaaaaaaaa%d", 1);
}
In C++, of course, you only have to return an instance of std::string, so that's mostly a C paradigm. Since C does not support references, the function usually returns the length of the string:
int getss(char *buffer, size_t bufsize)
{
return snprintf(buffer, bufsize, "aaaaaaaaaa%d", 1);
}
You were only lucky. Sprintf() can't expand the (statically allocated) storage, and unless you pass in a char array of at least length + 1 elements, expect your program to crash.
In this case you are simply lucky that there is no "important" other data after the "char*" in memory.
The C runtime does not always detect these kinds of violations reliably.
Nonetheless, your are messing up the memory here and your program is prone to crash any time.
Apart from that, using raw "char*" pointers is really a thing you should not do any more in "modern" C++ code.
Use STL classes (std::string, std::wstring) instead. That way you do not have to bother about memory issues like this.
In real world in C++ is better to use std::string objects and std::stringstream
char *f = new char [1];
sprintf (ss,"aaaaaaaaaa%d",1);
Hello, buffer overflow! Use snprintf instead of sprintf in C and use C++ features in C++.
By my understanding callers tells length by variable "l" and "getcc" returns back length in case buffer is not filled comleatly but it is not allowed go outside array range defined by caller.
This is spot on!
But reality told me that really it is not so important what size of buffer was created by caller. It is ok, if you create size of 1, and getss fills with 11 characters long. In output I will get all characters that "getss" has filled.
This is absolutely wrong: you invoked undefined behavior, and did not get a crash. A memory checker such as valgrind would report this behavior as an error.
So what is reason to pass length variable.
The length is there to avoid this kind of undefined behavior. I understand that this is rather frustrating when you do not know the length of the string being returned, but this is the only safe way of doing it that does not create questions of string ownership.
One alternative is to allocate the return value dynamically. This lets you return strings of arbitrary length, but the caller is now responsible for freeing the returned value. This is not very intuitive to the reader, because malloc and free happen in different places.
The answer in C++ is quite different, and it is a lot better: you use std::string, a class from the standard library that represents strings of arbitrary length. Objects of this class manage the memory allocated for the string, eliminating the need of calling free manually.
For cpp consider smart pointers in your case propably a shared_ptr, this will take care of freeing the memory, currently your program is leaking memory since, you never free the memory you allocate with new. Space allocate by new must be dealocated with delete or it will be allocated till your programm exits, this is bad, imagine your browser not freeing the memory it uses for tabs when you close them.
In the special case of strings I would recommend what OP's said, go with a String. With Cpp11 this will be moved (not copied) and you don't need to use new and have no worries with delete.
std::string myFunc() {
std::string str
//work with str
return str
}
In C++ you don't have to build a string. Just output the parts separately
std::cout << "aaaaaaaaaa" << 1;
Or, if you want to save it as a string
std::string f = "aaaaaaaaaa" + std::to_string(1);
(Event though calling to_string is a bit silly for a constant value).
how do you implement substring in C++ that returns pointer to char? (takes pointer to the first letter)
say something like char* substr(char* c, int pos, int lenght)
I use methods of the std::string class.
Edit:
say something like char* substr(char* c, int pos, int lenght)
This isn't a function that it's possible to implemement well. To create a substring, you need memory:
Same memory as original string: did you mean to overwrite the original string? Is the original string writeable?
New memory: is the caller going to invoke the delete[] operator on the pointer which it receives from your substr function (if it doesn't, there would be a memory leak)?
Global memory: you could reserve a fixed-length buffer in global memory, but that's all sorts of problems (may not be long enough, will be overwritten when someone else calls your substr).
The right way to do it is to return a std::string instance, which is what the string::substr method does, as shown in Graphics Noob's answer, because the std::string instance (unlike a char* instance) will manage the lifetime of its own memory; and if you then want a char* instance from the std::string instance, you can get that using the c_str() method.
Is this the functionality you are trying to replicate?
http://www.cplusplus.com/reference/clibrary/cstring/strstr/
str.substr(int,int).c_str()
Will return the substring as a const char* but be careful using it, the memory containing the string will be invalid at the end of the statement, so you may need to surround it with a strcpy() if you want to store the result. Or better yet just break it up into two lines:
std::string str2 = str.substr(int,int);
const char* cstr = str2.c_str();
You'll need to do a strcpy() to safely get rid of the const.
The ints refer to the parameters for the substring you're trying to get.