dynamic allocating memory for char array - c++

having some understanding issues with the next block of code.
#include<iostream>
using namespace std;
int main() {
char *str = "hi";
char *p = new char[strlen(str) + 1];
for (int i = 0; *(str + i); i++)
*(p + i) = *(str + i);
cout << p << endl;
return 0;
}
Here's the result:
hi═¤¤¤¤
When i'm using debugger, i can see that my p points to an array of like 10 or 15 or some other amount of symbols (depends on compilation), so i'm getting extra symbols after "hi". BUT, when i'm using strcpy():
#include<iostream>
using namespace std;
int main() {
char *str = "hi";
char *p = new char[strlen(str) + 1];
strcpy(p, str);
cout << p << endl;
return 0;
}
i'm getting the result:
hi
So, can someone, please, explain to me, why am i getting such a result with the first example of a program and how to rework it to get the result like in the second example.
Thanks in advance.

The answer is in the stopping condition of the loop, i.e. *(str + i):
for (int i = 0 ; *(str + i) ; i++)
*(p + i) = *(str + i);
Note that there is no comparison operator in the expression. When an expression like this is used in a context where a logical condition is required, there is an implicit comparison to zero, i.e. *(str + i) means the same thing as *(str + i) != 0.
Now it should be clear why the string remains unterminated: loop stops when it discovers null terminator, and does not copy it into the destination string.
A slightly more "cryptic" way of doing the same thing would be coupling the comparison with the assignment, the way K&R book did:
for (int i = 0 ; *(p + i) = *(str + i) ; i++)
;
Now the null test happens after the assignment, ensuring that the destination is null-terminated.

You are not adding the terminating null character to p.
Add the line
*(p + i) = '\0';
after the for loop. However, to do that, you have to declare i before the for loop.
int i = 0;
for (i = 0; *(str + i); i++)
*(p + i) = *(str + i);
*(p + i) = '\0';
cout << p << endl;

You forgot to terminate the string in your first exaple with a zero:
#include <cstddef>
#include <iostream>
int main()
{
char const *str = "hi";
std::size_t length = std::strlen(str);
char *p = new char[length + 1];
for (std::size_t i = 0; i < length; ++i)
p[i] = str[i];
str[length] = '\0';
std::cout << p << '\n';
delete[] p;
}
Please mind: String literals are immutable so they should be pointed to by char const*s. The correct type to hold sizes of objects in memory or indexes into them is std::size_t, not int. If you do manual memory management you have to make sure that you free the allocated memory by passing pointers obtained using new to delete and pointers from new[] to delete[].
You shouldn't do memory management manually though. Use containers like std::string or std::vector or at least smart pointers like std::shared_ptr<> or std::unique_ptr<>.

Related

releasing memory from char array

