Having trouble with arrays and pointers - c++

I currently reading a book to refreshing my memory on c++. The chapter I'm on has to do with dynamic memory allocation. I doing a practice problem and I'm having some trouble figuring out what is wrong with my program. The question is
"Write a program that lets users keep track of the last time they talked to each of their friends. Users should be able to add new friends (as many as they want!) and store the number of days ago that they last talked to each friend. Let users update this value (but don't let them put in bogus numbers like negative values). Make it possible to display the list sorted by the names of the friends of by how recently it was since they talked to each friend."
For now I'm just trying to get the program to store the user's input correctly.
It crashes after I enter 5 friends so I'm guessing its writing over the array but the Resize function should take care of that.
He is my code
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
struct Friend
{
string friends;
int days;
};
Friend Resize(Friend* p_array, int* size_of_array);
int main()
{
struct Friend f;
int quit = 1;
int array_size = 5;
int number_of_friends = 0;
Friend *p_array = new Friend [array_size];
while(quit != 0)
{
cout << "Enter a friends name.\n";
cin >> f.friends;
cout << "Enter the number of days sence you last saw them.\n";
cin >> f.days;
cout << "Enter '0' to quit the program.\n";
cin >> quit;
if(array_size == number_of_friends)
{
Resize(p_array, &array_size);
}
p_array[number_of_friends] = f;
number_of_friends++;
}
//print the array
cout << endl;
for(int i = 0; i < sizeof(p_array); i++)
{
cout << p_array[i].friends << " " << p_array[i].days << endl;
}
//delete the array
delete [] p_array;
return 0;
}
Friend Resize(Friend* p_array, int* size_of_array)
{
*size_of_array *= 2;
Friend *p_new_array = new Friend [*size_of_array];
for(int i = 0; i < *size_of_array; i++)
{
p_new_array[i] = p_array[i];
}
delete [] p_array;
p_array = p_new_array;
}

p_array = p_new_array;
This will assign the local Friend* parameter to p_new_array.
Therefor
p_array[number_of_friends] = f;
is an access to an invalid object.
Declare Resize as
Friend Resize(Friend** p_array, int* size_of_array)
or
Friend Resize(Friend*& p_array, int* size_of_array)
to solve this issue.

The crash is due to the resize function.
The following line causes the crash:
for(int i = 0; i < *size_of_array; i++)
{
p_new_array[i] = p_array[i];
}
You have doubled the size of size_of_array, but p_array has only 5 elements. So this means that you step out of bounds here.

The problem is that although your resize code is kind of OK, it only changes the pointer inside the Resize function. The pointer in main never gets changed at all. The other error is that you double the size_of_array variable before you copy the array, so you end up copying elements from the old array that don't exist.
Change your function like this
Friend* Resize(Friend* p_array, int* size_of_array)
{
Friend *p_new_array = new Friend [*size_of_array * 2];
for(int i = 0; i < *size_of_array; i++)
{
p_new_array[i] = p_array[i];
}
delete [] p_array;
*size_of_array *= 2;
return p_new_array;
}
And then in main use it like this
if(array_size == number_of_friends)
{
p_array = Resize(p_array, &array_size);
}
This way the Resize function returns the new array, and you assign it to the p_array variable in main.,

Related

Dynamically allocated array C++ reads a sentence and prints the words

