I am trying to learn C++ by firstly going through the low level details before I start using abstractions such as std::copy or memcpy. Currently I am stuck in trying to figure out why this code is never assigning into "sortedArray" variable, when looking with debugger I dereference the value from "data" correctly but it is never assigned to "sortedArray". I see value such as "-842150451" instead of "14" for first value. Can you please help me figure out what I am doing wrong ? And any other issues there may be that I do not see or advice would be greatly appreciated !
void swap(int* bigger, int* smaller){
*bigger += *smaller;
*smaller = *bigger - *smaller;
*bigger = *bigger - *smaller;
}
int* bubbleSort(int *data, int size){
bool swapped = true;
int *sortedArray = (int*)malloc(size*sizeof(int));
for (int i = 0; i < size;i++){
*(sortedArray++) = *(data++);
}
while (swapped){
swapped = false;
for (int i = 1; i <= size - 1; i++){
if (sortedArray[i - 1] > sortedArray[i]){
swap(&sortedArray[i - 1], &sortedArray[i]);
swapped = true;
}
}
size--;
}
return sortedArray;
}
*(sortedArray++) = *(data++); modifies the pointer so it no longer points to the start of the allocated memory. So, later on sortedArray[i] is whatever happens to be in memory past the array, and accessing it is undefined behavior.
If you must use pointers, a quick fix is to use a temporary one, like:
int *sortedArray = (int*)malloc(size*sizeof(int));
int* s = sortedArray;
for (int i = 0; i < size;i++){
*s++ = *data++;
}
Another way would be:
int *sortedArray = (int*)malloc(size*sizeof(int));
for (int i = 0; i < size;i++){
sortedArray[i] = data[i];
}
But, the best way would be to use standard containers and algorithms, like vector and sort.
Here's a demo of the first fix in action.
Change
*(sortedArray++) = *(data++);
to
sortedArray[i] = data[i];
You need to leave intact the pointer to the block of memory you allocated, so you can use it (and free it) later.
Note, there is nothing to be gained by using the *(x+y) syntax instead of x[y], they are equivalent but the latter is easier to read.
In C++ you should not use malloc. Instead use new int[size]. For int there is no difference other than reduced risk of making a typo, however for non-trivial types malloc will not construct them correctly.
That is not C++ at all. You can write generic code that takes a begin iterator and an end iterator in order for it to work with any kind of container that supports such semantic.
template<typename IT>
void bubble_sort(IT begin, IT end) {
while (true) {
bool swapped = false;
for (IT i = begin; i != end-1; i = i+1) {
if (*i > *(i+1)) {
std::iter_swap(i, i+1);
swapped = true;
}
}
if (swapped == false) return;
}
}
Live demo
Where std::iter_swap is like std::swap but works on iterators. You can see iterators as a pair of pointers to the beginning and (past the) end of a container.
You first pointer sortedArray points to some allocated memory.
Then in the first for loop you increment the pointer. not it doesn't point to that memory anymore.
Simply use a temporary pointer for the memory copy.
int* t = sortedArray ;
And now use t in your for loop which copies the data.
Instead of the temporary variable, you can rather count the number of times you called sortedArray++ in your for loop.
If you take a look: for (int i = 0; i < size;i++) you will see that the loop took exactly size number of iterations.
Just subtract size from the pointer after the loop and you point back to your allocated memory.
sortedArray -= size ;
Related
I am trying to create an array, which doubles every time it is completely filled.
#include <iostream>
using namespace std;
int* array_doubler(int* array, int size){
int *new_array = new int[size*2];
for(int i = 0; i < size; i++){
new_array[i] = array[i];
}
delete[] array;
return new_array;
}
int main()
{
int N = 10; // Size of array to be created
int *array = new int[0];
for(int i = 0; i < N; i++)
{
if(array[i] == '\0')
array = array_doubler(array, i);
array[i] = i*2;
}
//Printing array elemensts
for(int i = 0; i < N; i++)
cout << array[i] << '\t';
cout << '\n';
return 0;
}
Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot). i.e. If i write:
int* p = new int[5];
then all the 5 blocks in memory p[0],p[1],p[2],p[3],p[4],p[5] have \0 in them, not just the p[5]. So the if(array[i] == '\0') in my main() calls array_doubler for every single iteration of for loop. I want it to fill the available spots in the array first and when it reaches the last element, then call array_doubler.
Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot).
Actually they have undefined values in them. 0 is a valid value for them to have, but tomorrow the compiler might suddenly decide that they should all have 1 instead of 0.
If you want to detect the end of an array, then you have to remember how big the array is. C++ doesn't do it for you. Actually, it does do it for you if you use std::vector, but I suppose that's not the point of this exercise.
I'm not sure why you'd want to do this, as std::vector offer this kind of feature, and are more idiomatic of c++ (see isocpp faq on why C-style array are evil).
One of the issue of C-style array is the fact that they donĀ“t know their own size, and that they don't have default value, thus stay uninitialized.
If for some reason you need to not use std::vector, the next best solution would be to wrap the array with it's size in a structure or a class (which is kinda what std::vector is doing), or to initialize your array using std::memset (which is the C function you would use if you were in C).
Do keep in mind that this is not considered as good practices, and that the STL offer plenty of solution when you need containers.
I am trying to recreate the vector class and I believe there is a memory leak in my code, but I don't know how to solve it. Using the CRT Library in my Visual Studio, it tells me that there is a supposed memory leak that doubles for each time that reserve is called.
I am not quite sure why that is or if there even is a memory leak. The memory leak detection says that it is this line in the reserve function int* temp = new int[n];
This is what I understand to be happening in the reserve function:
Once the contents of arr are copied into temp, it's fine to delete arr. Assigning arr = temp should work because all I'm doing is making arr point to the same place as temp. Because arr was previously deleted, I only have 1 array in the heap and arr and temp both point to the same array so there should be no memory leak. Temp shouldn't matter because it disappears after it exits the scope. On subsequent calls to the reserve function, every thing repeats and there should only be one array in the heap which arr points to.
I do believe that my thinking is probably erroneous in some way.
#include "Vector.h"
namespace Vector {
vector::vector() {
sz = 0;
space = 0;
arr = nullptr;
}
vector::vector(int n) {
sz = n;
space = n;
arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = 0;
}
}
void vector::push_back(int x) {
if(sz == 0) {
reserve(1);
} else if (sz == space) {
reserve(2*space);
}
arr[sz] = x;
sz++;
}
void vector::reserve(int n) {
if (n == 1) {
arr = new int[1]; //arr was a nullptr beforehand
}
int* temp = new int[n];
for(int i = 0; i < n; i++) {
temp[i] = arr[i];
}
delete[] arr;
arr = temp;
space = n;
}
Your code assumes in vector::reserve(int n) that arr is null.
Instead maybe spilt up how reserve functions based on whether or not arr is null.
void vector::reserve(int n) {
if (arr) { //handle case when arr is null
space += n;
arr = new int[space];
//no need to copy anything!
} else { //handle case when arr is not null
int* tmp(new int[space + n]);
for(int i = 0; i < space; i++) {
tmp[i] = arr[i];
}
delete[] arr;
arr = tmp;
space += n;
}
}
Also the above code assumes you mean to reserve space+n instead of allowing reserve to shrink the array as you'll lose data if you reserve less then a previous reserve. It's usually better practice to not use assumptions about a pointer's state when working with them because when your code gets more complex the assumptions can end up getting forgotten or more obscure.
I have same issues too. I have created two pointers that points in the same address in heap. When I'm trying too deallocate the memory, and the result is only one pointer that can do that, it's the first pointers that point that address. The second or third pointers that points that address doesn't have an authority to deallocate the memory, but only the first pointers who have that authority.
Example
int *a = new int[5];
int *b = a;
int *c = a;
Pointers b and c doesn't have an authority too dealloacte the memory address that pointers a pointed. Therefore, the memory wasn't deallocated if i'm saying delete[] b nor delete[] c, they didn't have an authority for doing that. Then I tried to write delete [] a and that worked. I don't have an real answers, and I just trying to approaching through my try and errors that I have done. And that's what I got.
Actually this case is violating the rules, but C++ still allowed us to do it, it's called undefined behaviors. We are violating the rules of delete[] operators by, but C++ still allowed you to do, and as the result, you get unexpected output.
Not too much wrong in there.
Bugs
if (n == 1) {
arr = new int[1]; //arr was a nullptr beforehand
}
The comment cannot be guaranteed. Nothing prevents multiple calls of resize including a call of reserve(1), and that will leak whatever memory was pointed at by arr. Instead consider
if (arr == nullptr) {
arr = new int[n]; //arr was a nullptr beforehand
}
now the comment is guaranteed to be true.
The copy loop overshoots the end of arr every time the size of the array is increased.
for(int i = 0; i < n; i++) {
temp[i] = arr[i];
}
arr is only good up to arr[sz-1]. If n is greater than space, and it almost always will be, arr[i] wanders into the great wilds of Undefined Behaviour. Not a good place to go.
for(int i = 0; i < n && i < sz; i++) {
temp[i] = arr[i];
}
Checks both n and sz to prevent overrun on either end and copying of data that has not been set yet. If there is nothing to be copied, all done.
Targets of opportunity
The class needs a destructor to release any memory that it owns (What is ownership of resources or pointers?) when it is destroyed. Without it, you have a leak.
vector::~vector() {
delete[] arr;
}
And if it has a destructor, the Rule of Three requires it to have special support functions to handle (at least) copying of the class or expressly forbid copying.
// exchanges one vector for the other. Generally useful, but also makes moves
// and assignments easy
void vector::swap(vector& a, vector& b)
{
std::swap(a.sz, b.sz);
std::swap(a.space, b.space);
std::swap(a.arr, b.arr);
}
// Copy constructor
vector::vector(const vector& src):
sz(src.sz),
space (src.space),
arr(new int[space])
{
for(int i = 0; i < sz; i++) {
arr[i] = src.arr[i];
}
}
// move constructor
vector::vector(vector&& src): vector()
{
swap(*this, src);
}
// assignment operator
vector::vector& vector::operator=(vector src)
{
swap(*this, src);
return *this;
}
The Copy Constructor uses a Member Initializer List. That's the funny : bit.
The assignment operator makes use of the Copy and Swap Idiom. This isn't the fastest way to implement the assignment operator, but it is probably the easiest. Start with easy and only go to hard if easiest doesn't meet the requirements.
My teacher introduced us to looping through an array in the following format:
int size;
cin >> size;
int *garbage = new int[size];
for (int* p = garbage; p < (garbage + size); p++) {
if (*p > *max) {
max = p;
}
}
I understand what's going on, but it's just odd to me as a new concept. Are there better ways of going through an array like this?
Second Question: do you have to turn every pointer to a nullptr once you are done with it? For example, does it cause memory leaks to have that for loop like that with the pointer p or does it self destruct once it leaves the for loop scope?
There certainly are better (as in - more readable) ways of iterating through an array. For instance:
for (int index = 0; index < size; index++) {
if (p[index] > *max) {
max = &p[index];
}
}
However, as you see in the max = ... assignment, it's easier to have a pointer to an element of an array if you want to pass it on to another pointer variable.
Regarding your second question - there is no inherent value in setting it to nullptr. However, to prevent memory leaks, you should deallocate (free) the memory you reserved with operator new by using the operator delete once you're done with the array, like so:
delete [] p;
EDIT: Please note that you won't be able to safely dereference the pointer max (meaning you can't read that int it's pointing to with *max expression) after you deallocate the array without causing Undefined Behavior and possibly crashing your program, because your program will return the reserved memory to the OS and won't have access to it.
Thanks to #user4581301 for pointing it out.
There's another way of solving the problem. There's a C++ standard library algorithm for finding the maximum element in a range: std::max_element. No hand-written loop is needed.
int max = *std::max_element(garbage, garbage + size);
Note that it returns an iterator (a pointer in this case) so I used * to get the value from the iterator.
Your teacher might not like this solution.
It's a bit cleaner to do this:
int size = 10, max = 0;
int *mem = new int[size];
int *end = mem + size;
for (int *p = mem; p < end; p++)
if (*p > max)
max = *p;
But if you start using C++11 you can do this:
int max = 0;
std::vector<int> mem;
for (auto &i : mem)
if (i > max)
max = i;
There are probably even easier ways using other std namespace tools.
do you have to turn every pointer to a nullptr once you are done with it?
No, but it helps a lot when debugging. If you use a freed pointer that wasn't set to nullptr you'll be a lot more confused than if it is nullptr. Setting the pointer to nullptr doesn't actually automatically free the memory. You still have to call the appropriate 'free' function before setting to nullptr.
in C++11 you can do this:
int max = 0;
std::vector<int> mem;
for (auto &i : mem)
if (i > max)
max = i;
I am currently writing a program for a class that takes user input to either add or remove a number from a dynamic array, and then print all the values of the array in ascending order.
From what I have already researched, all I need to do to get the value of the element in the array to print is to ensure the dereference operator is inserted next to the pointer name. However, when done as below (newArray[i]) I get a compile-time error saying that the operand to the right of the '' must be a pointer, even though newArray is declared as pointer at the beginning of the function.
void output(int *arrayPtr, int size){
int small;
int i, j;
int *newArray;
newArray = new int[size];
for (i = 0; i < size; i++){
*newArray[i] = arrayPtr[i];
}
for (i = 0; i < size; i++){
small = *newArray[i];
for (j = 0; j < size; j++){
if (*newArray[j] < small){
*newArray[j] = small;
}
std::cout << small;
}
int number = small;
removeNumber(*& arrayPtr, number, size);
}
}
I feel like there is something totally obvious I am missing, but I would greatly appreciate any help or ideas!!
small = *newArray[i];
That should just be:
small = newArray[i];
(Same thing in the other places you compare/assign *newArray[i]
What your first operation is doing is first dereferencing newArray, which means it gets the value of the first element in the array, and then attempting to index that. The element is not a pointer, so this of course fails. When you index, it also implicitly dereferences the pointer. You could also write:
small = *(newArray + i);
However, generally you only use pointer arithmetic when you need the actual pointer, since indexing is easier to read if you need the value.
Going through your code, a few other things seem off:
for (i = 0; i < size; i++){
*newArray[i] = arrayPtr[i];
}
This might compile but I don't think it is right, I'm guessing you mean:
for (i = 0; i < size; i++){
newArray[i] = arrayPtr[i];
}
Also:
removeNumber(*& arrayPtr, number, size);
While this is technically correct, *& first returns a pointer reference, then turns around and dereferences it again. I wouldn't be surprised if the compiler optimizes it away anyway, but it is unnecessary.
I have a Deck object (deck of cards) which is a double-ended queue implemented as a doubly-linked list. I would like to be able to shuffle the queue at will, but the way I would go about it is beyond me. So instead I've opted to pre-shuffle an array a pointers to the cards and enqueue them after the fact. Problem is, the code I have now doesn't seem to be initializing the pointers at all.
void BuildDeck(Deck* deck) {
Card** cards = new Card*[20];
const size_t MAX_INTEGER_LENGTH = sizeof(int) * 4;
char szPostfix[] = "_Card.bmp";
for(int i = 1; i < 21; i++) {
char path[MAX_INTEGER_LENGTH + sizeof(szPostfix) + 1];
sprintf(path,"%d%s",i, szPostfix);
cards[i-1] = new Card(i,path);
}
ShuffleArray(cards);
for (int i = 0; i < 20; i++) {
deck->PushTop(cards[i]);
}
}
void Swap(Card* a, Card* b) {
Card temp = *a;
*a = *b;
*b = temp;
}
void ShuffleArray(Card** cardArray) {
srand(dbTimer());
for (int i = 0; i < 20; i++)
Swap(cardArray[i],cardArray[rand()%20]);
}
I think where I screwed up is in the card[i] = new Card(...) line, but it somehow looks right to me.
Any suggestions would be appreciated.
DISCLAIMER: I know I should be using the standard library for most of this stuff, but I'm trying to teach myself the hard stuff first. It's just the way I learn.
EDIT: I fixed the index problem. Now I've just gotta figure out why some image aren't drawing now... :/ Thanks for the help!
Your code has many problems
You are looping with 1 <= i <= 20 but for an array of 20 elements indexing goes from 0 <= index <= 19. You need to use cards[i-1] = new Card(i,path);
You are allocating the array of pointers cards but you are not deallocating it (memory leak). Either deallocate it with delete[] cards; once you are done or just use a stack based array with Card *cards[20]; instead of allocating it with new.
The way you compute MAX_INTEGER_LENGTH shows you don't really understand what sizeof does.
This is the reason for which the cards don't get shuffled. You wrote a function that swaps two pointers, but the pointers it is swapping are local variables (parameters) of the function, not the elements of the array. One solution is to pass the parameters as pointer references by declaring swap with void Swap(Card *& a, Card *& b), another solution would be passing pointers to pointers (but this would require a more complex syntax of the implementation because of the double indirection and would also require a change in the way you call the function).
In the first for loop your starting index is 0, while in the second for loop the starting index is 0. That could be the problem.
Your code:
for(int i = 1; i < 21; i++) {
char path[MAX_INTEGER_LENGTH + sizeof(szPostfix) + 1];
sprintf(path,"%d%s",i, szPostfix);
cards[i] = new Card(i,path);
}
Here the loop should start from 0 to 20 as:
for(int i = 1 ; i < 21; i++) //incorrect - original code
for(int i = 0 ; i < 20; i++) //correct - fix
And after the fix, you could use i+1 instead of i in :
sprintf(path,"%d%s",i+1, szPostfix);
cards[i] = new Card(i+1,path);
if that is required.