Getting the sound of an error (or may be exception), but not a pop-up window of it, so can't understand what's wrong. After debugger usage, realized that the error comes from the destructor. So i'm getting the result "August" but the program don't stop working after that. Assume that the problem is in releasing memory. Thanks in advance.
#include <iostream>
using namespace std;
class B_class {
char *p;
public:
void put_author(char *p) {
this->p = new char[strlen(p)];
for (int i = 0; i < strlen(p) + 1; i++)
*(this->p + i) = *(p + i);
}
void show_author() {
for (int i = 0; i < strlen(p) + 1; i++)
cout << *(p + i);
cout << endl;
}
~B_class() {
if (*p) {
delete[] p;
p = nullptr;
}
}
};
int main() {
B_class B;
B.put_author("August");
B.show_author();
return 0;
}
this->p = new char[strlen(p)];
You've allocated strlen(p) characters.
for (int i = 0; i < strlen(p) + 1; i++)
*(this->p + i) = *(p + i);
You write strlen(p) + 1 characters into the array. That's one more than the length of the allocated array. The behaviour of accessing an array outside of its bound is undefined.
You can fix this by allocating sufficiently large buffer.
If you created an instance of B_class, but never call put_author, you'd be calling delete[] p on an uninitialized pointer. The behaviour would be undefined.
You can fix this by initializing the p member in a constructor. Either to nullptr, or some buffer allocated using new[].
if (*p) {
delete[] p;
You only delete p if it isn't an empty string. So, if you did B.put_author("");, the memory would leak.
You can fix this by removing the if.
You happen to not do this in your example, but if you made any copies of B_class instances, the destructors of those instances would attempt to delete the same buffer, which would result in undefined behaviour.
You can fix this by following the rule of zero / three / five. The conventional approach would be to use std::string and get rid of your destructor.

C++ delete[] crash

Program crashes when I'm trying to delete[] an array that was allocated with new[]. I don't see any reasons why this shouldn't work. The array is allocated in method and deleted in the end of it, it's local, everything should be fine, but it's not.
I don't see any exception name that was thrown in debug, that's why I don't know where to dig.
Through debug I see that crash is happening at first delete[] operator.
Without those two deletes no crashes happening, but I don't want something to float in memory.
void Atbash::EncryptString(string t)
{
char *cOriginalString;
char *cEncryptedString;
unsigned int originalStringLength;
unsigned int i;
unsigned short j = 0;
originalString = t;
originalStringLength = originalString.length();
cOriginalString = new char(originalStringLength + 1);
cEncryptedString = new char(originalStringLength + 1);
strcpy_s(cOriginalString, originalStringLength + 1, originalString.c_str());
cOriginalString[originalStringLength] = '\0';
for (i = 0; i < originalStringLength; i++)
{
while (cOriginalString[i] != alphabet[j])
{
j++;
}
cEncryptedString[i] = alphabet[N - j - 2];
j = 0;
}
cEncryptedString[originalStringLength] = '\0';
encryptedString = cEncryptedString;
delete[] cOriginalString;
delete[] cEncryptedString;
}
originalString and encryptedString are of "string" type.
You aren't allocating a char[], just a plain old char. Note that you should be using square braces ([]) and not parenthethis (()):
cOriginalString = new char[originalStringLength + 1];
// Here ------------------^------------------------^
cEncryptedString = new char[originalStringLength + 1];
// And here ---------------^------------------------^
You can process individual characters in a std::string and it will both simplify your code and make it more robust. Here is one possible implementation.
void Atbash::EncryptString(string originalString)
{
encryptedString.clear();
encryptedString.reserve(originalString.size());
for (auto ch:originalString)
{
auto index= alphabet.find(ch);
if (index != npos)
encryptedString += alphabet[N - index - 2];
}
}

C++. How can I free memory correctly?

Written code to find and remove the largest word in a string without the using of library functions. Everything works fine. But when I want to free memory, the result is negative (displays an empty line). If you remove the call to the memory release function, everything will work correctly, but there will be a leak of memory.
How do I fix it? Please help me.
#include <iostream>
using namespace std;
int length(char *text) // string length
{
char *begin = text;
while(*text++);
return text - begin - 1;
}
int size(char **text) // size of two-dimensional array
{
int i = 0;
while(text[i]) i++;
return i;
}
void free_memory(char **text)
{
for(int i=0; i<size(text); i++)
delete text[i];
delete [] text;
}
char **split(char *text, char delim)
{
int words = 1;
int len = length(text);
for(int i=0; i<len; i++)
if(text[i] == delim) words++;
char **result = new char*[words + 1];
int j = 0, t = 0;
for(int i=0; i<words; i++)
{
result[i] = new char[len];
while(text[j] != delim && text[j] != '\0') result[i][t++] = text[j++];
j++;
t = 0;
}
result[words + 1] = nullptr;
return result;
}
char *strcat(char *source, char *destination)
{
char *begin = destination;
while(*destination) destination++;
*destination++ = ' ';
while(*source) *destination++ = *source++;
return begin;
}
char *removeWord(char *in_string)
{
char **words = split(in_string, ' ');
int max = length(words[0]);
int j = 0;
for(int i=0; i<size(words); i++)
if(max < length(words[i]))
{
max = length(words[i]);
j = i;
}
int index;
char *result;
if(!j) index = 1;
else index = 0;
result = words[index];
for(int i=0; i<size(words); i++)
if(i != j && i != index)
result = strcat(words[i], result);
free_memory(words); // I want free memory here
return result;
}
int main()
{
char text[] = "audi and volkswagen are the best car";
cout << removeWord(text) << endl;
return 0;
}
In fact, this is C style programming - not C++. I see that your aim is to implement everything from scratch, possibly for practicing. But even then, your code is not designed/structured properly.
Besides that, you also have several bugs in your code:
result[words + 1] = nullptr; must be result[words] = nullptr;
You need result[i][t] = '\0'; after the while loop in split
delete text[i] must be delete [] text[i]
You cannot assign to your result pointer memory from words, then free it and then return it for use by the caller.
There is at least one further bug in the second half of removeWord. It would be tedious to try to understand what you are trying to do there.
You might want to start with a simpler task. You also should proceed step-by-step and check each function for correctness independently first and not implement everything and then test. Also take a look at the tool valgrind for memory checking - if you use Linux.
The way you free memory correctly is to use RAII:
Only use new and new[] in constructors
Pair those with delete and delete[] in the corresponding destructor
Use automatic storage duration objects as much as possible
If you are specifically not using std::string and std::vector etc, for reasons of learning pointers, you will end up writing some small number of classes that resemble string and vector and unique_ptr, and then you go about programming as if you were using the std versions.
You have two issues. First is that result is assigned to a memory location in words. Second, is that you're storing the result of strcat in words[i] which will likely not have enough room (see strcat documentation).
result = new char[len(in_string)+1]; // +1 for space for null char
// the old loop reversed the word order -- if you want to keep doing
// that, make this a descending loop
for(int i=0; i<size(words); i++)
if(i != j && i != index)
strcat(result, words[i]);
free_memory(words);
return result;
So that when you free words, what result points to is also free'd. You would then need to free your result in main().
int main()
{
char text[] = "audi and volkswagen are the best car";
char * result = removeWord(text);
cout << result << endl;
delete[] result;
return 0;
}

Dereferencing an element of an array of pointers

So recently in class, we were introduced to pointers and heaps and how they work. A question I have is why cant we cout a dereferenced pointer in that array? For example, in the code below:
#include <iostream>
using namespace std;
int main() {
double* p = new double[2];
*(p + 0) = 37.5;
*(p + 1) = 101.4;
for (int i = 0; i < 2; i++)
cout << *p[i] << endl;
return 0;
}
Why doesn't cout << *p[i] work but cout << *(p + i) does?
In C, the name of an array is a pointer to the first element. C++ inherited that from C. In your program, p is the pointer to the first element of the array. So you either do pointer arithmetics as you did when setting the elements (e. g. *(p + 1) = 101.4;) or you use the subscript operator ([]) to do the arithmetics: *(p + i) is the same as p[i]. The compiler translates p[i] to 1) adding i to p and then 2) access the address that resulted from the sum. That is exactly what you have written: *(p + 1). The statement in the parentheses is calculated first and the reference operator is applied to this result. That is exactly what happens if you use the index operator instead. So your loop has to look like this:
for (int i = 0; i < 2; i++)
{
std::cout << p[i] << std::endl;
}
Because of the precedence of operators your statement *p[i] translates to *(p[i]). So this statement tries to use the double read from the array as an address that shall be accessed. That this is not possible, is obvious (hopefully).
Got it?
P.S.: And please, do yourself a favor and ALWAYS surround the body of for/while/if statements with curly brackets. That saves you a LOT of time (especially debugging your own nonsense). Trust me, it is true.
p[1] = *(p + 1)
it is what you want to do. The [] operator already dereferences.
*p[1] = *(*(p + 1))
it tries to dereference a double Wich cannot happen
cout << p[i];
should work as you expect
because *p[i] basically is *(*(p + i))
read here for me https://www.tutorialspoint.com/cplusplus/cpp_pointer_arithmatic.htm
http://www.learncpp.com/cpp-tutorial/6-8a-pointer-arithmetic-and-array-indexing/
Note that p[i] is same as *(p+i).
Now *p[i] is meaningless, unless p[i] itself points to a different location, for e.g.
int t=0;
for(int i = 0; i < 2 ;i++)
p[i] = &t;
cout << *p[i] << "is nothing but value of t" << endl;
I hope it is clear.