On the input we get a sentence which we read until EOF. We need to add single words to dynamic array and then write them one on each line.
Input: Hello this, is an example.
Output:
Hello
this,
is
an
example
I have the following code and I can't figure out why it doesn't even add anything to the array.
#include <iostream>
#include <string>
using namespace std;
void addToArray(string newWord, string myArray[], int& arrayLength)
{
string * tempArray = new string[arrayLength + 1];
tempArray[arrayLength] = newWord;
for (int i = 0; i < arrayLength; ++i)
{
myArray[i] = tempArray[i];
}
arrayLength++;
myArray = tempArray;
delete [] tempArray;
}
int main()
{
string * arrayOfWOrds = new string[1000];
int arrayLength = 0;
string temp;
while (getline(cin, temp))
{
cout << temp << endl;
addToArray(temp, arrayOfWOrds, arrayLength);
}
cout << "Array" << endl;
for (int i = 0; i < arrayLength; ++i)
{
cout << arrayOfWOrds[i] << endl;
}
}
It's because you don't return the new array from the addToArray function. The change you make only happens in addToArray, it doesn't happen in main.
You also delete[] the wrong array, you delete the array you've just created.
You also copy the array elements in the wrong direction, i.e. from your new array to your old array.
Try this, I've renamed some of the variables for clarity. There is no temporary array in your function only a new array and an old array. Choosing good variable names is very important for writing working code. Bad variable names just confuse yourself.
string* addToArray(string newWord, string* oldArray, int& arrayLength)
{
string * newArray = new string[arrayLength + 1];
newArray[arrayLength] = newWord;
for (int i = 0; i < arrayLength; ++i)
{
newArray[i] = oldArray[i];
}
arrayLength++;
delete [] oldArray;
return newArray;
}
Then use it like this
arrayOfWOrds = addToArray(temp, arrayOfWOrds, arrayLength);
I see several issues here. To begin with, you set arrayLength = 0, so it's not going to iterate over the whole array if you have stuff already in it. If you don't have anything in it, there's no point in making it start off with 1000 items. Also, while (getline(cin,temp)) is an infinite loop, so it will never end and actually print the array. If you want to print the array after each addition, you need to move it into the while loop. There's no real reason to cout the number the user types either; they can already see the line they just typed.
More importantly, there are real issues with the dynamic allocation. You've created a static array (string * arrayOfWOrds = new string[1000];), then you're giving that to the function which makes a new array one item larger, sets the last item in that array to the new value, then iterates over the entire new array and duplicates the values to the old array. Basically, you're just inserting items into the static array at that point, and what you're inserting is a bunch of nothing (because the new array only has one item in it, and it's at arrayLength+1 which is outside the bounds of the original array).
You need to delete the old array, not the new array, which actually should be thrown on the heap and returned.
Basically, it should look more like this:
#include <iostream>
#include <string>
using namespace std;
string* addToArray(string newWord, string myArray[], int& arrayLength)
{
string * returnArray = new string[arrayLength + 1];
returnArray[arrayLength] = newWord;
for (int i = 0; i < arrayLength; ++i)
{
returnArray[i] = myArray[i];
}
arrayLength++;
delete [] myArray;
return returnArray;
}
int main()
{
const int startSize = 0;
string * arrayOfWords = new string[1];
int arrayLength = startSize;
string temp;
cout << "Input: ";
getline(cin, temp);
string word = "";
for (char c : temp){
if (c == ' '){
arrayOfWords = addToArray(word, arrayOfWords, arrayLength);
word = "";
} else word.push_back(c);
}
arrayOfWords = addToArray(word, arrayOfWords, arrayLength); // Don't forget the last word
for (int i = 0; i < arrayLength; ++i)
{
cout << arrayOfWords[i] << endl;
}
}
The array is unchanged, because you pass the pointer to the addToArray function, but it has no way to pass the new pointer back. You can fix this by changing the signature of the function to
void addToArray(string newWord, string *myArray[], int& arrayLength)
You also need to change the code accordingly, and fix problem with deallocation.
You can save yourself all the trouble and use std::vector in place of manually allocated dynamic array:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<string> arrayOfWOrds;
string temp;
while (getline(cin, temp))
{
cout << temp << endl;
arrayOfWOrds.push_back(temp);
}
cout << "Array" << endl;
for (size_t i = 0; i < arrayOfWOrds.size(); ++i)
{
cout << arrayOfWOrds[i] << endl;
}
}
string in="dasd adas ads adsada adsa asd ads",out;
stringstream ss(in);
vector<string> vr;
while(ss>>out)
{
vr.push_back(out);
//cout<<out<<endl;
}
for(int i=0;i<vr.length();i++)
{
cout<<vr[i]<<endl;
}
try doing this

C++ beginner declaring a function involving array of structures

