Allocate extra memory to the character array C++ - c++

I have this problem where I have a string and I pass it to the function as a character pointer.
void test(char * str) {
....
}
where str = "abc". Now I want to add few extra characters to the end of this string without creating a new string. I do not want to use strcat as I do not know how many characters I am adding to the end of the string and what I am adding. I was trying to work with realloc but it does not work as the str is allocated on stack.
Is there any way I can increase the size of the char array dynamically?
UPDATE :
I was asked a question which involved this in my interview. I was asked to do it without using additional space. So if I allocate memory using malloc I am technically using additional space right?
Thanks

No, especially if the string is allocated on the stack. The stack space is fixed at compile-time. You must either allocate more space initially, or allocate a new array with more space and strcpy it over.

If you are using C++ - then stick to std::string and forget the whole deal with char *.
However if you wish to use the char * for strings, then allocate a new character array and strcpy() from one string to another. Do not forget to deallocate the original char * memory to avoid memory leaks.
I was asked a question which involved this in my interview. I was asked to do it without using additional space. So if I allocate memory using malloc I am technically using additional space right?
How can you increase the length of the string without adding additional space?

You must delete the old string and allocate a new one with new with the length you want.

Sorry, no. A dynamic variable/array cannot be resized up. The problem is that another variable, or even another call frame could be immediately following the variable in question. These cannot be moved to make space as there may be pointers to these objects elsewhere in the code.

void test(string &str) {
....
str += "wibble";
}
Seems to work for C++

Rather than using realloc(not to be done on stack) or strcpy(uses extra buffer space) you may store the new values from the byte right after the input string. In the simple example below, I begin with "abcd" and add three z's at the end in the function fn.
void fn(char *str)
{
int len = strlen(str);
memset(str+len, 'z', 3);
str[len+3] = 0;
return;
}
int main()
{
char s[] = "abcd";
printf("%s\n", s);
fn(s);
printf("%s\n", s);
}
Output:
abcd
zzz
This way can be extended to adding different strings in front of original one.

Related

How to code a strcat function that works with two dynamic arrays

