I am working on a program in c++ in which the user can add phone numbers to a list. For this assignment, we have to use pointers while dynamically allocating the memory needed. The code below works fine, except for the fact that when the program lists the elements in the pointer, random numbers are spit out. I'm new to c++ so any ways I could be pointed into the right direction of fixing this issue are greatly appreciated.
int *FirstArray = new int(size);
int *SecondArray = new int(size + 1);
if (size == 0) {
cout << "Please enter the number which you would like to add";
cin >> FirstArray[size];
for (int x = 0; x <= size; x++) {
cout << x << ". " << FirstArray[x] << endl;
}
for (int x = 0; x <= size; x++) {
FirstArray[x] = SecondArray[x];
}
SecondArray = FirstArray;
delete (FirstArray);
}
else {
cout << "Please enter the number which you would like to add";
cin >> SecondArray[size];
for (int x = 0; x <= size; x++) {
cout << x + 1 << ". " << SecondArray[x] << endl;
}
}
size++;
Apart from the fact that a std::vector would be really the better choice for such application I think learning about pointers is a good starting point to understand why the usage of std-containers is better.
The whole if(size==0)-block in your code snippet is unsafe as well as the else-scope in further consequence because FirstArray[x] reads from memory which is not allocated at least for every x > 0.
So called segmentation faults are then very likely in such cases though such may be defered in case of debugger friendly memory layout or other reasons.
Besides the fact that you then never had really a list but just two values refered by two single-element arrays (or just pointers) it's then clear why you get only random numbers from the memory pointed to by the pointers.
A pointer in C (or C++) is not restricting the access to succeeding elements behind the first element.
This means, that pointers can be used for either single values (which is exactly the same as an array with size == 1) and arrays with more than one element.
Some more issues...
Use new int[] rather than new int() because in this context curved brackets () is understood as argument list to the compiler generated 'constructor' of the data type 'int' which in case of int() just sets the value. C++ is consequently applying its type paradigms to primitive types as well and not only classes. See another SO article on this topic
Using new int[size] instead does what you want. It allocates memory for an integer array with 'size' elements and returns the pointer to the first element.
I think you do not need a SecondArray. A statement like "SecondArray = FirstArray" is anyway not copying the elements. It's copying the pointers and leaving the memory allocated to SecondArray behind as a memory leak.
Deleting then FirstArray with "delete (FirstArray)" makes it even worse because then you delete FirstArray and SecondArray at once because both point to the same memory location and any further access to SecondArray would be dangerous (segfault etc.)
Incrementing size++ at the end is as well in vain (if I got your idea right) because the size should be clear before you allocate and access the memory, not afterwards.
Resizing the array in case that 'size' changes can be done either by calling new(FirstArray)[size] (which is seldomly used directly but common in std-containers) or by consequently giving up using C++ and switching to the ANSI C style with malloc() for initial allocation, realloc() for resizing, memcpy() for copying/assignment and finally free() for deallocation. But switching to ANSI C style in this case doesn't mean that you are not allowed to use it in a C++ context. BTW, in most standard C++ frameworks the new-operator and the delete-operator call malloc() and free() behind the scenes.
At the end of the day, using std::vector<> can make life MUCH easier ;-)
Related
I am trying to learn C++, I have a fair bit of experience in C# and the 2 languages are so dissimilar and I am having trouble understanding data types and pointer variants of data types and the initialization of them, please consider the code below:
wchar_t *array = new wchar_t[10]; //Declaring a pointer of wchart_t and initializing to a wchar_t array of size 10 ?
auto memAddressOfPointer = &array; //auto is resolving memAddressOfPointer to a pointer of a pointer?
cout << array << endl; //Printing the memory address of array not the object created above?
cout << *array << endl; //Getting the actual value of the object (empty wchar_t array of size 10 in bytes?
cout << &array << endl; //Printing the address of the obj?
cout << memAddressOfPointer << endl; //Printing the address of the obj ?
My question is why would I create a pointer and initialize it? Why not just create an array of wchar_t? like:
wchar_t array [10];
I refer to this stack post as well:
Unable to create an array of wchar_t
Thank you for your consideration.
If you know the size of the number of elements you need to put in the array, then just use the array i.e., wchar_t arr[10];.
If you don't know the size, you can create the array at runtime using dynamic memory allocation with the required size i.e., wchar_t *arr = new wchar_t[required_size]. Once the memory is allocated, you need to deallocate it using delete[] operator for arrays and delete for non-array pointers. However I highly recommend you don't do that and instead either
Use std::wstring in this particular case which will automatically handle this for you.
Use std::vector for everything else if you can. It's a dynamic array which will grow automatically. No manual memory management etc.
In case you have to use pointers, use a smart pointer like unique_ptr or shared_ptr. The advantage of using smart pointers is that they will automatically clean up once they go out of scope.
If you know the extent of the array when writing the program, there's absolutely nothing wrong with wchar_t array [10];. If 10 is a fixed (constexpr) number - stick with that.
What wchar_t *array = new wchar_t[10]; lets you do is to let 10 be a number that you find out in run-time. You can change 10 to x and let x be a number that the user supplies or that you calculate somehow. wchar_t array [x]; when x is not a constexpr is on the other hand not valid C++ (but is available as an exension, called VLA, in some implementations).
Note: One downside with using new is that you need to make sure you delete the same pointer. This is not always simple. Using these raw pointers is therefore not what you usually want to do. Instead, use a smart pointer, like std::unique_ptr<wchar_t[]>, and the resource will be delete[]d when the pointer goes out of scope.
The advantages of creating a pointer instead of an array are the dynamic allocation that you can take advantage of and also the properties of the pointer that might help.
Consider the following code that represent the dynamic allocation and reallocation:
int x;
cin >> x;
int *oldArr = malloc(x * sizeof(int));
for(int i = 0; i < x; i++)
arr[i] = i;
cin >> x;
arr = realloc(arr, x * sizeof(int));
Here is another example that shows one of the pointer features which also you can use along with arrays.
int arr[5] = {1, 2, 3, 4 ,5};
int *ptr = arr;
cout << *ptr;
ptr++;
cout << *ptr;
cout << *(ptr + 1);
Despite these advantages and others, I think that the example you are presenting of using pointers instead of arrays is just for academic purposes to understand how to work with pointers in order to build more complex data structures using pointers in future lessons as you are using constant size arrays.
Everything seems to run okay up until the return part of shuffle_array(), but I'm not sure what.
int * shuffle_array(int initialArray[], int userSize)
{
// Variables
int shuffledArray[userSize]; // Create new array for shuffled
srand(time(0));
for (int i = 0; i < userSize; i++) // Copy initial array into new array
{
shuffledArray[i] = initialArray[i];
}
for(int i = userSize - 1; i > 0; i--)
{
int randomPosition = (rand() % userSize;
temp = shuffledArray[i];
shuffledArray[i] = shuffledArray[randomPosition];
shuffledArray[randomPosition] = temp;
}
cout << "The numbers in the initial array are: ";
for (int i = 0; i < userSize; i++)
{
cout << initialArray[i] << " ";
}
cout << endl;
cout << "The numbers in the shuffled array are: ";
for (int i = 0; i < userSize; i++)
{
cout << shuffledArray[i] << " ";
}
cout << endl;
return shuffledArray;
}
Sorry if spacing is off here, not sure how to copy and past code into here, so I had to do it by hand.
EDIT: Should also mention that this is just a fraction of code, not the whole project I'm working on.
There are several issues of varying severity, and here's my best attempt at flagging them:
int shuffledArray[userSize];
This array has a variable length. I don't think that it's as bad as other users point out, but you should know that this isn't allowed by the C++ standard, so you can't expect it to work on every compiler that you try (GCC and Clang will let you do it, but MSVC won't, for instance).
srand(time(0));
This is most likely outside the scope of your assignment (you've probably been told "use rand/srand" as a simplification), but rand is actually a terrible random number generator compared to what else the C++ language offers. It is rather slow, it repeats quickly (calling rand() in sequence will eventually start returning the same sequence that it did before), it is easy to predict based on just a few samples, and it is not uniform (some values have a much higher probability of being returned than others). If you pursue C++, you should look into the <random> header (and, realistically, how to use it, because it's unfortunately not a shining example of simplicity).
Additionally, seeding with time(0) will give you sequences that change only once per second. This means that if you call shuffle_array twice quickly in succession, you're likely to get the same "random" order. (This is one reason that often people will call srand once, in main, instead.)
for(int i = userSize - 1; i > 0; i--)
By iterating to i > 0, you will never enter the loop with i == 0. This means that there's a chance that you'll never swap the zeroth element. (It could still be swapped by another iteration, depending on your luck, but this is clearly a bug.)
int randomPosition = (rand() % userSize);
You should know that this is biased: because the maximum value of rand() is likely not divisible by userSize, you are marginally more likely to get small values than large values. You can probably just read up the explanation and move on for the purposes of your assignment.
return shuffledArray;
This is a hard error: it is never legal to return storage that was allocated for a function. In this case, the memory for shuffledArray is allocated automatically at the beginning at the function, and importantly, it is deallocated automatically at the end: this means that your program will reuse it for other purposes. Reading from it is likely to return values that have been overwritten by some code, and writing to it is likely to overwrite memory that is currently used by other code, which can have catastrophic consequences.
Of course, I'm writing all of this assuming that you use the result of shuffle_array. If you don't use it, you should just not return it (although in this case, it's unlikely to be the reason that your program crashes).
Inside a function, it's fine to pass a pointer to automatic storage to another function, but it's never okay to return that. If you can't use std::vector (which is the best option here, IMO), you have three other options:
have shuffle_array accept a shuffledArray[] that is the same size as initialArray already, and return nothing;
have shuffle_array modify initialArray instead (the shuffling algorithm that you are using is in-place, meaning that you'll get correct results even if you don't copy the original input)
dynamically allocate the memory for shuffledArray using new, which will prevent it from being automatically reclaimed at the end of the function.
Option 3 requires you to use manual memory management, which is generally frowned upon these days. I think that option 1 or 2 are best. Option 1 would look like this:
void shuffle_array(int initialArray[], int shuffledArray[], int userSize) { ... }
where userSize is the size of both initialArray and shuffledArray. In this scenario, the caller needs to own the storage for shuffledArray.
You should NOT return a pointer to local variable. After the function returns, shuffledArray gets deallocated and you're left with a dangling pointer.
You cannot return a local array. The local array's memory is released when you return (did the compiler warn you about that). If you do not want to use std::vector then create yr result array using new
int *shuffledArray = new int[userSize];
your caller will have to delete[] it (not true with std::vector)
When you define any non static variables inside a function, those variables will reside in function's stack. Once you return from function, the function's stack is gone. In your program, you are trying to return a local array which will be gone once control is outside of shuffle_array().
To solve this, either you need to define the array globally (which I won't prefer because using global variables are dangerous) or use dynamic memory allocation for the array which will create space for the array in heap rather than allocating the space on the function's stack. You can use std::vectors also, if you are familiar with vectors.
To allocate memory dynamically, you have to use new as mentioned below.
int *shuffledArray[] = new int[userSize];
and once you completed using shuffledArray, you need to free the memory as below.
delete [] shuffledArray;
otherwise your program will leak memory.
Why does the new[] operator in C++ actually create an array of length + 1? For example, see this code:
#include <iostream>
int main()
{
std::cout << "Enter a positive integer: ";
int length;
std::cin >> length;
int *array = new int[length]; // use array new. Note that length does not need to be constant!
//int *array;
std::cout << "I just allocated an array of integers of length " << length << '\n';
for (int n = 0; n<=length+1; n++)
{
array[n] = 1; // set element n to value 1
}
std::cout << "array[0] " << array[0] << '\n';
std::cout << "array[length-1] " << array[length-1] << '\n';
std::cout << "array[length] " << array[length] << '\n';
std::cout << "array[length+1] " << array[length+1] << '\n';
delete[] array; // use array delete to deallocate array
array = 0; // use nullptr instead of 0 in C++11
return 0;
}
We dynamically create an array of length "length" but we are able to assign a value at the index length+1. If we try to do length+2, we get an error.
Why is this? Why does C++ make the length = length + 1?
It doesn’t. You’re allowed to calculate the address array + n, for the purpose of checking that another address is less than it. Trying to access the element array[n] is undefined behavior, which means the program becomes meaningless and the compiler is allowed to do anything whatsoever. Literally anything; one old version of GCC, if it saw a #pragma directive, started a roguelike game on the terminal. (Thanks, Revolver_Ocelot, for reminding me: that was technically implementation-defined behavior, a different category.) Even calculating the address array + n + 1 is undefined behavior.
Because it can do anything, the particular compiler you tried that on decided to let you shoot yourself in the foot. If, for example, the next two words after the array were the header of another block in the heap, you might get a memory-corruption bug. Or maybe a compiler stored the array at the top of your memory space, the address &array[n+1] is aNULL` pointer, and trying to dereference it causes a segmentation fault. Or maybe the next page of memory is not readable or writable and trying to access it crashes the program with a protection fault. Or maybe the implementation bounds-checks your array accesses at runtime and crashes the program. Maybe the runtime stuck a canary value after the array and checks later to see if it was overwritten. Or maybe it happens, by accident, to work.
In practice, you really want the compiler to catch those bugs for you instead of trying to track down the bugs that buffer overruns cause later. It would be better to use a std::vector than a dynamic array. If you must use an array, you want to check that all your accesses are in-bounds yourself, because you cannot rely on the compiler to do that for you and skipping them is a major cause of bugs.
If you write or read beyond the end of an array or other object you create with new, your program's behaviour is no longer defined by the C++ standard.
Anything can happen and the compiler and program remain standard compliant.
The most likely thing to happen in this case is you are corrupting memory in the heap. In a small program this "seems to work" as the section of the heap ypu use isn't being used by any other code, in a larger one you will crash or behave randomly elsewhere in a seemingoy unrelated bit of code.
But arbitrary things could happen. The compiler could prove a branch leads to access beyond tue end of an array and dead-code eliminate paths that lead to it (UB that time travels), or it could hit a protected memory region and crash, or it could corrupt heap management data and cause a future new/delete to crash, or nasal demons, or whatever else.
At the for loop you are assigning elements beyond the bounds of the loop and remember that C++ does not do bounds checking.
So when you initialize the array you are initializing beyond the bounds of the array (Say the user enters 3 for length you are initializing 1 to array[0] through array[5] because the condition is n <= length + 1;
The behavior of the array is unpredictable when you go beyond its bounds, but most likely your program will crash. In this case you are going 2 elements beyonds its bounds because you have used = in the condition and length + 1.
There is no requirement that the new [] operator allocate more memory than requested.
What is happening is that your code is running past the end of the allocated array. It therefore has undefined behaviour.
Undefined behaviour means that the C++ standard imposes no requirements on what happens. Therefore, your implementation (compiler and standard library, in this case) will be equally correct if your program SEEMS to work properly (as it does in your case), produces a run time error, trashes your system drive, or anything else.
In practice, all that is happening is that your code is writing to memory, and later reading from that memory, past the end of the allocated memory block. What happens depends on what is actually in that memory location. In your case, whatever happens to be in that memory location is able to be modified (in the loop) or read (in order to print to std::cout).
Conclusion: the explanation is not that new[] over-allocates. It is that your code has undefined behaviour, so can seem to work anyway.
I have been struggling in finding an explanation to an error I get in the following code:
#include <stdlib.h>
int main() {
int m=65536;
int n=65536;
float *a;
a = (float *)malloc(m*n*sizeof(float));
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
a[i*n + j] = 0;
}
}
return 0;
}
Why do I get an "Access Violation" Error when executing this program?
The memory allocation is succesful, the problem is in the nested for loops at some iteration count. I tried with a smaller value of m&n and the program works.
Does this mean I ran out of memory?
The problem is that m*n*sizeof(float) is likely an overflow, resulting in a relatively small value. Thus the malloc works, but it does not allocate as much memory as you're expecting and so you run off the end of the buffer.
Specifically, if your ints are 32 bits wide (which is common), then 65336 * 65336 is already an overflow, because you would need at least 33 bits to represent it. Signed integer overflows in C++ (and I believe in C) result in undefined behavior, but a common result is that the most significant bits are lopped off, and you're left with the lower ones. In your case, that gives 0. That's then multiplied by sizeof(float), but zero times anything is still zero.
So you've tried to allocate 0 bytes. It turns out that malloc will let you do that, and it will give back a valid pointer rather than a null pointer (which is what you'd get if the allocation failed). (See Edit below.)
So you have a valid pointer, but it's not valid to dereference it. That fact that you are able to dereference it at all is a side-effect of the implementation: In order to generate a unique address that doesn't get reused, which is what malloc is required to do when you ask for 0 bytes, malloc probably allocated a small-but-non-zero number of bytes. When you try to reference far enough beyond those, you'll typically get an access violation.
EDIT:
It turns out that what malloc does when requesting 0 bytes may depend on whether you're using C or C++. In the old days, the C standard required a malloc of 0 bytes to return a unique pointer as a way of generating "special" pointer values. In modern C++, a malloc of 0 bytes is undefined (see Footnote 35 in Section 3.7.4.1 of the C++11 standard). I hadn't realized malloc's API had changed in this way when I originally wrote the answer. (I love it when a newbie question causes me to learn something new.) VC++2013 appears to preserve the older behavior (returning a unique pointer for an allocation of 0 bytes), even when compiling for C++.
You are victim of 2 problems.
First the size calculation:
As some people have pointned out, you are exceeding the range of size_t. You can verify the size that you are trying to allocate with this code:
cout << "Max size_t is: " << SIZE_MAX<<endl;
cout << "Max int is : " << INT_MAX<<endl;
long long lsz = static_cast<long long>(m)*n*sizeof(float); // long long to see theoretical result
size_t sz = m*n*sizeof(float); // real result with overflow as will be used by malloc
cout << "Expected size: " << lsz << endl;
cout << "Requested size_t:" << sz << endl;
You'll be surprised but with MSVC13, you are asking 0 bytes because of the overflow (!!). You might get another number with a different compiler (resulting in a lower than expected size).
Second, malloc() might return a problem pointer:
The call for malloc() could appear as successfull because it does not return nullptr. The allocated memory could be smaller than expected. And even requesting 0 bytes might appear as successfull, as documented here: If size is zero, the return value depends on the particular library implementation (it may or may not be a null pointer), but the returned pointer shall not be dereferenced.
float *a = reinterpret_cast<float*>(malloc(m*n*sizeof(float))); // prefer casts in future
if (a == nullptr)
cout << "Big trouble !"; // will not be called
Alternatives
If you absolutely want to use C, prefer calloc(), you'll get at least a null pointer, because the function notices that you'll have an overflow:
float *b = reinterpret_cast<float*>(calloc(m,n*sizeof(float)));
But a better approach would be to use the operator new[]:
float *c = new (std::nothrow) float[m*n]; // this is the C++ way to do it
if (c == nullptr)
cout << "new Big trouble !";
else {
cout << "\nnew Array: " << c << endl;
c[n*m-1] = 3.0; // check that last elements are accessible
}
Edit:
It's also subject to the size_t limit.
Edit 2:
new[] throws bad_alloc exceptions when there is a problem, or even bad_array_new_length. You could try/catch these if you want. But if you prefer to get nullptr when there's not enough memory, you have to use (std::nothrow) as pointed out in the comments by Beat.
The best approach for your case, if you really need these huge number of floats, would be to go for vectors. As they are also subject to size_t limitation, but as you have in fact a 2D array, you could use vectors of vectors (if you have enough memory):
vector <vector<float>> v (n, vector<float>(m));
In C++, I understand that the delete operator, when used with an array, 'destroys' it, freeing the memory it used. But what happens when this is done?
I figured my program would just mark off the relevant part of the heap being freed for re-usage, and continue on.
But I noticed that also, the first element of the array is set to null, while the other elements are left unchanged. What purpose does this serve?
int * nums = new int[3];
nums[0] = 1;
nums[1] = 2;
cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;
delete [] nums;
cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;
Two things happen when delete[] is called:
If the array is of a type that has a nontrivial destructor, the destructor is called for each of the elements in the array, in reverse order
The memory occupied by the array is released
Accessing the memory that the array occupied after calling delete results in undefined behavior (that is, anything could happen--the data might still be there, or your program might crash when you try to read it, or something else far worse might happen).
The reasons for it being NULL are up to the heap implementation.
Some possible reasons are that it is using the space for it's free-space tracking. It might be using it as a pointer to the next free block. It might be using it to record the size of the free block. It might be writing in some serial number for new/delete debug tracking.
It could just be writing NULL because it feels like it.
Whenever someone says int* nums = new int[3], the runtime system is required to store the number of objects, 3, in a place that can be retrieved knowing only the pointer, nums. The compiler can use any technique it wants to use, but there are two popular ones.
The code generated by nums = new int[3] might store the number 3 in a static associative array, where the pointer nums is used as the lookup key and the number 3 is the associated value. The code generated by delete[] nums would look up the pointer in the associative array, would extract the associated size_t, then would remove the entry from the associative array.
The code generated by nums = new int[3] might allocate an extra sizeof(size_t) bytes of memory (possibly plus some alignment bytes) and put the value 3 just before the first int object. Then delete[] nums would find 3 by looking at the fixed offset before the first int object (that is, before *num) and would deallocate the memory starting at the beginning of the allocation (that is, the block of memory beginning the fixed offset before *nums).
Neither technique is perfect. Here are a few of the tradeoffs.
The associative array technique is slower but safer: if someone forgets the [] when deallocating an array of things, (a) the entry in the associative array would be a leak, and (b) only the first object in the array would be destructed. This may or may not be a serious problem, but at least it might not crash the application.
The overallocation technique is faster but more dangerous: if someone says delete nums where they should have said delete[] nums, the address that is passed to operator delete(void* nums) would not be a valid heap allocation—it would be at least sizeof(size_t) bytes after a valid heap allocation. This would probably corrupt the heap. - C++ FAQs