There is a few lines of my code that I would like to define as a function because I plan to use it multiple times. portion of code is as follows:
// loop within loop used to reorder with highest price at the top
for(i=0;i<x;i++){
for(t=i;t<x;t++){
if(f[i].price < f[t].price) {
temp = f[i].price;
f[i].price = f[t].price;
f[t].price = temp;
}
}
}
I hope to be able to enter new values for x and f each time I call the function. I have included all of my code below. If I'm unclear about my objective in anyway please feel free to ask. I apologize in advance for the improper terminology I am new to this. Thank you
#include <iostream>
using namespace std;
struct List
{
char name[10];
int price;
};
int main()
{
//x represents number of structures within array!
int x;
cout << "How many items would you like to list under the fruit menu?\n";
cin >> x;
//array of structures fruit
struct List f[x];
int i;
//input values into structure
for (i = 0; i < x; i++) {
cout << "\nEnter fruit name, and price.\n";
cin >> f[i].name;
cin >> f[i].price;
};
//variables for reordering
int temp;
int t;
// loop within loop used to reorder with highest price at the top
for(i=0;i<x;i++){
for(t=i;t<x;t++){
if(f[i].price < f[t].price) {
temp = f[i].price;
f[i].price = f[t].price;
f[t].price = temp;
}
}
}
//Output of menus
//fruit Menu
cout << "\n\nFruit Menu";
for (i = 0; i < x; i++) {
cout << "\n" << f[i].name << " $" << f[i]. price;
};
return 0;
}
I suppose it is an assignment that says "implement your own sort function for sorting an array of fruits", so I take the data structure "array of fruits" as given. You can, of course, change this to vector<struct Fruit> as well, but that's a different topic.
Maybe the following fragments help you finishing your code. It contains functions for entering, sorting, and printing the array with some samples how to deal with the parameters and the calls. You'll have to finalise the code.
Have fun!
#include <iostream>
using namespace std;
struct Fruit
{
char name[10];
int price;
};
// enter up to nrOfFruis; return number of fruits actually entered
int enterFruits(struct Fruit *fruits, int maxNrOfFruits) {
int entered = 0;
while (entered < maxNrOfFruits) {
cin >> fruits[entered].name;
entered++;
}
return entered;
}
void sortFruits(struct Fruit* fruits, int nrOfFruits) {
// your sort code goes here
// example for swaping two elements:
Fruit temp = fruits[0];
fruits[0] = fruits[1];
fruits[1] = temp;
}
void printFruits(struct Fruit *fruits, int nrOfFruits) {
cout << "\n\nFruit Menu";
for (int i = 0; i < nrOfFruits; i++) {
cout << "\n" << fruits[i].name << " $" << fruits[i]. price;
};
}
int main()
{
// Your task: put a proper loop and exit condition arround the following lines...
int x;
cout << "How many items would you like to list under the fruit menu?\n";
cin >> x;
struct Fruit fruits[x];
int entered = enterFruits(fruits, x);
sortFruits(fruits, entered);
printFruits(fruits, entered);
return 0;
}
You cannot allocate an array on the stack if you do not know it's size at compile time. Therefore, you need to dynamically allocate memory for it(you also need to remember to delete it):
//x represents number of structures within array!
int x;
cout << "How many items would you like to list under the fruit menu?\n";
cin >> x;
//array of structures fruit
struct List * f = new List[x];
//...
delete [] f;
Alternatively, you could do it the C++ way, using vector, having the vector elements on the stack:
int x;
std::cin>>x;
std::vector<A> v(x);
for( size_t i = 0; i < x; i++)
{
std::cin >> v[i].x;
}
If you just want to pass an array to a function you can do so like this:
void sortArray(struct List list[]);
void sortArray(struct List* list, int n); // n = size of array
may be better to just use std::vector or some other list container instead. :)
Sounds like you want a function that receives an array t and index x, and you want to mutate the array in the function?
C++ is "pass by value", so to mutate the array you have to have your function take a reference (or pointer) to the array so that you're mutating the original array and not a copy of it, so just have your function signature like this: func(T& t, int x) (assuming T is the type of array t).