Flaws in algorithm and algorithm performance

char *stringmult(int n)
{
char *x = "hello ";
for (int i=0; i<n; ++i)
{
char *y = new char[strlen(x) * 2];
strcpy(y,x);
strcat(y,x);
delete[] x;
x=y;
}
return x;
}
I'm trying to figure out what the flaws of this segment is. For one, it deletes x and then tries to copy it's values over to y. Another is that y is twice the size of x and that y never gets deleted. Is there anything that I'm missing? And also, I need to figure out how to get algorithm performance. If you've got a quick link where you learned how, I'd appreciate it.
y needs one more byte than strlen(x) * 2 to make space for the terminating nul character -- just for starters.
Anyway, as you're returning a newed memory area, it's up to the caller to delete it (eek).
What you're missing, it seems to me, is std::string...!-)
As for performance, copying N characters with strcpy is O(N); concatenating N1 characters to a char array with a previous strlen of N2 is O(N1+N2) (std::string is faster as it keeps the length of the string in an O(1)-accessible attribute!-). So just sum N+N**2 for N up to whatever your limit of interest is (you can ignore the N+ part if all you want is a big-O estimate since it's clearly going to drop away for larger and larger values of N!-).
For starters delete[] x; operates for the first time round the loop on some static memory. Not good.
It looks like an attempt to return a buffer containing 2^n copies of the string "hello ". So the fastest way to do that would be to figure out the number of copies, then allocate a big enough buffer for the whole result, then fill it with the content and return it.
void repeat_string(const std::string &str, int count, std::vector<char> &result)
{
result.resize(str.size() * count);
for (int n = 0; n < count; n++)
str.copy(&result[n * s.size()], s.size());
}
void foo(int power, std::vector<char> &result)
{
repeat_string("hello ", 1 << (power + 1), result);
}
no need to call strlen() in a loop - only call it once;
when new is called no space is requested for the null-character - will cause undefined behaviour;
should use strcpy instead of strcat - you already know where to copy the second string and findig the end of string by strcat requires extra computation;
delete[] is used on a statically allocated string literal - will cause undefined behaviour;
memory is constantly reallocated although you know the result length well in advance - memory reallocation is quite expensive
You should instead compute the result length at once and allocate memory at once and pass the char* as an in-parameter:
char* stringMult(const char* what, int n)
{
const size_t sourceLen = strlen( what );
int i;
size_t resultLen = sourceLen;
// this computation can be done more cleverly and faster
for( i = 0; i < n; i++ ) {
resultLen *= 2;
}
const int numberOfCopies = resultLen / sourceLen;
char* result = new char[resultLen + 1];
char* whereToWrite = result;
for( i = 0; i < numberOfCopies; i++ ) {
strcpy( whereToWrite, what );
whereToWrite += sourceLen;
}
return result;
}
Certain parts of my implementation can be optimized but still it is much better and (I hope) contains no undefined-behaviour class errors.
you have to add one while allocating space for Y for NULL terminating string
Check the code at below location http://codepad.org/tkGhuUDn
char * stringmult (int n)
{
int i;
size_t m;
for (i = 0, m = 1; i < n; ++i; m *= 2);
char * source = "hello ";
int source_len = strlen(source);
char * target = malloc(source_len*m+1) * sizeof(char));
char * tmp = target;
for (i = 0; i < m; ++i) {
strcpy(tmp, source);
tmp += source_len;
}
*tmp = '\0';
return target;
}
Here a better version in plain C. Most of the drawbacks of your code have been eliminated, i.e. deleting a non-allocated pointer, too many uses of strlen and new.
Nonetheless, my version may imply the same memory leak as your version, as the caller is responsible to free the string afterwards.
Edit: corrected my code, thanks to sharptooth.
char* string_mult(int n)
{
const char* x = "hello ";
char* y;
int i;
for (i = 0; i < n; i++)
{
if ( i == 0)
{
y = (char*) malloc(strlen(x)*sizeof(char));
strcpy(y, x);
}
else
{
y = (char*)realloc(y, strlen(x)*(i+1));
strcat(y, x);
}
}
return y;
}
Nobody is going to point out that "y" is in fact being deleted?
Not even one reference to Schlmeiel the Painter?
But the first thing I'd do with this algorithm is:
int l = strlen(x);
int log2l = 0;
int log2n = 0;
int ncopy = n;
while (log2l++, l >>= 1);
while (log2n++, n >>= 1);
if (log2l+log2n >= 8*(sizeof(void*)-1)) {
cout << "don't even bother trying, you'll run out of virtual memory first";
}