The following C++ function has not been working in Visual Studio 6 (1998 year) until I added static. Why?
char* test(char* s1)
{
static char s[100]; strcpy(s, s1); char* r = s1;
if(s[0] == '\n')
{
s[0] = ' ';
cout << "\n";
}
return r;
}
It's dangerously unsafe (undefined behavior) to return a pointer to a stack variable. That includes arrays allocated on the stack. The memory occupied by a stack variable is essentially deallocated as soon as the function returns.
char* test(char* s1)
{
char s[100];
...
return s; // Bad! s is invalid memory when the function returns
}
By making the array allocation static, it's allocation will persist and is safer...
char* test(char* s1)
{
static char s[100];
...
return s;
}
But if any code path caches the pointer returned from "test", another code path that calls this function could invalidate the previous result.
For your example, you probably want to duplicate the string before returning. With the expectation that the caller will "free" the memory later:
char* test(char* s1)
{
char* s = strdup(s1);
strcpy(s, s1);
if(s[0] == '\n')
{
s[0] = ' ';
cout << "\n";
}
return s; // caller is expected to "free" the memory allocation later
}
Related
This function worked fine in another program, but in some cases it causes a runtime error saying that the stack around some variable, sometimes one that wasn't even sent into the function, was corrupted.
char *strCpy(char *dest, const char *source) { // copy cstring
char *origin = dest; // non iterated address
while (*source || *dest) {
*dest = *source;
dest++;
source++;
}
return origin;
}
implementation of the function:
int main() {
std::cout << "Will it crash?\n";
char temp[255];
char b[255];
std::cin >> temp;
strCpy(b, temp);
std::cout << b;
std::cout << "end\n";
return 0;
}
In this case, temp is corrupted, but not necessarily because it was passed into the function. I'm having trouble hunting down the issue beyond this.
The reason I wrote my own copy function is because of restrictions on the project. I am also not allowed to use [] to index arrays
Your logic in the loop condition is flawed and will lead to undefined behavior.
The contents of the destination is uninitialized and therefore indeterminate. You should not check the destination at all in your condition, only the source:
while (*source) { ... }
And of course, you need to add the terminator to the destination. This can simply be done after the loop like
*dest = '\0';
I am coding this in C++. My current issue at hand is that I have to trim the whitespace from the beginning of the character array. I am not allowed to use any string functions. My idea is to count the number of whitespaces at the beginning, allocate memory based on how much less memory I would need in a character array if I didn't have those whitespaces, do so, and then copy over the new string and deallocate the original string.
My issue is that I can't seem to deallocate that string without Visual Studio hitting a break point for me. I can get it working with the code I have below, (not deallocating the roginal strig at all) d=but wouldn't that cause a memory leak?
Thanks for your help in advance.
#include <iostream>
using namespace std;
class SmartString{
private:
char* str;
public:
SmartString ( )
{
str = NULL;
}
SmartString (char *str){
int length = 0;
int copy_index = 0;
while(str[length] != '\0')
{
length++;
}
length++;
char * copy;
copy = (char*)malloc(sizeof(char) * length);
copy = new char[length];
while(copy_index < length)
{
copy[copy_index] = str[copy_index];
cout << str[copy_index];
copy_index++;
}
this -> str = copy;
}
~ SmartString()
{
if(str != NULL)
{
delete str;
free(str);
}
}
void ShowString()
{
cout << "[" << str << "]";
}
int Size()
{
if(str == NULL)
return 0;
else
{
int i = 0;
while(str[i] != '\0')
{
i++;
}
i++;
return i;
}
}
**void Trim()
{
int counter = 0;
while (str[counter] == ' ' && counter < Size())
{
counter++;
}
int new_length = Size() - (counter + 1);
char * temp;
temp = (char*) malloc(sizeof(char) * new_length);
temp = new char[new_length];
int counter_2 = 0;
while(counter_2 < Size())
{
temp[counter_2] = str[counter_2 + counter];
counter_2++;
}
str = temp;
}**
};
int main()
{
char *str;
str = " Hello";
SmartString * s = new SmartString(str);
str = "Change";
(*s).Trim();
(*s).ShowString();
system("Pause");
}
You have not used 'delete' in your main function to deallocate your 's' pointer variable, So that the destructor method of your 'SmartString' class never called. In your second constrcutor method, you I've allocated the 'copy' variable twice where it's not need And also you have some mistake in your 'Trim' method.
In your destructor method, You should remove the free(str); statement cause the delete str; statement will deallocate the 'str'. So there is no need to deallocate twice.
malloc - Allocates the requested memory and returns a pointer to it.
new X; - Do the same thing but also calls constructor method if X is a class or struct after allocating.
new X[] - Allocates dynamic array with the requested memory and returns a pointer to it.
free - Deallocates the memory previously allocated.
delete - Do the same thing but also calls destructor method if X is a class or struct after deallocating.
delete[] - Deallocates the memory previously allocated dynamic array.
new and delete is the standard memory allocation and deallocation implement of C++ language where malloc and free is the standard memory allocation and deallocation function of C language.
Here I've rewritten your 'Trim' method:
void Trim()
{
int counter = 0;
while (str[counter] == ' ' && counter < Size())
{
counter++;
}
int new_length = Size() - (counter + 1);
char * temp;
// There is no need to allocate twice
//temp = (char*) malloc(sizeof(char) * new_length);
temp = new char[new_length+1];
int counter_2 = 0;
while(counter_2 < //Size() ( Here is your big mistake. You should not use 'Size()' here )
new_length
)
{
temp[counter_2] = str[counter_2 + counter];
counter_2++;
}
temp[counter_2] = 0;
str = temp;
}
And for deallocating, you have to use the 'delete' like this:
int main()
{
char *str;
str = " Hello";
SmartString * s = new SmartString(str);
str = "Change";
(*s).Trim();
(*s).ShowString();
// use delete to deallocate a pointer
delete s;
system("pause");
}
I see three reasonable approaches to this.
One would be to modify the existing string in-place. Find the position of the first non-space character, then copy from there to the end of the string to positions starting from the first element of the string. This can't be applied to a string literal (or you'll get undefined behavior).
The second would be to allocate a new buffer and copy the data you want to keep into that buffer. In this case, you probably do not want to try to modify the original (and, especially, you don't want to try to free its data).
The third would be to (basically) re-implement a class about like std::string, that always allocates a buffer in a specific way, so it "knows" how to manipulate that buffer safely. In this case, you could/would have a constructor to create an object from a string literal, so by the time your function was invoked, it would only (even attempt to) manipulate such objects and could never accidentally try to manipulate/modify something like a string literal.
So I'm studying this book, and I came across an exercise which (briefly) wants me to remove all white spaces of a char-array by using a function: void removeSpaces(char* s)
[iostream, cstring are included and SIZE is defined]
This is main():
int main() {
char a[SIZE] = "a bb ccc d";
cout << a << endl; // a bb ccc d
removeSpaces(a);
cout << a << endl; // a bb ccc d instead of abbcccd
}
This is removeSpaces():
void removeSpace(char* s) {
int size = strlen(s);
char* cpy = s; // an alias to iterate through s without moving s
char* temp = new char[size]; // this one produces the desired string
s = temp; // s points to the beginning of the desired string
while(*cpy) {
if(*cpy == ' ')
cpy++;
else
*temp++ = *cpy++;
}
cout << s << endl; // This prints out the desired result: abbcccd
}
(My choice of names isn't ideal, but nevermind that now.) So my function basically does what I want it to do, except that the result has no effect outside of the function's scope. How can I accomplish that? What am I missing, what am I doing wrong?
Since you pass the pointer by value, you are surely changing the array in place. Obviously, you'd remove spaces like this:
void removeSpaces(char* s) {
*std::remove(s, s + strlen(s), ' ') = 0;
}
Your function shouldn't even do any string copying. It should just do an in-place replacement:
void removeSpace(char* s)
{
for (char* s2 = s; *s2; ++s2) {
if (*s2 != ' ')
*s++ = *s2;
}
*s = 0;
}
Even terser:
void removeSpace(char* s)
{
char* s2 = s;
do {
if (*s2 != ' ')
*s++ = *s2;
} while (*s2++);
}
You change the value of s but that is a local variable and thus has no affect outside the function:
void removeSpace(char* s)
You could change this to:
void removeSpace(char*& s)
This makes a reference to the passed value. Thus changing s will change the original. Unfortunately that does not work for you because of the way you call removeSpace() (as you pass an array).
char a[SIZE] = "a bb ccc d";
removeSpaces(a);
You could change your code too:
char buffer[SIZE] = "a bb ccc d";
char* a = buffer;
removeSpaces(a);
Now the modifications suggested above would work correctly. But you are leaking memory (you dynamically allocate memory in removeSpace() that is never released. The best way to resolve that is to use modern C++ techniques rather than write C and and compile it with the C++ compiler.
Couple of solutions:
Modify the array in place (no dynamic allocation)
Use proper containers (std::string or std::vector)
Use the standard algorithms.
The call to removeSpaces has no affect because you are creating a temporary buffer in the function and copying the string into that while applying the transformation. You can fix this by removing the temporary buffer and just modifying the string in place.
void removeSpaces(char* s)
{
char* cpy = s; // an alias to iterate through s without moving s
char* temp = s;
while (*cpy)
{
if (*cpy != ' ')
*temp++ = *cpy;
cpy++;
}
*temp = 0;
cout << s << endl; // This prints out the desired result: abbcccd
}
Just add one last line to your function:-
strcpy(s, temp);
and remove unnecessary ones:-
s = temp;
Your function receives a copy of the pointer a. Changing the copy within the function does not change the caller's original a pointer.
I am trying to implement the functions below, but printing out the output of Printme(), the program that freezes . Any ideas why?
int main()
{
for (int i=0; i<12; i++)
{
cout<< PrintMe()[i];
}
return 0;
}
char * PrintMe() {
char str[12];
strncpy (str, "hello world", 11);
str[11] = 0;
return str;
}
Your code invokes Undefined Behaviour as you are returning a pointer to a temporary.
As soon PrintMe ends its execution, str becomes destroyed. Thus the pointer your accessing with PrintMe()[i] is invalid.
To fix this you have to return a heap allocated string (no automatic storage duration). But dont forget to destroy it afterwards:
char * PrintMe() {
char* str = new char[12];
strncpy (str, "hello world", 11);
str[11] = 0;
return str;
}
char* str = PrintMe();
for (int i=0; i<12; i++)
{
cout<< str[i];
}
delete[] str;
Or as you're writing c++ nontheless, why dont you go with a std::string?
In your PrintMe function, you are returning a pointer to a local variable. This is undefined behavior:
char* PrintMe() {
char str[12];
//...
return str; // cannot do this, UB.
}
This works if you change the return type to std::string
std::string PrintMe() {
char str[12];
//...
return str;
}
The reason why the above now works is that a std::string is being constructed from the local array and returned instead of the local variable.
The program has undefined behaviour because function PrintMe returns a pointer to the first element of a local array that will be destroyed after exiting the function. So the pointer will not be valid.
Change the function the following way that to get the predicted result
char * PrintMe() {
static char str[12];
strncpy (str, "hello world", 11);
str[11] = 0;
return str;
}
I have main function like this:
void main()
{
char *s;
inputString(s);
printf("%s",s);
}
and inputString function:
void inputString(char *&s)
{
//Some code line to input a string and set s point to this string
}
Is there have a function auto malloc memory enough store string which inputed (I need input string in inputString function).
Just 3 lines of code (put these inside int main() )are enough
std::string s;
std::cin >> s; //or getline() as desired
std::cout << s;
If you keep using this C style approach, then no, you will have to make assumptions and allocate enough memory yourself. The C++ approach is much more superior, use std::strings and don't do manual allocations:
#include <string>
#include <iostream>
void inputString(std::string& s)
{
//Don't bother for the memory management
}
int main()
{
std::string s;
inputString(s);
std::cout << s ;
}
Also do note that your code is not legal C++. void main() is illegal!!!
Edit: At the time of this answer the question was tagged C++. Later the question was retagged NOT by the OP, and I don't quite agree with it...
You're mixing C and C++ in your example.
In your case before you can use s it should be initialized. For example, like this:
void inputString(char *&s)
{
s = strdup(xxx); // or malloc, calloc, etc.
}
But really, then it's better to just use plain old C:
char* inputString(void)
{
char* s = strdup(xxx);
return s;
}
Assuming that you are doing this is C and not C++.
There are two approaches, either inputString must allocate the memory or the caller of inputString must allocate the memory.
if inputString allocates the memory your function will probably look something like:
char* inputString(void)
{
int len = strlen (MyInternalString) + 1;
char* s = malloc (len);
strncpy(s, MyInternalString, len);
return s;
} //similar to what Rustram illustrated
you should also include:
void freeString(char* str)
{
free(str);
}
as well. This makes it clear to the user that they are required to manage the memory of the returned string themselves.
Alternatively you can write inputString where the user is expected to provide the required memory. This will then look something like
int inputString(char* str, int maxLen) //
{
if (maxLen >= myInternalStringLength + 1)
{
strncpy(str, myInternalString, maxLen)
}
return myInternalStringLength + 1;
}
Here the user of my string can check the return code to see if the buffer that he allocated was big enough. If it was too small, then he can always realloc a bigger one
Your main now becomes:
int main()
{
char *s = NULL;
int len = inputString(s, 0);
s = alloca(len); //allocates the memory on the stack
len = inputstring(s, len);
printf("%s",s);
} //no need to free the memory because the memory alloca'ed gets
//freed at the end of the stack frame
int main()
{
std::string s;
inputString(s);
printf("%s",s.c_str());
}
and inputString function:
void inputString(std::string& s)
{
//Some code line to input a string and set s point to this string
std::cin >> s;
}