C++ code breaks into line and for the love of me I can't fix it

Basically my code is supposed to take input from the user about the runners of a marathon, and then display the 3 best times and have the ability to search and display any runner. Right now the code is still pretty bare-bones, but it should at least take the input it, organize the info in ascending order (winners function) and I was in the middle of writing the display function when I decided to compile the code to test, and then it all goes down hill.
Basically when I have to input the name of the first runner, the code breaks into this line:
static void __CLRCALL_OR_CDECL assign(_Elem& _Left, const _Elem& _Right) _NOEXCEPT
{ // assign an element
_Left = _Right;
}
First of all I have no idea what that means or why left = right, and second a friend ran my code on his machine and told me he encountered no errors.
Here is my code:
#include <iomanip>
#include <iostream>
#include <math.h>
#include <string>
using namespace std;
#pragma once
#include <string>
using namespace std;
class race
{
private:
public:
int timeH, timeM, timeS, timeT;
int number;
string name;
void input();
};
int size;
race *runner = new race[size];
void input();
void winners();
void display();
int main(){
input();
winners();
display();
system("pause");
}
void input(){
cout << "Indique la cantidad de corredores: ";
cin >> size;
for (int i = 0; i < size; i++){
cout << "Nombre del corredor ";
cin >> runner[i].name;
cout << "Numero del corredor # "<<i;
cin >> runner[i].number;
cout << "Tiempo del corredor # " << i << endl << "Indique cuantas horas tardo :";
cin >> runner[i].timeH;
runner[i].timeH = runner[i].timeH * 3600;
cout << "Cuantos minutos: ";
cin >> runner[i].timeM;
runner[i].timeM = runner[i].timeM * 60;
cout << "Cuantos segundos: ";
cin >> runner[i].timeS;
runner[i].timeT = runner[i].timeH + runner[i].timeM + runner[i].timeS;
}
}
void winners(){
race temp;
int flag = 1;
for (int j = 1; (j <= size) && flag; j++){
flag = 0;
for (int i = 0; i < size-1; i++){
if (runner[i + 1].timeT < runner[i].timeT)
{
temp = runner[i];
runner[i] = runner[i + 1];
runner[i + 1] = temp;
flag = 1;
}
}
}
}
Thanks in advance, any help is appreciated.
int size;
race *runner = new race[size];
That's a problem right there. You're allocating memory, but you haven't set size yet (that allocation runs before main() is invoked). That means you are doing new race[0] (because size is initialized to zero, since it's a global int). Ergo, the rest of your program is invoking undefined behavior, because runner is an empty array, which you're trying to (illegally) access.
You're also leaking memory, as you never delete [] the memory you allocate with new []. I suggest heading Joachim's advice and using std::vector.
The problem is this:
int size;
race *runner = new race[size];
Uninitialized global variables are zero initialized, so size will be initialized to zero, so you're allocating a zero-sized array which means any access to the array will be out of bounds and lead to undefined behavior.
There are two ways of solving this:
Wait with the allocation until you know the size. (Not the solution I recommend.)
Use std::vector which is a dynamically sized "array" type (the solution I do recommend).

Doubling of an arbitrary array of strings

