I need some help since I'm new to c++, I have a homework question where we should read a name to a char[] and then place that input inside a dynamic array, sort the dynamic array, and then terminate the allocated memory. We have to work with a half-done written program and I don't think I'm getting the input incorrectly in the dynamic array and I have a problem with deallocating memory could someone help with some tips maybe? My contribution to the code is highlighted in ** ** thanks!
const int BUFLEN = 100; // Max length of reading buffer
void sort(char* friendList[], int n); // n is the number of elements
void print(char* friendList[], int n); // n is the number of elements
void terminate(char* friendList[], int n); // n is the number of elements
const int AMOUNT = 5;
int main()
{
char* friends[AMOUNT]; // Dynamic array with AMOUNT pcs of string pointers
char buff[BUFLEN] = { "" }; // Creates a string buffer (null terminated)
int count = 0;
while (count < AMOUNT) // enter AMOUNT number of friends
{
cout << "Name a friend: ";
cin.getline(buff, BUFLEN); // Temporary reading into string buffer
friends[count] = **new char[AMOUNT];** //. . . WRITE CODE allocating memory to the string
// WRITE CODE that adds loaded name to current location in the dynamic array
**strcpy(friends[count], buff);**
++count;
}
sort(friends, count); // Sorts the ‘count’ strings
print(friends, count); // Prints the ‘count’ first names
terminate(friends, count);// Releases all allocated memory space
return 0;
}
void sort(char* friendList[], int n)
{
// WRITE FUNCTION that sorts the strings in the friendList in alphabetical order!
**int result;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
result = strcmp(friendList[j+1], friendList[j]);
if (result < 0)
swap(friendList[j+1], friendList[j]);
}
}**
}
void print(char* friendList[], int n)
{
// WRITE FUNCTION that prints ‘n’ names from the friendList on screen!
**for (int i = 0; i < n; i++)
{
cout << friendList[i] << " " << i << endl;
}**
}
void terminate(char* friendList[], int n)
{
// WRITE FUNCTION that releases all dynamically allocated memory!
**for (int i = 0; i < n; i++)
{
delete friendList[i];
}
delete [] friendList;
cout << "deleted! ";**
}
I see a few problems with this code:
In main():
not validating that cin.getline() is successful before using the contents of buff.
AMOUNT is the wrong size to use when allocating a new char[] to store in friends[]. The correct size should be either strlen(buff)+1 or cin.gcount().
In terminate() (not to be confused with std::terminate()):
delete[]'ing the input array itself, which was not allocated with new[] to begin with and thus must not be delete[]'ed.
Instead of this statement
friends[count] = new char[AMOUNT];
you need to write
friends[count] = new char[strlen( buff ) + 1];
Pay attention to that the array friends itself is not allocated dynamically. But each its element points to a dynamically allocated array. So the function terminate can look like
void terminate(char* friendList[], int n)
{
// WRITE FUNCTION that releases all dynamically allocated memory!
for (int i = 0; i < n; i++)
{
delete [] friendList[i];
friendList[i] = nullptr;
}
cout << "deleted! ";
}
I am trying to create a two dimensional dynamically allocated array who's column size is increased every time the user wants to enter an additional number in the array. That is, a new address will be assigned on the heap and returned to "arr" In my example the rows are constant. The problem is I can't dynamically allocate memory and assign integers to my array to any other row besides the first.
int allocate(int** &arr, char choice)
{
int x = 1;
int index = 0;
int row = 0;
int colCount = 0;
do
{
*(arr + index) = (new int + index);
arr[row][index] = x;
//(arr[0]+index)= new int*[index]; this fundementally does not work, cant modify left value
colCount++;
cout << x << "'s address " << &arr[row][index] << " I have " << colCount
<< " columns " << endl;
x++;
index++;
cout << "Select another number?" << endl;
cin >> choice;
} while (choice != 'n');
return colCount;
}
int main()
{
int rowCount = 3;
int colCount = 0;
int **arr = new int*[rowCount];
char choice = 'n';
colCount = allocate(arr, choice);
for (int i = 0; i < colCount; i++)
{
delete[] arr[i];
}
delete[] arr;
return 0;
}
My problem is with this line of code here
*(arr + index) = (new int + index);
while it does print out the values and addresses I allocated assigned in my function, I get a heap corruption when I try to delete the memory I assigned .Also, I can't figure out how to get the numbers to assign
Also, if I am not mistaken *(arr + index) is giving me pointers of the first column only! So I am not even sure why this is working!
Why don't you use vector<vector<int>>? Vector is a dynamic array.
I have no idea what the line *(arr + index) = (new int + index); even supposed to do.
If you want to allocate array of ints size columnSize you write it as:
int * column = new int[columnSize]
If you want to store the pointer in arr at location index then write
arr[index] = new int[columnSize]
I am not sure what you wanted to write, your code is confusing for me. Why don't you use std::vector<int>? Or std::vector<std::vector<int> >?
So This Is What I Ended up coming up with for it. I currently can't figure out how to put my reverseArray function into the main... If i just copy and paste the code into it, it crashes every time it's run... I don't know why it causes it to crash or anything. Thank you everyone that has helped me so far with this.
using namespace std;
// Prototype for printArray goes here
void reverseArray(int*, int);
void printArray(int*, int);
int main()
{
int size; // size of the dynamically allocated array
// Declare as needed for a dynamically allocated array of
ints named "data".
// Declare other variables as needed
// Edit to display your own name
cout << "" << endl << endl;
// Prompt the user for the array size
cout << "Array size: ";
cin >> size;
// Add code to validate array size, so it is greater than one
while (size < 2)
{
cout << "Array size must be greater than 1: ";
cin >> size;
}
// Add code to dynamically allocate "data". Don't forget to release the memory before
// the program ends
int *data = new int[size],
*p = data;
// Write a loop to fill the "data" array with random numbers from 1 - 100 (inclusive)
// This code must use POINTER NOTATION (no subscripting) to work with the array.
// Reminder: neither of these notations is acceptable here:
// data[n] or *(data + n)
// Instead this code will use pointer incrementing/decrementing and dereferencing
for (int i = 0; i < size; i++, p++)
{
*p = rand() % 100 + 1;
}
// Call function to print the original "data" array
cout << "\nOriginal array:\n" << endl;
printArray(data, size);
// Reset "data" to point to the beginning of the array
// Add code to reverse the array. Use 2 pointers: one starts at the beginning of the array and
// moves forward, the other starts at its last element and works backward. Swap the values they
// point to.
// Reminder: neither of these notations is acceptable here:
// data[n] or *(data + n)
// Instead this code will use pointer incrementing/decrementing and dereferencing
// For this, I made the function reverseArray instead of coding it in main.
reverseArray(data, size);
cout << endl;
cout << "\nReversed array:\n" << endl;
printArray(data, size);
cout << endl << endl;
// Finish up
delete[] data;
system("pause");
return 0;
}
// Function printArray() goes here. Print the array, 5 numbers per line,
right-aligned
void printArray(int*p, int size)
{
for (int i = 0; i < size; i++, p++)
{
cout << setw(5) << right << *p;
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
}
// Function reverseArray() Reverses the array.
void reverseArray(int *data, int size)
{
int *e = data + size - 1; // Pointer at the end
for (; e > data; data++, e--) // while end pointer (e)> start pointer, swap start w/ end
{
int arrayFlip = *data;
*data = *e;
*e = arrayFlip;
}
}
You may be torturing yourself for no reason, or beating your head into a brick wall (don't worry - we've all been there... and have the bruises to prove it.)
First, lets start with any allocated block of memory, say:
int *a = new int[NELEM], ...
What is a? (a pointer -- yes, but to what?) It is a pointer to the beginning address in a block of memory, NELEM * sizeof *a bytes in size. What type of pointer is it? (int). How many bytes per-int? (generally 4).
So why is having the pointer be type int important? (well, it sets the type-size that controls how pointer-arithmetic operates when referencing the block of memory though that pointer) Meaning since your pointer type is int, the compiler knows that a + 1 is a + 4-bytes which allows you to reference the next value in your block of memory.
OK, but I allocated memory for a, what are my responsibilities with regard to a? In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
What does that mean to me? It means that if you cannot simply increment a (e.g. a++) in the scope where a was declared. If you do, you have lost your reference to the beginning address of the block and that block can no longer be freed (that's a memory leak).
So if I cannot use any indexing (e.g. a[i] or *(a + i)) and I can't increment my pointer a -- then what are my options? Use another pointer..., e.g.
int *a = new int[NELEM],
*p = a;
...
std::cout << "array : ";
for (int i = 0; i < NELEM; i++, p++) {
*p = rand() % 100 + 1;
std::cout << std::setw(5) << *p;
}
std::cout << '\n';
Have you satisfied your responsibilities regarding the block of memory you assigned to a? Sure, a still points to the beginning address of the block, so it can be freed. All you did was use a second pointer p and iterated using p leaving a unchanged.
Hmm.. Using a second pointer.. I wonder if I can reverse my array using that same scheme. Yep. In it simplest form, you could do something like:
void rev (int *a, size_t size)
{
int *e = a + size - 1; /* end pointer */
for (; e > a; a++, e--) { /* while end > start, swap start, end */
int tmp = *a;
*a = *e;
*e = tmp;
}
}
But wait!! You said you couldn't increment a without losing the starting address to my allocated block -- how can I free it now? (a in main() never changes, the function rev receives a copy of a and within rev you are free to increment/decrement or do whatever you like to a, within the bounds of the block of memory, because a in rev has its very own (and very different) address from your original pointer in main().
(an aside...) You could have declared a third pointer within rev, e.g.
int *s = a, /* start pointer */
*e = a + size - 1; /* end pointer */
and then used s instead of a in your iteration and swap, but there isn't any need to. You are free to do it that way if it is more clear to you which pointer you are working with. It's simply another 8-bytes (or 4 on x86), so the additional storage is a non-issue.
Putting it altogether in a short example, you could do something similar to the following:
#include <iostream>
#include <iomanip>
#include <cstdlib>
#define NELEM 10
void rev (int *a, size_t size)
{
int *e = a + size - 1; /* end pointer */
for (; e > a; a++, e--) { /* while end > start, swap start, end */
int tmp = *a;
*a = *e;
*e = tmp;
}
}
int main (void) {
int *a = new int[NELEM],
*p = a;
srand (20180502);
std::cout << "array : ";
for (int i = 0; i < NELEM; i++, p++) {
*p = rand() % 100 + 1;
std::cout << std::setw(5) << *p;
}
std::cout << '\n';
rev (a, NELEM);
p = a;
std::cout << "reverse: ";
for (int i = 0; i < NELEM; i++, p++)
std::cout << std::setw(5) << *p;
std::cout << '\n';
delete[] a;
}
Example Use/Output
$ ./bin/array_reverse
array : 11 6 78 93 25 71 82 58 97 68
reverse: 68 97 58 82 71 25 93 78 6 11
All of this takes a bit of time to sink in. We all have bruises on our foreheads from the same wall. Just make peace with the fact that a pointer is just a variable that holds the address of something else as it value (e.g. it points to where something else is stored).
Understand how the type of the pointer effects the pointer-arithmetic (and indexing), e.g. how many bytes are advanced with p++ or in for (i = 0; i < size; i++) p[i], and make sure you know exactly where your pointer is pointing and things should start to fall into place.
If you ever have any problems figuring out what is going on with your pointer, pull out an 8.5 x 11 sheet of paper and a No.2 pencil and just draw it out -- on each iteration fill in the block where your pointer is pointing, etc.. -- it really helps. Once you have drawn enough diagrams, done enough linked-lists, stacks, etc... you won't need the paper as much as you do now (you will still need it -- so keep it handy)
Reversing in main() with a Function
In response to your comment, when you look at main(), you already have an additional pointer p declared. So you can simply use that as your start pointer and add e from from the rev() function as your end-pointer. A simple implementation would be:
int main (void) {
int *a = new int[NELEM],
*p = a,
*e = a + NELEM - 1;;
srand (20180502);
std::cout << "array : ";
for (int i = 0; i < NELEM; i++, p++) {
*p = rand() % 100 + 1;
std::cout << std::setw(5) << *p;
}
std::cout << '\n';
p = a; /* reset pointer */
for (; e > p; p++, e--) { /* reverse array */
int tmp = *p;
*p = *e;
*e = tmp;
}
p = a; /* reset pointer -- again */
std::cout << "reverse: ";
for (int i = 0; i < NELEM; i++, p++)
std::cout << std::setw(5) << *p;
std::cout << '\n';
delete[] a;
}
(same output)
Look things over and let me know if you have further questions.
The following lines in main are not correct.
*data = rand() % 100 + 1;
cout << setw(5) << right << *data;
They just set the value of the first element of the array and print the same element.
Use data[i] instead.
data[i] = rand() % 100 + 1;
cout << setw(5) << right << data[i];
If you must use the pointer notation, use *(data+i).
*(data+i) = rand() % 100 + 1;
cout << setw(5) << right << *(data+i);
Another method you can use is to use a temporary pointer variable just for iterating over the array.
int* iter = data;
for (int i = 0; i < size; i++. ++iter)
{
*iter = rand() % 100 + 1;
cout << setw(5) << right << *iter;
...
}
This makes sure that you don't lose the original pointer, which is necessary to be able to deallocate the memory.
PS There may be other errors, or not, but I noticed the above problem after a quick glance through your code.
Moving A Pointer
data++;
and
data--;
mostly. There are other things you could do, but your instructor asked for increment and decrement.
So
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data;
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
becomes
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data++; // change made here
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
Note only one data++, and it's on the second use of data. You should be able to figure out why.
Resetting A Pointer
The easiest and most obvious is to
int*reset = data;
then you can data around to your heart's content, and when you want to reset,
data = reset;
So the above loops wind up looking like
int*reset = data;
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data++; // change made here
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
data = reset;
But... You can also separate your logic out into functions and take advantage of pass by value
void fill(int * data,
int size)
{
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data++; // change made here
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
}
and the related part of main now looks something like
data = new int[size];
// Write a loop to fill the "data" array with random numbers from 1 - 100 (inclusive)
// This code must use POINTER NOTATION (no subscripting) to work with the array.
// Reminder: neither of these notations is acceptable here:
// data[n] or *(data + n)
// Instead this code will use pointer incrementing/decrementing and dereferencing
cout << "This is just the test to see if the pointer is successfully creating the array" << endl;
fill(data, size);
// Reset "data" to point to the beginning of the array
"Just wait a minute!" you're thinking. "How in Crom's name is int * data pass by value? That's a <expletive deleted>ing pointer!" The data pointed at is passed by reference, but the pointer itself is passed by value. data in fill is a copy of data in main. All of the data++ing in fill happens to a copy, so data in main is still pointing right where you left it.
No reset required and you've simplified main's responsibilities by spinning off part of them to their own simple and independently testable function. Keeping everything as simple, small, and stupid as possible is worth it's weight in bitcoin in my view.
So I have to implement a stack using an array built in a class, and if the "stack" ever fills up, I am supposed to increase the size of the array which I attempted, and failed. So I am just curious as to what I need to change in order to make this work.
class AbstractStack
{
private:
Type elements; // elements in the array
Type max;
Type *s;
public:
AbstractStack(Type num) { //CONSTRUCTOR
elements= -1;
this->max = num;
s = new Type[max];
}
/* bunch of code that does not apply to this issue
*/
void push ( Type e ) {
if (elements + 1 == max) {
cout << "Stack at max size, WIll increase size of array and add item" << endl;
Type *temp = new Type[max + (max/2)];
for (int i = 0; i < elements+1; i++) {
temp[i] = s[i];
}
s = temp;
delete temp;
elements++;
s[elements] ;
return;
}
else {
elements++;
s[elements] = e;
}
}
When I take the size of this new s, I get the correct size of 1 larger than before because this function is only called when trying to add 1 element to the full stack, but when I attempt to use the top function, it just gives me 0 then I get like 50 lines of error codes starting in:
*** Error in `./a.out': double free or corruption (top): 0x0000000000c53cf0 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7c619)[0x7fa34a270619]
./a.out[0x400c38]
./a.out[0x400b48]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7fa34a215c05]
./a.out[0x400979]
Type elements; // elements in the array
Type max;
These are both just ints, or unsigneds, or size_ts, or whatever you prefer for counting. They have nothing to do with Type whatsoever.
void push ( Type e ) {
if (elements + 1 == max) {
cout << "Stack at max size, WIll increase size of array and add item" << endl;
Type *temp = new Type[max + (max/2)];
After this you should increase max to max*3/2.
for (int i = 0; i < elements+1; i++) {
Loop condition should be i < elements. You are using element zero, and element[elements] does not exist yet.
temp[i] = s[i];
}
s = temp;
delete temp;
Last two lines should be delete[] s followed by s = temp.
elements++;
s[elements] ;
Last two lines should be s[elements++] = e;
return;
return is redundant here.
}
else {
elements++;
s[elements] = e;
Again, the last two lines should be s[elements++] = e;
}
}
Corrected and simplified version:
int elements;
int max;
// ...
void push ( Type e ) {
if (elements + 1 == max) {
cout << "Stack at max size, WIll increase size of array and add item" << endl;
max += max/2;
Type *temp = new Type[max];
for (int i = 0; i < elements; i++) {
temp[i] = s[i];
}
delete[] s;
s = temp;
}
s[elements++] = e;
}
You have to delete the old array (s) instead of the new (temp):
delete[] s;
s = temp;
Also: make sure that your class has a proper destructor (deleting s).
Crashes when the delete command comes around. It's supposed make a struct with pointers to arrays, fill them with random numbers, and then deallocate the memory. Works fine until the delete command, in which it crashes with our without the for loop or boolean check.
int main() {
cout << "start" << endl;
//Creating Struct
struct
{
int* ptrarray[10];
bool boolarray[10];
} data;
//Initializing Random Generator
srand ( time(NULL) );
cout << "Initializing: ";
//Allocating Memory and generating random numbers with for loops
for (int i = 0; i < 10; i++)
{
int counter = 0; //Counts numbers set
cout << i << " "; //Counting arrays initialized
data.ptrarray[i] = new int [12582912]; // Memory Allocation
for (int j = 0; j < 12582912; j++)//Number Generating
{
*data.ptrarray[i] = rand() % 899 + 100;
data.ptrarray[i]++;
counter++;
}
//Checking for failed initializations and declaring if success
if (counter == 12582912)
{
data.boolarray[i] = true;
}
else
{
data.boolarray[i] = false;
}
}
cout << endl;
//This is where it always crashes.
for (int i=0; i<10; i++)
{
if (data.boolarray[i] == true)
delete[] data.ptrarray[i];
}
cout << endl;
return 0;
}
I'm using MS Visual studio 2010.
The culprit is this line:
data.ptrarray[i]++;
You are changing the pointer, then using delete [] on the modified pointer. This will not work: you must use delete[] with the exact same pointer you got from new[].
Try
data.ptrarray[i][j] = rand() % 899 + 100;
instead so you don't have to change your pointer.
data.ptrarray[i]++; is the problem.
You're incrementing your reference to the data, but then not resetting it to the start before trying to delete it.
Your problem lies with:
data.ptrarray[i]++;
This is modifying the pointer. When you then attempt to free that modified pointer, it crashes.
You can solve this by using a copy of the pointer to run through the array, or by indexing with thej variable as well:
data.ptrarray[i][j]