I'm trying to make my own string class, and I'm trying to create the constructor. So far I'm having a little struggle.
I have my function prototypes defined in a header file and the variable buffer defined in the header file like this char *buffer;, in a new cpp file I'm trying to define the constructor like this:
mystring::mystring(const char *s)
{
int counter = strlen(s)+1;
*buffer = generate_c_array(counter);
}
char * mystring::generate_c_array(int size)
{
return new char[size];
}
I'm basically trying to make it such that buffer is a char array of size s+1 and contains the contents of s followed by a null terminator. Though, this is causing my program to crash.
I'm not sure how to assign buffer correctly, does this look correct?
You can simply write your code
mystring::mystring(const char *s)
{
sz = strlen(s) // sz- another data member, holds size
buffer = new char[sz + 1];
strcpy(buffer, s); // assuming s is null-terminated
}
The for loop and counter were not necessary, in fact
You assign to the specific character in the buffer, not to the variable buffer. Change to:
buffer = generate_c_array(counter);
Other than that, strdup will do the same job for you, but you will have to deallocate with free(). In current code you actually don't really copy, you will have to do strcpy(buffer, s) unless using the strdup mentioned earlier.
Why are you looping over length of the string s?
If you need length of the string use it directly:
std::size_t length = strlen(s);
buffer = generate_c_array(length + 1);
// Copy your string:
memcpy(buffer, s, length)
// Add the terminator character:
buffer[length] = '\0';
You haven't copied the content..
If you want to assign a pointer ( which is what new give you ) to another pointer, you don't need *.
strncpy do the copying for you.
mystring::mystring(const char *s)
{
int counter = strlen(s)+1;
char* buffer = generate_c_array(counter);
strncpy(buffer, s, counter);
}
char * mystring::generate_c_array(int size)
{
return new char[size];
}
Related
char string2char(String ipString){
char opChar[ipString.length() + 1];
memset(opChar, 0, ipString.length() + 1);
for (int i = 0; i < ipString.length(); i++)
opChar[i] = ipString.charAt(i);
}
Called as char charssId[AP_NameString.length()+1] = string2char(AP_NameString);
What is the right way to call the function? Want to change String ssid to char ssid, to make it compatible with esp8266 library.
char charssId[AP_NameString.length()+1] = string2char(AP_NameString);
This line is will not work. Because char charssId[AP_NameString.length()+1] this means you are declaring an array of certain size and at the same time replacing it with the returned array from the method.
You can do as follows,
char* string2char(String ipString){ // make it to return pointer not a single char
char* opChar = new char[ipString.length() + 1]; // local array should not be returned as it will be destroyed outside of the scope of this function. So create it with new operator.
memset(opChar, 0, ipString.length() + 1);
for (int i = 0; i < ipString.length(); i++)
opChar[i] = ipString.charAt(i);
return opChar; //Add this return statement.
}
// Now call this as below,
char* charssId = string2char(AP_NameString); // make the variable as pointer so that it can hold an array address.
// use it as a char array.
delete[] charssId; // Remember to delete it after finished using it.
There are many problems with your code.
Your function is declared as returning a single char, not an array of chars. And it is missing an actual return statement. But even if it weren't, you would be returning a local array that goes out of scope when the function exits, leaving the caller with a dangling pointer to invalid data.
You are declaring the opChar array in a non-standard way known as a "variable-length array". VLAs are a compiler-specific extension, and thus not portable. You need to dynamically allocate the array using new[] instead.
Try this:
char* string2char(const String &ipString){
char *opChar = new char[ipString.length() + 1];
/*
for (int i = 0; i < ipString.length(); i++)
opChar[i] = ipString.charAt(i);
*/
ipString.toCharArray(opChar, ipString.length());
opChar[ipString.length()] = '\0';
return opChar;
}
char *charssId = string2char(AP_NameString);
// use charssId as needed...
delete[] charssId;
A safer option is to use std::string instead:
std::string string2char(const String &ipString){
std::string opChar;
opChar.resize(ipString.length());
/*
for (int i = 0; i < ipString.length(); i++)
opChar[i] = ipString.charAt(i);
*/
ipString.toCharArray(opChar, ipString.length());
return opChar;
// alternatively:
// return std::string(ipString.c_str(), ipString.length());
}
std::string charssId = string2char(AP_NameString);
// use charssId.c_str() as needed...
But a conversion is actually not needed at all:
const char *charssId = AP_NameString.c_str();
// use charssId as needed...
You are returning pointer to first character of the array from the function and assigning it to the array, this is not possible. Learn more here.
To make it work you've got to assign a pointer returned from function to pointer variable -- like following:
char* charssId = string2char(AP_NameString);
// Do stuff
delete [] charssId;
and then access it like regular array:
charssId[index]
Thats already explained in answer above, so there are several approaches which handles this task easier.
First is toCharArray() method of string class
char opChar[ipString.length() + 1];
ipString.toCharArray(opChar, ipString.length());
// Do stuff
delete [] opChar;
Second is c_str() method of class string (string returned is const)
const char *unmodificable = ipString.c_str();
I'm doing an exercise in which I have to copy a c-style string into memory allocated on free store. I am required to do it without using subscripting and relying solely on pointer arithmetic. I wrote the following function-
char* str_dup(const char* s)
{
// count no. of elements
int i = 0;
const char* q = s;
while (*q) { ++i; ++q; }
//create an array +1 for terminating 0
char* scpy = new char[i + 1];
//copy elements to new array
while (*s)
{
*scpy = *s;
++s;
++scpy;
}
*scpy = 0;
return scpy;
}
The function is returning random characters. But if I change it into this-
char* str_dup(const char* s)
{
// count no. of elements
int i = 0;
const char* q = s;
while (*q) { ++i; ++q; }
//create an array +1 for terminating 0
char* scpyx = new char[i + 1];
char* scpy = scpyx;
//copy elements to new array
while (*s)
{
*scpy = *s;
++s;
++scpy;
}
*scpy = 0;
return scpyx;
}
it works. Can someone explain me why first code is not working and second is working?
The first code is not working since you return the final value of scpy, which at that point points at the terminating NUL character, and not the start of the string.
One solution is to do as you did, and save a copy of the original pointer to have something to return.
You should really use strlen() and memcpy(), they make this easier but perhaps they're off-limits to you.
I wrote a function which receives as a parameter a char pointer,then builds a new dynamic allocated char array that contains that parameter char.Then,it returns the new char array.
This is the function:
char* read_string(char *pstr)
{
char *str;
str = new char[strlen(pstr)];//allocate memory for the new char
str[strlen(pstr)] = '\0';
for(unsigned i=0;i<strlen(pstr);i++)//build the new char
str[i]=pstr[i];
return str;//then return it
}
In main I have:
int main()
{
char *Pchar = read_string("Test");
cout<<Pchar;// Outputs "Test"
delete [] Pchar;//"Program received signal SIGTRAP, Trace/breakpoint trap." error
}
I declare a char pointer in main and then make it point to the char array that is returned from the read_string function.It outputs what I want but if I want to free the memory it gives me runtime error.How can I free up the memory if I don't need to use Pchar anymore?
EDIT:Thank you all for your very informative answers.I have successfully resolved the problem.
You need to allocate more memory to have space for EOS character:
str = new char[strlen(pstr)+1];
Your specific problem is an off-by-one error:
str = new char[strlen(pstr) + 1];
// ^^^^ need one more for the '\0'
str[strlen(pstr)] = '\0';
Generally, since this is C++ and not C, it would be better to return a smart pointer so the caller knows what the ownership semantics of the pointer are:
std::unique_ptr<char[]> read_string(char *pstr)
{
std::unique_ptr<char[]> str(new char[strlen(pstr) + 1]);
// rest as before
return str;
}
It seems that the error occurs due to incorrect length of the allocated string.
You have to use the following record to allocate the string
str = new char[strlen(pstr) + 1];//allocate memory for the new char
str[strlen(pstr)] = '\0';
The function can look the following way
char* read_string( const char *pstr )
{
char *str;
size_t n = strlen( pstr );
str = new char[n + 1];//allocate memory for the new char
strcpy( str, pstr );
return str;
}
Right off the bat, I'm required to use dynamically allocated character arrays for my assignment, so do NOT suggest I just use strings. I need to create a method that accepts a character array as an argument, and inserts that character into a char* using strcpy. How do I do this without first initializing the char*?
Here is my code so far:
char* char_array;
char test_array[] = {'t','e','s','t','\0'};
strcpy(char_array, test_array);
Your char_array is just an unitialized pointer. You need to dynamically allocate memory for it and then carry out strcpy.
char* char_array = new char[6];
char test_array[] = {'t','e','s','t','\0'};
strcpy(char_array, test_array);
Or as suggested by Joachim you can use strdup() to duplicate a string - it will allocate the memory and copy the string into it.
In both cases, don't forget to free() (or delete[]) the resulting memory once you're done with it.
You can't do that unless you actually allocate a chunk of memory for char_array through malloc or new.
int length = 6;
char* char_array = (char*) malloc(sizeof(char) * length);
or
char* char_array = new char[6];
char * char_array = NULL;
void yourFunc(char your_array[]) {
if (NULL != char_array) {
free(char_array);
char_array = NULL;
}
char_array = (char *)malloc(sizeof(char) * strlen(your_array));
strcpy(char_array, your_array);
}
you stated you need a method/function that accepts a char[]/char *
you have stated your constraints ...
this does seem to be low level for instructional purpose
I assuming null terminated character array and valid source character array
//function accepts character array
char * charseqduplicate(char * s)
{
//low level c
const int len = strlen(s) + 1;;
char * copy = new char[len];
strcpy(copy, s);
//remember to delete or use something like unique_ptr
return copy;
}
void letsdothis()
{
//low level c
char test[] = {'y','e','s',char(0)};
char * dup = charseqduplicate(test);
cout << dup;
delete [] dup;
}
Can anyone help me, why I'm getting an error message while trying to free the allocated memory: Heap corruption detected. CTR detected the application wrote the memory after end of heap buffer.
char *ff (char *s){
char *s1 = new char [strlen(s)];
strcpy(s1, s);
return s1;
}
int _tmain(int argc, _TCHAR* argv[])
{
char *s = new char [5];
strcpy(s, "hello");
char *s2 = ff(s);
delete []s; // This works normal
delete []s2; // But I get an error on that line
return 0;
}
char *s = new char [5];
strcpy(s, "hello");
Causes Undefined behavior(UB).
You are writing beyond the bounds of allocated memery. You allocated enough memory for 5 characters but your string has 6 characters including the \0.
Once your program has caused this UB, all bets are off and any behavior is possible.
You need:
char *s = new char [strlen("hello") + 1];
In fact the ideal solution is to use std::string and not char *. These are precisley the mistakes which std::string avoids. And there is no real need of using char * instead of std::string in your example.
With std::string:
You don't need to new anything
You don't need to delete anything &
You can do everything with std::string, that you do with char *.
new char [strlen(s)]; does not count the closing \0 character, so your buffer is too short by one character.
strcpy includes the null terminator; strlen does not. Write:
char *s1 = new char [strlen(s) + 1];
From man strcpy(3):
The strcpy() function copies the string pointed to by src,
including the terminating null byte ('\0'), to the buffer pointed to
by dest.
So you need to reserve 6 bytes 5 for the string and 1 for the NULL byte
char *s = new char [6];
strcpy(s, "hello");
All answers so far have addressed either the first or the second allocation. To sum up, there are two changes you must make:
char *s1 = new char [strlen(s) + 1];
...
char *s = new char [5 + 1];
In both cases, you must allocate enough space for the string plus one byte for the terminating '\0'.
As others already pointed out, with c++ it's easier and safer to use std::string. No fuss with allocation and release of memory or paying attention to '\0' bytes:
std::string ff (const std::string &s){
std::string s1(s);
// do something else with s1
return s1;
}
int main(int argc, char* argv[])
{
std::string s("hello");
std::string s2 = ff(s);
return 0;
}
and if it's just copying the string:
std::string s("hello");
std::string s2(s);
You need to specify char *s1 = new char [strlen(s) + 1]; to make room for the '\0' which terminates the string.
You've corrupted s2 pointer by
strcpy(s, "hello");
Because s has size 5, while you've missed that strcpy includes string terminator.
Your initial string s is only five characters long so can't be null terminated. "hello" will be copied by strcpy including the null-terminator but you'll have overrun the buffer. The strlen needs it to be null terminated so if the null's not there, you'll have problems. Try changing this line:
char *s = new char [6];
Better still, prefer std::string to C style string functions - they're just as efficient and a lot safer and easier to use. Also, try to avoid new and delete unless you really have to use them. The problems you're getting are very common and can easily be avoided.