1: My goal is to create two arbitrary arrays using pointers: one with names, another one with corresponding numbers. From my previous question, I know that doubling an array is a good way to deal with arbitrary sizes. So, I am trying to double both arrays correspondingly. But while the doubling of an int array goes well, array of strings does not double. Could you explain, what is the problem with that?
2: Is there an alternative to the creation of arbitrary array of strings to store list of names?
Here is the part of the code:
string *pn = new string [size];
int *pd = new int [size];
while (x != 0) {
if (size == k+1) {
pn = doubn (pn, size);
pd = doubd (pd, size);
}
pn[k] = name;
pd[k] = val;
cout << "Another entry? (0 for exit)";
cin >> x;
getline (cin, name, ',');
cin >> val;
++k;
}
for (int i = 0; i<k; ++i) {
cout << pn[i] << " - " << pd[i] << " days"; }
del (pn, pd, k);
cin.get ();
cin.ignore();
}
string* doubn (string *pn, int size) {
string* pnn = new string [size*2];
for (int i = 0; i < size; ++i) {
pnn [i] = pn[i]; }
delete pn;
return pnn; }
int* doubd (int *pd, int size) {
int *pdn = new int [size*2];
for (int i = 0; i<size; ++i) {
pdn [i] = pd[i];}
delete pd;
return pdn;}
To have arbitrary sized arrays, use vectors.
Vectors are a part of the C++ Standard Template Library (STL) and required the #include<vector> header.
For more information, check this out: http://www.cplusplus.com/reference/vector/vector/
Also, you should be using delete [] instead of delete.
You use delete on memory allocated by new[], you should use delete[] instead.
Using std::vector would be simpler and less error prone anyway.

Arrays and Pointers as arguments and return values

#include <iostream>
using namespace std;
int getDegree()
{
int degree;
cout << "Enter degree of polynomial" << endl;
cin >> degree;
return degree;
}
int* getPoly(int degree)
{
cout << "Enter coefficients in order of power of x. e.g. for 2 + x + 3x^2, enter 2 then 1 then 3" << endl;
int coeff [degree +1];
for (int i = 0; i <= degree; i++)
{
cin >> coeff[i];
}
return coeff;
}
int* polyder(int p[], int degree)
{
int dp[degree];
for(int i = 0; i < degree; i++)
{
dp[i] = p[i+1] * (i+1);
}
return dp;
}
int main(int argc, const char * argv[])
{
int degree = getDegree();
int p = *getPoly(degree);
int dp = *polyder(&p, degree);
for(int i = 0; i < degree +1; i++)
cout << " " << p[i] << " x^" << i;
cout << endl;
for(int i = 0; i < degree +1; i++)
cout << " " << dp[i] << " x^" << i;
cout << endl;
return 0;
}
I am getting an error during the print statements.
I am not worried about the math involved, just how to pass the arrays between functions/methods.
Can anyone find why this is not working?
I am new to C++, used to Java.
Can anyone find why this is not working?
In C++ variables are destroyed when the scope in which they were declared ends. You return an address of a variable that doesn't exist when the function ends:
int* getPoly(int degree)
{
int coeff [degree +1];
// ...
return coeff;
}
If you wish the variable still exists after the function ends, you have to allocate it using new:
int* getPoly(int degree)
{
int *coeff = new int[degree +1];
// ...
return coeff;
}
And, at the end of your main function (or wherever you don't need the array anymore), call delete[] to deallocate the memory:
int *p = getPoly(degree);
delete[] p;
The Array name is essentially a pointer to the first element of the array (as you can see in the code above, I've declared p as a pointer to int), so you pass them to other functions just by providing their name:
int* polyder(int p[], int degree){/*do something here*/}
// <-- some other code
int *p = getPoly(degree);
int* returnedArray = polyder(p,degree);
First of all, the line
int coeff [degree +1];
is not a valid C++ statement unless 'degree' is a constant, even through some compilers may allow it.
Even if some compiler allowed it, the space for coeff is allocated from the stack and will be invalid after the function returns. Hence, the line
return coeff;
returns an memory location that will be invalid at its usage.
In order to return valid memory function, replace the line
int coeff [degree +1];
by
int* coeff = new int[degree];
You don't need degree+1 items in the array.
Similar changes are needed in the function polyder.
The thing to remember about arrays in C++ is that unlike Java, they are not objects (at least in the way they are in Java). They're simply pointers to a block of allocated memory, and the [] operator simply automatically does the math to move the pointer to the correct location.
When passing arrays between functions, you're basically just passing a pointer. Unless you want to get into some highly complicated and likely too much for your use case code, you should always pass the size of the array along with it to ensure that your indexes always stay in bounds.
And as the other answer points out, you need to ensure that the life cycle of the array lasts as long as you need it to. Simply returning a pointer to an object doesn't keep it alive like returning a reference does in Java.