I am playing around with arrays as pointers.
#include<iostream>
#include<cstring>
using namespace std;
int main(){
string *myarray[20];
*myarray[0]="Ich denke sein";
*myarray[1]="Ich sehe sein";
cout<<*myarray[0]<<endl;
cout<<*myarray[1]<<endl;
return 0;
}
The above code compiles but while executing, there is error, the program hangs. When I debugged using visual studio, it said memory allocation error. What is the error here?
As I know, I am dealing with values refered by pointers everywhere.
You have allocated an array of 20 pointers to strings. But you haven't allocated any memory for what the pointers point to. Rather than pursuing this and using new to allocate memory for the strings, it would be better instead to allocate memory for the strings themselves in the array and you will be fine.
string myarray[20];
myarray[0]="Ich denke sein";
myarray[1]="Ich sehe sein";
cout<<myarray[0]<<endl;
cout<<myarray[1]<<endl;
In response to your comment, to make your program work as is, set the pointer to point to a new string object
myarray[0]=new string("Ich denke sein");
myarray[1]=new string("Ich sehe sein");
The other lines of your program remain unchanged. Note
the remaining myarray[i], for 2<=i && i<20 will still be garbage. (It would be neater to set them to 0 or nullptr in a for loop.)
you also ought to delete the objects you've allocated. (You could use a for loop over the whole array to do this if you'd cleared the rest of the pointers first.)
as other answers have commented, in modern C++ it is best not to use pointers directly unless you absolutely have to. And you would also typically prefer to use a vector for arrays rather than using the built-in type (in C++11 the array type can be used for arrays where you know the length at compile time).
You have an array of uninitialized pointers:
string *myarray[20];
Then you treat it as if the pointers pointed to valid objects:
*myarray[0]="Ich denke sein";
This is undefined behaviour. It is unrelated to arrays. It is the same as doing this:
std::string* s;
*s = "boom!";
Besides that, you really should #include <string> if you want to use std::string.
First, you didn't include the right header. For string, you should:
#include <string>
Second, the program hangs because you're assigning data to where the pointer is pointing to. So where does myArray[0] point to? You don't know, I don't know, no one knows. It seems you didn't get the grasp of what pointers are all about, regardless of whether you're dealing with arrays of them or not.
To use a pointer, it must point somewhere valid. If you don't do that, then you can't dereference the pointer and assign data. It's that simple.
May be the problem is that those pointers aren't pointing to any addres in the memory. Pointers should be initialized to somewhere using the "address of operator" (&) or putting them in the free memory, using the "new" keyword, and if you do so, don't forget to free that memory using the "delete" keyword. Hope that works for you.
What is the error here?
The error is, that you are using pointers ;-)
#include <string>
#include <iostream>
int main() {
std::string myarray[2] = {
{ "Ich denke sein" }, { "Ich sehe sein" } };
std::cout << myarray[0] << std::endl;
std::cout << myarray[1] << std::endl;
return 0;
}
What is the reason behind using pointer? In C++ you mostly never use pointers.
Kind regards - Andreas
You have declared an array of 20 pointers. You will have to allocate memory to the pointer before assigning a value at the location to which it points.
string* myarray[20];
for(int i = 0; i < 20; i++) {
myarray[i] = new string();//allocating memory to the pointer
}
*myarray[0]="Ich denke sein";
*myarray[1]="Ich sehe sein";
cout<<*myarray[0]<<endl;
cout<<*myarray[1]<<endl;
Pointers are used to point to memory addresses, like this:
String text ="hello";
String *myptr = &text;
Now the pointer points to the address of the string text.
Or you can use new keyword to allocate memory for an array of pointers. new returns you a pointer to the first position of the array. Like this:
int *myptr = new int[20];
But remember to use delete, to deallocate the allocated memory later. Like this:
delete[] myptr
Related
Consider the following code:
int *expand_array(int *old_arr,int array_length)
{
int *new_arr = new int[array_length +3];
for(int counter=0;counter<array_length;counter++)
new_arr[counter]=old_arr[counter];
delete[] old_arr;
return new_arr;
}
int main()
{
int *my_first_arr = new int[4];
int *my_expanded_arr=expand_array(my_first_arr,4);
delete[] my_expanded_arr;
}
will there be any memory leak here?
And to generalize the question,
if the pointer returned from a new statement is copied ,passed to a function or assigned to a different pointer, will the delete copied_pointer release the memory?
Your code is perfectly valid C++ and has no memory leaks. You can copy a pointer as often as you want to and deleteing any of those copies in any scope has the same effect.
It is still bad practice, however, and you shouldn't write code like this. Use of raw new and delete is too error prone and will make for poorly maintainable code. Instead, use RAII wrapper types like std::unique_ptr, std::shared_ptr or, in this case, std::vector.
The code in your question is basically equivalent to this.
int
main()
{
auto numbers = std::vector<int>(4);
numbers.resize(7);
}
Much simple, no?
Why do you believe that there would be a memory leak? Of course there wouldn't be.
But there is a different bug in this code. If the new array size is larger than the size of the existing old_arr, the code that copies the old array to the newly allocated int array is going to copy too much, run off past the end of the old array, resulting in undefined behavior; possibly a crash (old array size is 2 ints, array_length is 10, the for loop will attempt to copy 10 values from the old array which only has 2).
I'm having trouble understanding arrays of pointers to structures. I created this simple example to try and understand them better. Although it compiles, I keep getting "BAD ACCESS" crashes (nonsense pointers) at the point shown below. Can anyone explain why this is wrong?
#include <iostream>
using namespace std;
struct complex_num {
double real_part;
double imag_part;
};
void init_complex(complex_num *element) {
element->real_part = -1.0; // <--- EXECUTION STOPS HERE.
element->imag_part = 1.0;
}
int main(int argc, char *argv[]) {
int n = 5;
complex_num *array[n]; // Allocates for an array of n pointers to
// the complex_num structure, correct?
for (int i = 0; i < n; i++) {
init_complex(array[i]);
}
return 0;
}
I know there are better ways to do this. I know this is very C in style. Please don't suggest a different data structure. I'm curious specifically about arrays of pointers to structures. Thanks!
You did not allocate memory for your complex_num objects, only for an array with pointers to it. So when you call init_complex, it operates on a pointer to an invalid location.
Try this:
for (int i = 0; i < n; i++) {
array[i] = new complex_num();
init_complex(array[i]);
}
Your statement complex_num *array[n] creates an array of n pointers to complex_num. Meaning, the array can hold n pointers to complex_num; but the pointers themselves are still uninitialized. They point to random locations - every uninitialized primitive (to which pointers belong as well) in C++ will usually simply contain whatever value was in the memory location before the allocation. This will almost certainly lead to unexpected results, as there is no way (or at least no reasonably easy way) of telling where an uninitialized pointer points to.
So you'd have to make each pointer in the array point to some properly set up memory location containing complex_num; only after that you should access (read or write) the values in the complex_num where the pointer points to. To make it e.g. point to a dynamically allocated, new complex_num object, use the above code (notice the new keyword which does the dynamic allocation).
Side note: "Raw" pointers, pointing to dynamically allocated objects, like shown above, are tricky to handle (you should not forget to call delete after you are finished, otherwise you will leak memory), therefore the recommended practice is usually to use smart pointers (like std::shared_ptr, introduced with C++11).
yes, there is no memory allocated to the pointers you have declared. It doesn't point to any valid structure object
I am trying to resize a dynamically allocated string array; here's the code!
void resize_array() {
size_t newSize = hash_array_length + 100;
string* newArr = new string[newSize];
fill_n(hash_array,newSize,"0"); //fills arrays with zeros
memcpy( newArr, hash_array, hash_array_length * sizeof(string) );
hash_array_length = newSize;
delete [] hash_array;
hash_array = newArr;
}
unfortunately it isn't working and gives a segmentation fault. any idea why? this is basically a linear probing hash table where the element gets inserted wherever there is a 0 hence I use fill_n to fill the newly created array with 0's. any help please?
memcpy( newArr, hash_array, hash_array_length * sizeof(string) );
This line is extremely dangerous, std::string is not a plain old data type,
you can't make sure that memcpy could initialize it correctly, it may cause
undefined behavior, one of the most nasty behavior of c++(or programming).
Besides, there are a better and safer(in most of the times) solution to create
a dynamic string array in c++, just use vector
//create a dynamic string array with newSize and initialize them with "0"
//in your case, I don't think you need to initialize it with "0"
std::vector<std::string> newArr(newSize, "0");
if the hash_array has the same type as newArr(std::vector)
The way of copy it is very easy.
c++98
std::copy(hash_array.begin(), hash_array.end(), newArr.begin());
c++11
std::copy(std::begin(hash_array), std::end(hash_array), std::begin(newArr));
Better treat c++ as a new language, it has too many things are different from c.
Besides, there are a lot of decent free IDE, like code::blocks and QtCreator
devc++ is a almost dead project.
If you are new to c++, c++ primer 5 is a good book to start.
If string is actually an std::string (and probably even if it isn't) then this will crash. You are creating a new array of strings, copying the old string classes over the top, and then freeing the old strings. But if the string class contains internal pointers to allocated memory this will result in a double free because all you are doing is copying the internal pointers - not making new memory allocations.
Think about it like this; imagine you had the following class:
class foo
{
char* bar;
foo() { bar = malloc(100); }
~foo() { free(bar);
};
foo* ptr1 = new foo;
foo* ptr2 = new foo;
memcpy(ptr2, ptr1, sizeof(foo*));
delete ptr1;
At this point, ptr2->bar points to the same memory that ptr1->bar did, but ptr1 and the memory it held has been freed
The best solution would be to use a std::vector because this handles the resizing automatically and you don't need to worry about copying arrays at all. But if you want to persist with your current approach, you need to change the memcpy call to the following:
for (int i = 0; i < hash_array_length; ++i)
{
newArr[i] = hash_array[i];
}
Rather than just copying the memory this will call the class's copy constructor and make a proper copy of its contents.
I suspect the culprit is memcpy call. string is complicated type which manages the char array by pointers (just as you are doing right now). Normally copying string is done using assignment operator, which for string also copies its own array. But memcpy simply copies byte-per-byte the pointer, and delete[] also deletes the array managed by string. Now the other string uses deleted string array, which is BAAAD.
You can use std::copy instead of memcpy, or even better yet, use std::vector, which is remedy to most of your dynamic memory handling problems ever.
void aFunction_2()
{
char* c = new char[10];
c = "abcefgh";
}
Questions:
Will the: c = "abdefgh" be stored in the new char[10]?
If the c = "abcdefgh" is another memory area should I dealloc it?
If I wanted to save info into the char[10] would I use a function like strcpy to put the info into the char[10]?
Yes that is a memory leak.
Yes, you would use strcpy to put a string into an allocated char array.
Since this is C++ code you would do neither one though. You would use std::string.
void aFunction_2()
{
char* c = new char[10]; //OK
c = "abcefgh"; //Error, use strcpy or preferably use std::string
}
1- Will the: c = "abdefgh" be
allocated inner the new char[10]?
no, you are changing the pointer from previously pointing to a memory location of 10 bytes to point to the new constant string causing a memory leak of ten bytes.
2- If the c = "abcdefgh" is another
memory area should I dealloc it?
no, it hasn't been allocated on heap, its in read-only memory
3- If I wanted to save info inner the
char[10] I would use a function like
strcpy to put the info inner the
char[10]?
not sure what you mean with 'inner' here. when you allocate using new the memory is allocated in the heap and in normal circumstances can be accessed from any part of your program if you provide the pointer to the memory block.
Your answer already has been answered multiple times, but I think all answers are missing one important bit (that you did not ask for excplicitly):
While you allocated memory for ten characters and then overwrote the only pointer you have referencing this area of memory, you are created a memory leak that you can not fix anymore. To do it right, you would std::strcpy() the memory from the pre-allocated, pre-initialized constant part of the memory where the content of your string-literal has been stored into your dynamically allocated 10 characters.
And here comes the important part:
When you are done with dealing with these 10 characters, you deallocate them using delete[]. The [] are important here. Everything that you allocate using new x[] has to be deallocated with delete[]. Neither the compiler nor the runtime warn you when use a normal delete instead, so it's important to memorize this rule.
No, that is only pointer reassignment;
No, deleteing something that didn't come from new will often crash; and
Yes, strcpy will do the job… but it's not usually used in C++.
Since nobody has answered with code, std::uninitialized_copy_n (or just std::copy_n, it really doesn't make a difference here) is more C++ than strcpy:
#include <memory>
static char const abcs[] = "abcdefgh"; // define string (static in local scope)
char *c = new char[10]; // allocate
std::copy_n( abcs, sizeof abcs, c ); // initialize (no need for strlen)
// when you're done with c:
delete[] c; // don't forget []
Of course, std::string is what you should use instead:
#include <string>
std::string c( "abcdefgh" ); // does allocate and copy for you
// no need for delete when finished, that is automatic too!
No (pointer reassignment)
No
Yes, you can use strcpy(), see for instance:
I'm reading through an example in primer and something which it talks about is not happening. Specifically, any implicit shallow copy is supposed to copy over the address of a pointer, not just the value of what is being pointed to (thus the same memory address). However, each of the pos properties are pointing to two different memory addresses (so I am able to change the value of one without affecting the other). What am I doing wrong?
Header
#include "stdafx.h"
#include <iostream>
class Yak
{
public:
int hour;
char * pos;
const Yak & toz(const Yak & yk);
Yak();
};
END HEADER
using namespace std;
const Yak & Yak:: toz(const Yak & yk)
{
return *this;
}
Yak::Yak()
{
pos = new char[20];
}
int _tmain(int argc, _TCHAR* argv[])
{
Yak tom;
tom.pos="Hi";
Yak blak = tom.toz(tom);
cout << &blak.pos << endl;
cout << &tom.pos << endl;
system("pause");
return 0;
}
You're printing the addresses of the pointers, not the address of the string they're pointing to:
cout << &blak.pos << endl;
cout << &tom.pos << endl;
They are two different pointers, so their addresses differ. However, they point to the same string:
cout << static_cast<void*>(blak.pos) << endl;
cout << static_cast<void*>(tom.pos) << endl;
(Note that cast static_cast<void*>(tom.pos). As Aaron pointed out in a comment, it is necessary because when outputting a char* will through operator<<, the stream library will assume the character pointed to to be the first character of a zero-terminated string. Outputting a void*, OTOH, will output the address.)
Note that there is more wrong with your code. Here
Yak tom;
You are creating a new object. Its constructor allocates 20 characters, and stores their address in tom.pos. In the very next line
tom.pos="Hi";
you are assigning the address of a string literal to tom.pos, thereby discarding the address of the bytes you allocated, effectively leaking that memory.
Also note that Yak has no destructor, so even if you don't discard the 20 characters that way, when tom goes out of scope, tom.pos will be destroyed and thus the address of those 20 bytes lost.
However, due to your missing copy constructor, when you copy a Yak object, you end up with two of them having their pos element pointing to the same allocated memory. When they go out of scope, they'd both try to delete that memory, which is fatal.
To cut this short: Use std::string. It's much easier. Get a grip on the basics, using safe features of the language like the std::string, the containers of the stdandard library, smart pointers. Once you feel sure with these, tackle manual memory management.
However, keep in mind that I, doing C++ for about 15 years, consider manual resource management (memory is but one resource) error-prone and try to avoid it. If I have to do it, I hide each resource behind an object managing it - effectively falling back to automatic memory management. :)
Which "primer" is this you're reading? Lippmann's C++ Primer? If so, which edition? I'd be surprised if a recent edition of Lippmann's book would let you lose onto dynamic memory without first showing your the tools to tackle this and how to use them.
Unless i'm missing something, it seems you are printing out the address of variable pos, but not the address to which they both point to. The addresses of both pos are different, but the pointers should be the same.
The code does not make a lot of sense.
The toz method takes a Yak but does nothing with it. Why? In fact, what is toz supposed to do, anyway?
tom.pos = "Hi" does not copy Hi into the new char[20] array that you allocate in the constructor. Instead it replaces the pos pointer with a pointer to a static const char array containing "Hi\0". You would need to use strcpy.
Your code has a memory leak in it. You are allocating 20 characters on construction and have pos point to the allocated memory. However you are then pointing pos at the memory containing "Hi" without deleting the memory first.
In any case, pos is a member variable of type char *. Each instance of Yak is going to have its own unique pos. Because pos is a pointer, however, it's possible that they are pointing to the same block of memory (and this is the case in your example).
What you are printing out is the address of the pos variable which is of type char *, and not the address of the memory it is pointing to, which is of type char. Remember that a pointer is a variable like any other, it has an address and a value (and that value, in the case of a pointer, is an address).
If you want blak to be a shallow copy of tom, try the following instead of using your function toz:
Yak *blak = &tom;
// Note the use of -> ; also, &blak->pos will work
cout << &(blak->pos) << endl;
cout << &tom.pos << endl;
Now, blak merely points to tom --- it has nothing else associated with it.
Also, there are two other issues with your code:
pos = new char[20];
You are allocating memory here which has not been freed when you're done with the Yak object --- this will lead to memory leaks (unless you plan to free it elsewhere). If the use of pos ends with the use of the Yak object it's associated with (e.g.tom) then I recommend adding delete pos; to the destructor of Yak. Or as sbi suggested, use std::string.
tom.pos = "Hi";
You're assigning it to a string literal. This means that pos will be stuck to Hi which is actually a read-only section in memory. You cannot change the string stored in pos, so I don't think this what you intended. Therefore, allocating 20 bytes in the beginning to pos seems pointless.
Again, I recommend using string.