In my application, I create a char* like this:
class sample
{
public:
char *thread;
};
sample::sample()
{
thread = new char[10];
}
sample::~sample()
{
delete []thread;
}
Am I doing the right thing in the code?
If you have [] after your new, you need [] after your delete. Your code looks correct.
List of points to be noted:
1) You need to allocate room for n characters, where n is the number of characters in the string, plus the room for the trailing null byte.
2) You then changed the thread to point to a different string. So you have to use delete[] function for the variable you are created using new[].
But why are you fooling around with new and delete for character data? Why not just use std::string, instead of 'C' functions? It's amazing why so many don't do the easiest thing:
#include <cstdio>
#include <string>
int countWords(const char *p);
int main(int argc, char *argv[])
{
std::string pString = "The Quick Brown Fox!";
int numWords1 = countWords(pString.c_str());
printf("\n\n%d words are in the string %s", numWords1, pString.c_str());
int numWords2 = countWords(argv[1]);
printf("\n%d words are in the string %s", numWords2, argv[1]);
}
No need for new[], delete[], strcpy(), etc.
Use strlen(). Better yet, don't use char* and use std::string for string data.
It's "right"*, but it's very wrong.
You should not use new[], but instead use std::vector<char> or std::string. Even if you weren't doing that, you need to respect the rule of three, or your class is broken.
*Assuming you meant new char[10]. Also, more orthodox is delete[] thread.
Related
I am new to C++ and paranoid of memory leaks. I'll strip my code down to just the important bits:
If I have a function like this:
char * myString = "Discombobulate";
char * ToUppercase()
{
int length = strlen(myString);
char * duplicateString = new char [length];
strcpy(duplicateString, myString);
//char arithmetic to turn every letter in duplicateString to uppercase
return duplicateString;
}
Obviously, I need to perform a delete[] to avoid memory leaks. Now what I wanted to know is if I can do the delete in main(), like so:
int main () {
char * result = Upper();
std::cout << result << std::endl;
delete[] result;
}
Will this work properly? Is there any catch to doing it like this?
Now what I wanted to know is if I can do the delete in main()
Yes, you can and you should.
BTW1: Think about using std::string, std::vector, smart pointers, to avoid such kind of manual memory management, since it's c++.
BTW2:
char * duplicateString = new char [length];
should be
char * duplicateString = new char [length + 1];
The last position will be used for the terminating null character '\0'.
Will this work properly?
Yes. As long as it is a valid pointer, you could delete it outside of the function that called new. Should you? Well...
Is there any catch to doing it like this?
Yes. It's bad practice. You're allocating resources in a function and expecting the caller to clean them up. It goes against RAII, as people in the comments have explained. Along with the advice to use std::string (do use it), you can use std::unique_ptr and friends instead of raw pointers.
YEs you can delete it the way you have... By the way, you can also assign memory for the pointer and pass that as a parameter to the function and delete it after it returns from the function.
char * duplicateString = new char [length + 1];
ToUppercase(char* duplicateString );
if( duplicateString ){ delete []duplicateString ; duplicateString = NULL;}
I'm reading the 3rd edition of The C++ Programming Language by Bjarne Stroustrup and attempting to complete all the exercises. I'm not sure how to approach exercise 13 from section 6.6, so I thought I'd turn to Stack Overflow for some insight. Here's the description of the problem:
Write a function cat() that takes two C-style string arguments and
returns a single string that is the concatenation of the arguments.
Use new to find store for the result.
Here's my code thus far, with question marks where I'm not sure what to do:
? cat(char first[], char second[])
{
char current = '';
int i = 0;
while (current != '\0')
{
current = first[i];
// somehow append current to whatever will eventually be returned
i++;
}
current = '';
i = 0;
while (current != '\0')
{
current = second[i];
// somehow append current to whatever will eventually be returned
i++;
}
return ?
}
int main(int argc, char* argv[])
{
char first[] = "Hello, ";
char second[] = "World!";
? = cat(first, second);
return 0;
}
And here are my questions:
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
Related to the previous question, what should I return from cat()? I assume it will need to be a pointer if I must use new. But a pointer to what?
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
The latter; the method takes C-style strings and nothing in the text suggests that it should return anything else. The prototype of the function should thus be char* cat(char const*, char const*). Of course this is not how you’d normally write functions; manual memory management is completely taboo in modern C++ because it’s so error-prone.
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
In this exercise, yes. In the real world, no: like I said above, this is completely taboo. In reality you would return a std::string and not allocate memory using new. If you find yourself manually allocating memory (and assuming it’s for good reason), you’d put that memory not in a raw pointer but a smart pointer – std::unique_ptr or std::shared_ptr.
In a "real" program, yes, you would use std::string. It sounds like this example wants you to use a C string instead.
So maybe something like this:
char * cat(char first[], char second[])
{
char *result = new char[strlen(first) + strlen(second) + 1];
...
Q: How do you "append"?
A: Just write everything in "first" to "result".
As soon as you're done, then continue by writing everything in "second" to result (starting where you left off). When you're done, make sure to append '\0' at the end.
You are supposed to return a C style string, so you can't use std::string (or at least, that's not "in the spirit of the question"). Yes, you should use new to make a C-style string.
You should return the C-style string you generated... So, the pointer to the first character of your newly created string.
Correct, you should delete the result at the end. I expect it may be ignored, as in this particular case, it probably doesn't matter that much - but for completeness/correctness, you should.
Here's some old code I dug up from a project of mine a while back:
char* mergeChar(char* text1, char* text2){
//Find the length of the first text
int alen = 0;
while(text1[alen] != '\0')
alen++;
//Find the length of the second text
int blen = 0;
while(text2[blen] != '\0')
blen++;
//Copy the first text
char* newchar = new char[alen + blen + 1];
for(int a = 0; a < alen; a++){
newchar[a] = text1[a];
}
//Copy the second text
for(int b = 0; b < blen; b++)
newchar[alen + b] = text2[b];
//Null terminate!
newchar[alen + blen] = '\0';
return newchar;
}
Generally, in a 'real' program, you'll be expected to use std::string, though. Make sure you delete[] newchar later!
What the exercise means is to use new in order to allocate memory. "Find store" is phrased weirdly, but in fact that's what it does. You tell it how much store you need, it finds an available block of memory that you can use, and returns its address.
It doesn't look like the exercise wants you to use std::string. It sounds like you need to return a char*. So the function prototype should be:
char* cat(const char first[], const char second[]);
Note the const specifier. It's important so that you'll be able to pass string literals as arguments.
So without giving the code out straight away, what you need to do is determine how big the resulting char* string should be, allocate the required amount using new, copy the two source strings into the newly allocated space, and return it.
Note that you normally don't do this kind of memory management manually in C++ (you use std::string instead), but it's still important to know about it, which is why the reason for this exercise.
It seems like you need to use new to allocate memory for a string, and then return the pointer. Therefore the return type of cat would be `char*.
You could do do something like this:
int n = 0;
int k = 0;
//also can use strlen
while( first[n] != '\0' )
n ++ ;
while( second[k] != '\0' )
k ++ ;
//now, the allocation
char* joint = new char[n+k+1]; //+1 for a '\0'
//and for example memcpy for joining
memcpy(joint, first, n );
memcpy(joint+n, second, k+1); //also copying the null
return joint;
It is telling you to do this the C way pretty much:
#include <cstring>
char *cat (const char *s1, const char *s2)
{
// Learn to explore your library a bit, and
// you'll see that there is no need for a loop
// to determine the lengths. Anything C string
// related is in <cstring>.
//
size_t len_s1 = std::strlen(s1);
size_t len_s2 = std::strlen(s2);
char *dst;
// You have the lengths.
// Now use `new` to allocate storage for dst.
/*
* There's a faster way to copy C strings
* than looping, especially when you
* know the lengths...
*
* Use a reference to determine what functions
* in <cstring> COPY values.
* Add code before the return statement to
* do this, and you will have your answer.
*
* Note: remember that C strings are zero
* terminated!
*/
return dst;
}
Don't forget to use the correct operator when you go to free the memory allocated. Otherwise you'll have a memory leak.
Happy coding! :-)
I wanna do something like:
string result;
char* a[100];
a[0]=result;
it seems that result.c_str() has to be const char*. Is there any way to do this?
You can take the address of the first character in the string.
a[0] = &result[0];
This is guaranteed to work in C++11. (The internal string representation must be contiguous and null-terminated like a C-style string)
In C++03 these guarantees do not exist, but all common implementations will work.
string result;
char a[100] = {0};
strncpy(a, result.c_str(), sizeof(a) - 1);
There is a member function (method) called "copy" to have this done.
but you need create the buffer first.
like this
string result;
char* a[100];
a[0] = new char[result.length() + 1];
result.copy(a[0], result.length(), 0);
a[0][result.length()] = '\0';
(references: http://www.cplusplus.com/reference/string/basic_string/copy/ )
by the way, I wonder if you means
string result;
char a[100];
You can do:
char a[100];
::strncpy(a, result.c_str(), 100);
Be careful of null termination.
The old fashioned way:
#include <string.h>
a[0] = strdup(result.c_str()); // allocates memory for a new string and copies it over
[...]
free(a[0]); // don't forget this or you leak memory!
If you really, truly can't avoid doing this, you shouldn't throw away all that C++ offers, and descend to using raw arrays and horrible functions like strncpy.
One reasonable possibility would be to copy the data from the string to a vector:
char const *temp = result.c_str();
std::vector<char> a(temp, temp+result.size()+1);
You can usually leave the data in the string though -- if you need a non-const pointer to the string's data, you can use &result[0].
My problem is that I don't know how to convert int value to char array char* m_value. I tried to use itoa but it doesn't work. itoa(m_val, m_wartosc, 10); Maybe there is some other function to do this ?
Main.cpp
int main(int argc, char *argv[])
{
LargeNumber l1;
LargeNumber l3(172839); //how to convert this int to char*
return 0;
}
LargeNumber.h
class LargeNumber{
public:
LargeNumber()
{
m_array = "0"; //zero for no arg.
}
LargeNumber(int val):m_val(val)
{
itoa(m_val, m_array, 10); //doesn't work
//sprintf(m_array, "%d", m_val);
}
LargeNumber(const LargeNumber& p):m_array(p.m_array)
{ } //copy constructor
~LargeNumber(){
delete []m_array; //for object with new
}
public: //should be private
int m_val;
char* m_array;
};
The simple answer is: don't. For two reasons:
As you can see from all the (wrong) other answers, memory management is tricky and bug-prone.
I can't see how storing your value in base-10, in an ASCII string, could possibly be useful. (Compared to, say, a base-232 representation.)
But if you really must store it this way, you will need to allocate the relevant amount of memory, use snprintf to convert (itoa is a non-standard function), and remember to free the memory at the correct time(s) (you will have to read and understand about the Rule of Three).
I would strongly recommend using a std::string instead of a raw C-style array, because it will at least deal with its own memory management, and you will then be able to populate it with a std::stringstream.
The second argument of itoa() needs to be an array in memory large enough to store the null-terminated string. An example:
int number = 172839;
char buffer[10];
itoa(number,buffer,10);
LargeNumber(int val):m_val(val)
{
std::stringstream stream;
stream << val;
m_array = new char[stream.str().size()];
strcpy(m_array, stream.str().c_str());
}
You have to first allocate the array with
m_array = new char[20]
in constructor before calling iota.
the iota doesnt allocate memory.
I would like to perform the above mentioned operation, however I would like to make sure that the char array is exactly the same size with the string at hand.
So the real question is, how can I make an array with a size that is going to be determined in the run time?
allocating memory on the free store, and copying the string in one go:
std::string s("abcdef");
...
char* chars=strdup(s.c_str());
You need to free the memory manually, of course. Documentation e.g. on the man page. As #Loki mentions: freeing this memory is done through free(chars), not through delete. Also, you need to include the <cstring> header.
If you want to stay in the c++ world, use a vector; it can be created with two iterators to copy it's data from, and will allocate on the heap, and will cleanup by itself. Isn't that a treat?
std::vector<char> vec( s.begin(), s.end() );
You can create an array of size known at runtime with the "new" operator:
char* res = new char[str.size()+1];
strncpy(res, str.c_str(), str.size()+1);
std::string s = "hello";
char* c = new char[s.length() + 1]; // '+ 1' is for trailing NULL character.
strcpy(c, s.c_str());
#include <string>
int main(int argc, char *argv[])
{
std::string random_data("This is a string");
char *array=new char[random_data.size()+1];
// do stuff
delete[] array;
return 0;
}
Try:
char* res = new char[str.size()+1](); // Note the () makes sure it is '0' filled.
std::copy(str.begin(), str.end(), res); // Don't need to copy the '\0' as underlying
// array already has '\0' at the end position.
...
delete [] res; // Must not forget to delete.
Or: (preferably)
std::vector<char> res(str.begin(), str.end());
Or: If all you want to do is call a C-unction:
str.c_str()
Use strlen() to find the length of the string, then malloc() a char array of that size.