I am trying to make a c++ program with a class which holds integers on the "heap" and has only one method, pop() which returns the first item in the class and removes it. This is my code so far:
#include <iostream>
using namespace std;
class LinkList {
int *values; //pointer to integers stored in linklist
int number; // number of values stored in linklist
public:
LinkList(const int*, int); // Constructor (method declaration)
int pop(); // typically remove item from data structure (method declaration)
};
LinkList::LinkList(const int *v, int n){
number = n;
*values = *v;
int mypointer = 1;
while (mypointer<n) {
*(values+mypointer) = *(v+mypointer);
mypointer++;
}
}
int LinkList::pop() {
if (number>0) {
int returnme = *values; //get the first integer in the linklist
number--;
values++; //move values to next address
return returnme;
}
else {return -1;}
}
int main() {
int test[] = {1,2,3,4,5};
LinkList l1(test,5);
cout << l1.pop() << endl;
LinkList l2(test,5);
cout << l2.pop() << endl;
return 0;
}
The issue is that its failing at the line *values = *v, if i remove the 4th and 5th lines from the main method, I no longer get this issue, so its go to be a memory management thing.
What I want to do is to get values to point to a continuous bit of memory with integers in. I have tried to use arrays for this but keep just getting random memory addresses returned by pop()
Background: normal I programming in java, I've only be using C/C++ for 2 months, I'm using eclipse IDE in ubuntu, I can make very basic use of the debugger but currently I dont have functioning scroll bars in eclipse so I can't do somethings if they dont fit on my screen.
You are dereferencing an uninitialized pointer (values) at the line *values = *v; which is undefined behavior (UB). What this line says is "get the integer that values points to and assign to it the value pointed by v". The problem with this logic is that values doesn't yet point to anything. The result of this UB is the crash that you receive.
There are many other problems with this code, such as passing a const int* to the constructor with the intent of modifying those values. The biggest problem is that this is not an actual linked list.
*values = *v;
You dereference the values pointer in this line before initializing it. This is the source of the later errors, and the non-errors in the first three lines of main are simply due to luck. You have to allocate space via values = new int[n] and deallocate it in the destructor via delete[] values. std::vector does this work in a clean and exception-safe way for you.
Perhaps the problem is that you're incrementing an integer - mypointer, rather than a a pointer. If the integer requires more than one byte of space, then this might lead to errors. Could you try declaring a pointer and incrementing that instead?
The values member variable is a pointer to uninitialized memory. Before you start copying numbers into it you have to point it to valid memory. For example:
LinkList::LinkList(const int *v, int n){
number = n;
values = new int[n]; // allocate memory
int mypointer = 0;
while (mypointer<n) {
*(values+mypointer) = *(v+mypointer);
mypointer++;
}
}
LinkList::~LinkList() {
delete values; // release memory
}
Also, why do you call this a linked list while in fact you are using a memory array to store your numbers?
Related
EDIT: Im quite new to c++ and programming as a whole.
I'm supposed to make a program where i use stucts and and an array of structs.
Security council < > Member of Security council
My task was to use the concept of "UML aggregation" to create a program where I use structs and struct arrays. (I hope you understand what I'm trying to say)
Since a Member of a Security council is a part of a Security council, and not the other way around, the struct of Security council must have an array of its members.(bear with me)
//example
struct Member_sc{
char * name;
int age;
};
struct Security_council{
Member_sc members[10];
};
Now, I've created this program and everything works perfectly (according to my teacher), but now she told me create an exact copy, but instead of the "members" array I must use an array of pointers to the Member_sc structs. Since I havent completely figured out how pointers work, I have come across some problems.
I can post the code to the original program if needed, but it contains 4 files(main, header, and some function files) and it would be a pain to try and post it here.
here is the prototype (all in one file, for now)
#include <iostream>
using namespace std;
struct member_sc{
string name;
};
struct security_council{
member_sc *point;
security_council **search; // ignore this for now
int n;
security_council():n(0){}
};
void in_mem( member_sc &x){
getline(cin,x.name);
}
void out_mem(member_sc &x){
cout<<x.name<<endl;
}
void in_SC(security_council &q, member_sc &x){
int num; //number of members
cin>>num;
for(int i=0; i<num; ++i){
in_mem(x);
q.point[q.n]=x;
q.n++;
}
}
void out_SC(security_council &q,member_sc &x){
for(int i=0; i<q.n; ++i){
out_mem(q.point[i]);
}
}
int main(){
member_sc y;
security_council x;
in_mem(y); // works
out_mem(y); // works
in_SC(x,y); // crashes after i input the number of members i want
out_SC(x,y); //
system("pause");
return 0;
}
The program crashes after you input the number of members you want in your Security council.
Is my way of thinking right? or should I use dynamic memory allocation?
in addition to that (my teacher gave me an additional task) create a search function using pointers. i thought that pointer to pointer may be good for that, but im not sure.
Any help or advice would be greatly appreciated.
( i think ill figure out the search thingy once i figure out how pointers to structs work)
The first part of your issue is this:
cin >> num;
this reads only the digits that have been typed and stops at the newline. Then, in in_mem the call to getline immediately reads a newline. You need to do:
cin >> num;
cin.ignore();
this will drain the input stream of any remaining input, or catch up so to speak.
However your core problem is that you don't allocate any memory for "point" to point to.
A pointer is just a variable holding a value that happens to be the address (offset from 0) of a thing in memory. If you are going to the airport and write "Gate 23" on a post-it note, the post it note is a pointer and "Gate 23" is the value.
In your code, that variable is uninitialized and will either be 0, if you are lucky, or some random address in memory if you aren't so lucky.
To the airport analogy: you arrive at the airport and find that your post-it note has "pizza" written on it. Not helpful.
Your teacher has actually specified an "array of pointers". Break that down: pointer to what? member_sc, that's member_sc*. And now make it an array
member_sc* pointers[10];
NOTE: This is not good, modern C++ - in modern C++ you would use something called a smart pointer (std::unique_ptr) probably.
std::unique_ptr<member_sc[]> pointers(new member_sc[10]);
Now you have 10 pointers instead of just one, and all of them will need some allocation to point to. The easiest way to do this is with the new keyword and the copy constructor:
for (int i = 0; i < num; i++) {
in_mem(x);
pointers[q.n] = new member_sc(x); // make a clone of x
q.n++;
}
or in modern C++
for (int i = 0; i < num; i++) {
in_mem(x); // x is temporary for reading in
pointers[q.n] = std::make_unique<member_sc>(x);
q.n++;
}
However there is a limitation with this approach: you can only have upto 10 security council members. How do you work around this? Well, the modern C++ answer would be to use a std::vector
std::vector<member_sc> members;
// ditch n - vector tracks it for you.
// ...
for (int i = 0; i < num; ++i) {
in_mem(x);
q.members.push_back(x);
// q.n is replaced with q.members.size()
// which is tracked automatically for you
}
but I'm guessing your teacher wants you to actually understand pointers before you get to forget about them with modern luxuries.
We need to re-use the pointer stuff we've just used above and change "pointers" to an array of pointers.
Which means we're going to want a pointer to a set of pointer-to-member_sc.
member_sc** pointers;
We'll need to assign some memory for this to point to:
cin >> num;
cin.ignore();
if (num == 0) {
// do something
return;
}
pointers = new member_sc[num];
luckily, using a pointer to an array is as easy as using an array, the only major difference being that you lose the size-of-array information -- all you have is the address, not the dimensions.
for (int i = 0; i < num; i++) {
in_mem(x);
q.pointers[i] = new member_sc(x);
q.n++;
}
I'm deliberately not providing you with a complete working example because this is obviously for a class.
You never initialize the memory that the point member refers to, yet then in statement q.point[q.n]=x; you attempt to use it.
Basically, after you read in the number of members, and before the for loop where you read in the individual members, you need to allocate an array of an appropriate number of member_sc objects and store it in q.point. Don't forget to free this memory when done using it.
Once you do that, you can also remove the member_sc &x argument from both in_SC and out_SC, as that will become unnecessary.
Finally, some validation of your input seems to be in place. Consider what will happen if the user enters a negative number, and you attempt to use that directly to determine the size of memory to allocate.
Here's a simple example showing how to use a dynamically allocated array of structures:
#include <iostream>
#include <string>
struct member_sc {
std::string name;
};
void test_array(int count)
{
if (count <= 0) {
return; // Error
}
// Allocate an array of appropriate size
member_sc* members = new member_sc[count];
if (members == nullptr) {
return; // Error
}
// ... fill in the individual array elements
for(int i(0); i < count; ++i) {
// ... read from input stream
// I'll just generate some names to keep it simple
members[i].name = "User A";
members[i].name[5] += i; // Change the last character, so we have different names
}
// Now let's try printing out the members...
for(int i(0); i < count; ++i) {
std::cout << i << ": " << members[i].name << "\n";
}
delete[] members;
}
int main(int argc, char** argv)
{
for(int count(1); count <= 10; ++count) {
std::cout << "Test count=" << count << "\n";
test_array(count);
std::cout << "\n";
}
return 0;
}
Example on Coliru
Of course, there are many other issues with this style of code, but I believe that's beside the point of this question. For example:
Instead of using bare pointers, it would be more appropriate to use some kind of a smart pointer.
Instead of a simple array, use some kind of collection, such as a vector.
Since you are asked to use an array of pointers, do so: replace
Member_sc members[10];
with
Member_sc* members[10];
Then fill out that array using dynamic memory allocation. As a matter of good form, at the end of the program remember to release the dynamic memory you have used.
Hoping for a little C++ assistance - I'm very new to the topic. I'm attempting to dynamically create an array based on user input with a pointer, then pass the array to a function. But the pointer (and thus array) pass feels a little wrong because there is no dereferencing that occurs.
During/after passing, do we just treat the pointer as if it were any normally declared-and-passed array, without the need to dereference (*) anything? Or am I applying this incorrectly?
Pseudocode follows:
#include<iostream>
using namespace std;
void arrayFunc(int [], int); // << Note no indication of pointer pass
int main()
{
int *arrayPtr = 0; // Array pointer
int arrayElem = 0; // Number of elements in array
cout << "\nPlease enter the number of elements: ";
cin >> arrayElem;
arrayPtr = new int[arrayElem]; // Dynamically create the new array
arrayFunc(arrayPtr, arrayElem); // << Note no dereferencing or other indication of pointer
return 0;
}
void arrayFunc(int array[], int arrayElem) // << Same here - now it's just a plain old array
{
// All the functiony-bits go here, referencing array without the need to dereference
}
[EDIT] While the above code works, the following includes the fixes determined in the discussion below:
#include<iostream>
using namespace std;
void arrayFunc(int*, int); // Changed to pointer pass instead of []
int main()
{
int *arrayPtr = 0; // Array pointer
int arrayElem = 0; // Number of elements in array
cout << "\nPlease enter the number of elements: ";
cin >> arrayElem;
arrayPtr = new int[arrayElem]; // Dynamically create the new array
arrayFunc(arrayPtr, arrayElem);
return 0;
}
void arrayFunc(int* array, int arrayElem) // Passing a pointer now instead of []
{
// All the functiony-bits go here, referencing array without the need to dereference
}
You should pass the pointer in your function, because it describes the situation accurately i.e. you are passing a dynamically allocated memory. arrayPtr is essentially a pointer to the first element of the array. As a result, you do not need to worry about dereferencing it.
Change the function signature to:
void arrayFunc(int*, int);
Your attempt is correct. You are passing the array pointer by value. You can then dereference it as normal within arrayFunc
C is designed to pretend a pointer and an array are the mostly same thing. Lots of simple uses are easier because of that. But the concept gets much more confusing when you think about a pointer to an array. It feels like it shouldn't be the same thing as a pointer to the first element of that array, but in the common methods for allocating memory and using pointers, a pointer to an array really is just a pointer to the first element of the array.
I find it best to think of "pointer to first element of array of" as the normal meaning of * in C. The special case of pointing to a scalar object is effectively treating the scalar as the first (and only) element of an array of length 1.
I have a method which fills the array with integers:
void fill(int* a[], int dim1, int dim2)
{
int intinArray = 0;
for(int i=0;i<dim1;i++)
{
for(int j=0;j<dim2;j++)
{
cin >> intinArray;
a[i][j] = intinArray;
}
}
}
If I declare array in method main() like this:
int** tab;
fill(tab,3,3);
It crashes when I put the first integer in cin. Why? If there's a problem with this line:
a[i][j] = intinArray;
how should I change it?
The fundamental thing wrong with your code is that you declared pointers, but nowhere do you initialize the pointers to point somewhere. You treat the pointer as if it is a regular old 2 dimensional array of integer. So if it's as easy as that, why use pointers?
Given that this is a fundamental in pointer usage and you plainly aren't doing that, the solution is to review working code that uses pointer.
int main()
{
int *p; // uninitialized -- points to who-knows-where
*p = 10; // this is undefined behavior and may crash
}
Take that code and understand why it also may crash. That pointer points to "we don't know", and then you're assigning 10 to a location that is unknown to you, me, and everyone else reading this answer. See the problem? To fix it, you have to initialize the pointer to point somewhere valid, then you can dereference it and assign to it without error.
int main()
{
int *p; // uninitialized -- points to who-knows-where
int x = 20;
p = &x; // this is now ok, since p points to x
*p = 20; // now x changes to 20
}
Your problem is in this code
int** tab; // <- this one
fill(tab,3,3);
You declared a pointer, and are using it under the assumption that it is pointing to allocated memory. (I guess a source of confusion is that with C++ objects this isn't really the case)
A pointer is a pointer - it points to a location in memory. There's no guarantee that the value it points to is valid unless you explicitly make sure it is yourself.
Read PaulMcKenzie's answer for more about pointers.
Try
int tab[x][y] = {{0}};
fill(tab,3,3);
where x and y define your 2D array's width and height. You're going to have to handle bounds checking for your application.
Note that changing {{0}} to a non zero number will not initialize everything to that number.
I'm studying for an exam in c++ and i have a question on the past papers
"Write a function in C++ that takes as input an array of doubles and the length of the array, and returns an array twice the length. The first half of the returned array should contain a copy of the contents of the original array. The second half of the returned array should contain the contents of the original array in reverse order."
"The function should have the following prototype: double *copy_and_reverse(double *a, int length);"
since im obviously new to c++ i got stuck in my solution, my code so far is:
double *copy_and_reverse(double *a, int length){
double *b[length*2];
for(int i=0;i<length;i++){
*b[i]=a[i];
}
for(int i=length;i<length*2;i++){
int w=length-1;
*b[i]=a[w];
w--;
}
return *b;
}
int main()
{
double nums[2]={1.23,5.364};
double *pnums=nums;
*pnums=*copy_and_reverse(pnums, 2);
I think i got the core of the method correct but i'm just stuck in the syntax of using pointers, any help is appreciated and if possible a reasoning behind it so i can learn for the exam.
You've got a few problems with this code.
First
double *b[length*2];
Here you're declaring an array of pointers to doubles. The array is of size length * 2, however, none of the pointers in this array are valid yet. This is probably not what you intended to do.
You want an array of doubles, of size length * 2. You can't return an array in C++ but you can return a pointer to some memory that contains an array of doubles.
Let's start by allocating enough memory for all those doubles
double *b= new double[length * 2];
In your first for loop you can treat result as an array
for(int i=0;i<length;i++){
b[i]=a[i];
}
Here you're copying the values from a for each index i to be at the same index. I'll let you figure out how to fill in the reverse part for the second half of the array. You're on the right track, however you might want to think about doing it all in one loop ;)
Your return statement just needs to return your variable b, as it's already a double *.
return b;
An important thing to remember is that you're allocating memory in this function with new. You are responsible for deleting this when you're done with it. Also, when you allocate using new and [] you have to delete using [] as well.
delete [] b;
you can call your function just by de-referencing the first item in your array.
int main() {
double nums[2]={1.23,5.364};
double *pnums = copy_and_reverse(&pnums[0], 2);//don't forget to clean up pnums afterwards!
There are quite many errors in your code. The major one is that you need to allocate new array of doubles. And return that array. I'd suggest compare this with your version line by line:
double *copy_and_reverse(double *a, int length){
double *result = new double[length*2];
for(int i=0;i<length;i++) {
result[i]=a[i];
}
int r = length*2;
for(int i=0; i < length;i++){
result[--r]=a[i];
}
return result;
}
And your main() shall look like:
int main()
{
double nums[2]={1.23,5.364};
double *pnums = copy_and_reverse(nums, 2);
...
delete[] pnums;
}
Ok, there are at least two problems with this:
double *b[length*2];
The first problem is that you are declaring a local array (of pointers), which you will then try to return:
return *b;
(You're returning the wrong thing here, too, but that's another story) You can't return a pointer to a locally-allocated thing because as soon as the function returns, the locally-allocated thing will be destroyed. Instead, given that you must return a pointer to the first element of an array, you have to dynamically allocate that thing using new.
Second, you can't declare an array like this using a length which s only known at runtime. But this problem will be obviated when you use new to dynamically allocate the array.
I would normally say that you shouldn't be doing any of this at all, and just use a std::vector -- but clearly a requirement of this assignment is to use a dynamically allocated C-style array. (Which I take great issue with your professor on.)
I would also say that the prototype:
double *copy_and_reverse(double *a, int length);
doesn't declare a function which takes an array, as your professor incorrectly asserts, but a function which takes a pointer to a double. That that pointer is the first element in an array doesn't magically make a an array. In short: an array and a pointer are not the same thing.
These last two observations are just for your benefit.
I assume this is not your homework and I am trying to help you out.
Look at the comment of code.
double *copy_and_reverse(double *a, int length)
{
double * b = new double[length*2]; //create a new array using new[]
for(int i=0;i<length;i++){
b[i]=a[i]; //addressing element with []
}
int w=length-1; //I assume this is what you want
for(int i=length;i<length*2;i++){
b[i]=a[w];
w--;
}
return b;
}
int main()
{
double nums[2]={1.23,5.364};
double *pnums = copy_and_reverse(nums, 2);
delete[] pnums;
}
Also noted the memory is allocated in the function, so in the main, you want to delete it by using [].
I am stuck in this problem: how to resize, inside a function, a dynamically allocated array, which has been passed, to the function, by reference.
I tried this, along with countless variations on this very approach. Of course this is just an example, it should print "john" ten times, expanding an array passed by reference that originally had only size 1 ( ie only 1 name ).
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
int NumLast=-1;
int Surname(string *MyData)
{
for (int i=0; i<10 ; i++)
{
NumLast++;
string *Temp = new string[NumLast+1]; // temporary array
for (int jjj=0; jjj<NumLast; jjj++)
Temp[jjj]=MyData[jjj];
delete[] MyData;
MyData=Temp;
MyData[NumLast]="John";
}
return 0;
}
void main()
{
string *Data = new string[1]; // inizializza l'array
Surname(&*Data);
for (int iii=0; iii<10; iii++)
cout << Data[iii] << endl;
system("pause");
}
You have to pass by reference. You are passing by value. You are getting
&*Data = Data
The value of the address of what is pointed to Data = Data
Then you pass it by value to Surname. Anything Surname does to it won't affect Data in main.
int Surname(string *MyData) // This will take a copy of whatever you passed in to MyData
should be (The reference operator should be on the function definition.)
int Surname(string*& MyData)
^^
And the call will be
void main()
{
string *Data = new string[1];
Surname(Data); // The function will take a reference of data.
Buy may I ask why you are allocating in a loop?
Looks like std::vector is best solution for your case.
If you really need to reallocate manually, think about old school malloc(), free(), realloc() interface. Main thing to remember is to not intermix it with C++ new/delete interface despite usually new / delete is implemented using malloc() / free().
If you need array you should pass not array but pointer (or reference) to array (double pointer). In case of std::vector it is enough to pass reference to it.
Yet another argument to use reference to std::vector - in case of pointer to array caller should be notified somehow what is new array size.
I decided to try and go through your code line by line and point out some of the issues and highlight what's going on. I will start from your main function:
void main()
{
string *Data = new string[1]; // inizializza l'array
Surname(&*Data);
for (int iii=0; iii<10; iii++)
cout << Data[iii] << endl;
}
OK, so what this code does is allocate one string and save the pointer to it in a variable called Data.
Then it dereferences Data, thus, getting back a string and then gets the address of of that string (i.e. gets back the same thing as Data).
In other words this code:
Surname(&*Data);
does exactly the same as this code:
Surname(Data);
So, now let's take a look at Surname:
int Surname(string *MyData)
{
for (int i=0; i<10 ; i++)
{
NumLast++;
string *Temp = new string[NumLast+1]; // temporary array
for (int jjj=0; jjj<NumLast; jjj++)
Temp[jjj]=MyData[jjj];
delete[] MyData;
MyData=Temp;
MyData[NumLast]="John";
}
return 0;
}
This weird function accepts a pointer to a string and loops 10 times doing stuff. Let's see what happens in the first iteration of the loop...
First, it increments NumLast (which goes from -1 to 0). Then it allocate an array of strings, of length NumLast + 1 (i.e. of length 1). So far so good.
Now you might think the function would enter the for loop. But it won't: remember that at that point NumLast and jjj are both 0 and therefore, jjj < NumLast is false.
The code will then delete[] MyData (that is, it will delete whatever MyData points to), set MyData to point to the temporary array allocated earlier in the loop, and then set the first element (at index 0) to the string "John".
In the second iteration of the loop, the function again increments NumLast (which will now be 1). It will again allocate an array of strings, this time of length 2.
The loop will be entered this time. It will copy the first entry from MyData into the first entry from Temp. And it will exit.
Again, MyData will be deleted, and the pointer will be made to point to the newly allocated array.
Rinse. Lather. Repeat.
Finally, the function will exit. We go back to main, which will now execute this bit of code:
for (int iii=0; iii<10; iii++)
cout << Data[iii] << endl;
Wait a second though. Where does Data point to? Well... it points to data that has already been deleted long ago. Why?
Well, Surname received a copy of the Data pointer. When it called delete[] MyData it deleted the array that it MyData pointed to (which was the same array that Data pointed to). When Surname later did MyData=Temp all that changed was MyData (the copy of the pointer local to the function Surname) and Data (the pointer in main) was unaffected and continued to point to the now deleted memory.
Others have explained how you can get the effect you want and I won't repeat what they wrote. But I would urge you to sit down and think about what Surname does and how the code is unclear and confusing and how it can be rewritten so that it's easier to understand and less prone to error.
For those who in the future will need the solution to the same problem here is the amended code:
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
int NumLast=-1;
int Surname(string *&MyData)
{
for (int i=0; i<10 ; i++)
{
NumLast++;
string *Temp = new string[NumLast+1];
for (int jjj=0; jjj<NumLast; jjj++)
Temp[jjj]=MyData[jjj];
delete[] MyData;
MyData=Temp;
MyData[NumLast]="franci";
}
return 0;
}
void main()
{
string *Data = new string[1]; // inizializza l'array
Surname(Data);
for (int iii=0; iii<10; iii++)
cout << Data[iii] << endl;
system("pause");
}