As we know, the strcat function concatinates one c-string onto another to make one big c-string containing two others.
My question is how to make a strcat function that works with two dynamically allocated arrays.
The desired strcat function should be able to work for any sized myStr1 and myStr2
//dynamic c-string array 1
char* myStr1 = new char [26];
strcpy(myStr1, "The dog on the farm goes ");
//dynamic c-string array 2
char* myStr2 = new char [6];
strcpy(myStr2, "bark.");
//desired function
strcat(myStr1,myStr2);
cout<<myStr1; //would output 'The dog on the farm goes bark.'
This is as far as I was able to get on my own:
//*& indicates that the dynamic c-string str1 is passed by reference
void strcat(char*& str1, char* str2)
{
int size1 = strlen(str1);
int size2 = strlen(str2);
//unknown code
//str1 = new char [size1+size2]; //Would wipe out str1's original contents
}
Thanks!
You need first to understand better how pointers work. Your code for example:
char* myStr1 = new char [25];
myStr1 = "The dog on the farm goes ";
first allocates 25 characters, then ignores the pointer to that allocated area (the technical term is "leaks it") and sets myStr1 to point to a string literal.
That code should have used strcpy instead to copy from the string literal into the allocated area. Except that the string is 25 characters so you will need to allocate space for at least 26 as one is needed for the ASCII NUL terminator (0x00).
Correct code for that part should have been:
char* myStr1 = new char [26]; // One more than the actual string length
strcpy(myStr1, "The dog on the farm goes ");
To do the concatenation of C strings the algorithm could be:
measure the lengths n1 and n2 of the two strings (with strlen)
allocate n1+n2+1 charaters for the destination buffer (+1 is needed for the C string terminator)
strcpy the first string at the start of the buffer
strcat the second string to the buffer (*)
delete[] the memory for the original string buffers if they are not needed (if this is the right thing to do or not depends on who is the "owner" of the strings... this part is tricky as the C string interface doesn't specify that).
(*) This is not the most efficient way. strcat will go through all the characters of the string to find where it ends, but you already know that the first string length is n1 and the concatenation could be done instead with strcpy too by choosing the correct start as buffer+n1. Even better instead of strcpy you could use memcpy everywhere if you know the count as strcpy will have to check each character for being the NUL terminator. Before getting into this kind of optimization however you should understand clearly how things work... only once the string concatenation code is correct and for you totally obvious you are authorized to even start thinking about optimization.
PS: Once you get all this correct and working and efficient you will appreciate how much of a simplification is to use std::string objects instead, where all this convoluted code becomes just s1+s2.
You allocate memory and make your pointers point to that memory. Then you overwrite the pointers, making them point somewhere else. The assignment of e.g. myStr1 causes the variable to point to the string literal instead of the memory you allocated. You need to copy the strings into the memory you have allocated.
Of course, that copying will lead to another problem, as you seem to forget that C-strings need an extra character for the terminator. So a C-string with 5 characters needs space for six characters.
As for your concatenation function, you need to do copying here too. Allocate enough space for both strings plus a single terminator character. Then copy the first string into the beginning of the new memory, and copy the second string into the end.
Also you need a temporary pointer variable for the memory you allocate, as you otherwise "would wipe out str1's original contents" (not strictly true, you just make str1 point somewhere else, losing the original pointer).

How to add strings?

I'm really new to C++ and I'm making a simple program
TCHAR CONFIG_NAME[32];
TCHAR CONFIG_PROCESSNAME[32];
int a = GetPrivateProfileString("Injection", "Name", "", CONFIG_DLLNAME, 32, path);
but I need to add a char* to it, because it needs the full path.
as a example, it's doing just
MyDLL.dll
but it needs to be doing
C:/folder/anotherfolder/mydog/MyDLL.dll
I tried doing
char* DLLLOC = "NULL";
sprintf(DLLLOC, "%s%s", dir, CONFIG_DLLNAME);
but it crashes
The problem is that DLLLOC hasn't had the sufficient space allocated to accommodate for your string concatenation.
A solution is to pre-allocate a large char buffer and use that instead, like below.
#define CONFIG_DLLNAME "configdllname"
int main()
{
char str[1024];
const char* dir = "dir";
sprintf(str, "%s%s", dir, CONFIG_DLLNAME);
printf(str);
}
If the strings exceeds 1024 characters, you'll run into the same problem; welcome to string operations in C. :)
Also, since you marked this is a C++ question, is there a reason you're not using std::string? This would make your life much easier.
Use
wstring DLLLOC(dir);
DLLLOC.append(CONFIG_DLLNAME);
this preserves with buffer overflow (and yes windows has a limit of 255 characters in path, so you can assert later than size is within limits)
Your char* DLLLOC only has five characters worth of space in it. (4 for the letters "NULL" and one more fore the null terminator (a zero byte that marks the end of strings in c++. You need to make sure char* DLLLOC points to an area large enough to contain the strings your putting into it.
You might try allocating the space dynamically:
// c style
char* DLLLOC = malloc(strlen(dir)+strlen(CONFIG_DLLNAME)+1);
// c++ style
char* DLLLOC = new char[strlen(dir)+strlen(CONFIG_DLLNAME)+1];
(You can use sizeof here if dir and config_DLLNAME are arrays of chars and not pointers to chars.)
Or, you can declare the space before hand:
char DLLLOC[256];
For this to work, you have to be sure the final string wont be longer that the size of the array.

good manier to get char[] from another function. Starting thinking in c/c++

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).

Why my source is changing when using strcpy in c

After using strcpy source is getting corrupted and getting correct destination. Following is my code please suggest me why my source is getting corrupted? If i keep a fixed size to second character array q[] then my source is not being changed. Why is this strange behaviour. -
I am using MSVC 2005
void function(char* str1,char* str2);
void main()
{
char p[]="Hello world";
char q[]="";
function(p,q);
cout<<"after function calling..."<<endl;
cout<<"string1:"<<"\t"<<p<<endl;
cout<<"string2:"<<"\t"<<q<<endl;
cin.get();
}
void function(char* str1, char* str2)
{
strcpy(str2,str1);
}
OUTPUT:
after function calling...
string1: ld
string2: Hello world
Thanks in advance,
Malathi
strcpy does not allocate memory required to store the string.
You must allocate enough memory in str2 before you do the strcpy.
Otherwise, you get undefined behaviour as you are overwriting some non-allocated memory.
q has only space for 1 character which is the terminating \0.
Please read a book about C - you need to learn something about memory management.
Most likely your memory looks like this (simplified): Qpppppppppppp. So when you strcpy to q, you will overwrite parts of p's memory.
Since you are using C++: Simply use std::string and or std::stringstream instead of raw char arrays.
In your code, q, is an one-element array (basing on the length of "", which is equal to one due to the null terminator), so it cannot contain the whole string. Hence you can't do a strcpy because it writes over invalid memory location (tries to write too much data to an array).
Declare q to be big enough to contain your string. Also, you can use strncpy to be on the safe side.
char q[] = ""; creates a character array with exactly 1 element - copying more data into it won't reserve more memory for it.
So, what happens is that when you write past the space reserved for q, you start overwriting what's in p - the two variables are next to each other in memory.
What everyone is saying is half correct. The code is failing because space is not reserved for the copy as others have pointed out correctly. The part that's missing is that your objects are on the stack, not the heap. Therefore it is not only likely, but inevitable that your code will get corrupted as the stack can no longer be unwound.
The array "q" is just one byte long; it definitely doesn't have room for the string "Hello, World"! When you try to copy "Hello, World" to q, you end up exceeding the bounds of q and overwriting p, which is adjacent to it on the stack. I imagine drawing a diagram of how these things are laid out on the stack, you could determine exactly why the garbage that ends up in p is just "ld".
strcpy expects you to provide an allocated storage buffer, not just a char* pointer. If you change char q[]=""; to char q[50]; it will work. Since you're only giving strcpy a pointer to a zero length string it doesn't have enough space to store the copied string and overwrites aka corrupts the memory.

basic question c++, dynamic memory allocation

Suppose I have a class
class person
{
char* name;
public:
void setname(const char*);
};
void person::setname(const char* p)
{
name=new char[strlen(p)];
strcpy(name,p);
name[strlen(p)]='\0';
}
My question is about the line
name=new char[strlen(p)];
suppose the p pointer is pointing to string i.e “zia” , now strlen(p) will return 3 it means we have an array of 4 characters i.e char[3] now I copy the string into the name and at the 4th location , I put the null character , what is wrong with this?????
You say:
we have an array of 4 characters i.e
char[3]
Surprisingly enough, char[3] is an array of THREE characters, not FOUR!
You MUST allocate one more char for zero terminator:
name = new char[strlen(p) + 1];
The problems are
You never delete[] name;, thus every time the user calls setname(), you leak an array.
To accomodate the extra '\0' you need to allocate for strlen(p)+1 elements.
You need to allocate one more memory position for the \0 character otherwise when you do this name[strlen(p)]='\0'; you get a Segmentation Fault. Basically do new char[strlen(p) + 1].
You should allocate strlen(p)+1 characters:
name = new char[strlen(p)+1];
The point where you're going wrong is here:
now strlen(p) will return 3 it means we have an array of 4 characters i.e char[3]
An array of 4 characters is a char[4]; if you allocate dynamically, you will have to pass 4 to operator new or, in general:
name=new char[strlen(p)+1];
void person::setname(const char* p)
{
name=new char[strlen(p) + 1]; // make a room to have null character
strcpy(name,p);
name[strlen(p)]='\0';
}
array index starts from 0 so max index for array of size = 5 is arr[4].
A lot of people have mentioned a cure for the immediate problem you've encountered. In doing so, they've almost done you a disservice though. Unless you have a really good reason to do otherwise, what you should probably do is define the name as and std::string, and use its assignment operator to handle the job correctly.
If you do have a spectacularly good reason to avoid using std::string, then you should design a string class of your own, and use it instead. At least in my opinion, writing code the way you have, with dynamic allocations and strcpys all over the place is just a poor idea. Even at very best, it's difficult to read, prone to lots of silly off-by-one errors, and essentially impossible to make anywhere close to exception safe.