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");
}
Related
I've been stuck on this problem and I'm hoping someone can explain where I'm wrong on this. I'm working on an assignment where I need to:
1) Allocate an array that can contain 100 int values by calling allocIntArray and assign the returned pointer to ptr1.
2) Use the new operator to allocate an array of integers using the parameter as the size of the array.
3) Return the pointer that is returned by the new operator.
4) Print out the new array.
I'm trying to print out the array after passing the size I want through the function.
int main() {
int *ptr = NULL;
ptr1 = *allocIntArray(100);
cout << ptr1 << endl;
return 0;
}
//The function I want to call
int *allocIntArray(int size) {
int *newarr = nullptr;
newarr = new int[size];
return newarr;
}
However when I call the function, the output comes out as 00F011E8.
I'm currently trying to understand why this is the output and not the first value in the array. (Just the number 1)
I've been having a lot of trouble grasping pointers any help understanding would be greatly appreciated.
Thanks to everyone who took the time to respond.
From what I understand from assignment directions, I shouldn't need to use vectors. I'm trying to modify my current code to display the array output and this is what currently comes up when I run it.[enter image description hereMy current results
At first, if you're using C++, you should use std::vector/std::array. This avoids a huge amount of possible problems.
It would look like:
#include <iostream>
#include <vector>
int main()
{
// create array of size 10 and initialize it with 0's
std::vector<int> vec(10, 0);
// print array
for(auto a : vec)
std::cout << a << '\t';
std::cout << std::endl;
}
If it's some kind of exercise, you have done four big mistakes:
you dereference the returned pointer to the array. So you get the value of the first element in the array and not the array itself. Simply remove the *.
you print out the address of the first element of the array. To print the array, you have to iterate over each element of the array. This can be done in a for loop:
for(int i = 0; i < 10; ++i)
std::cout << ptr1[i] << '\t';
you want to print out the array uninitialized. In fact, you try to print out some random values which are there in the memory. At first, you have to assign the elements values.
you forget to delete the array by using
delete[] ptr1;
I just have to answer as you seem to be missing some important fundamentals. Either the instructor should be dismissed or you have not paid enough attention in the class. So...
ptr1 = *allocIntArray(100);
You could not have pasted code that compiles, ptr1 is not declared.
You need to understand what the * operator does. What ever value to the right of * must be a pointer. What a pointer is should be fundamental in your understanding. If you had:
int* ptr1 = *allocIntArray(100);
You should have gotten a compiler error, so you must have:
int ptr1;
Somewhere along the line. As allocIntArray(...) returns a pointer, then *allocIntArray(...) gives you an integer.
You would have wanted to:
int* ptr1 = allocIntArray(100);
To get a pointer to the new array. Then you:
std::cout << ptr1 << std::endl;
So, what is ptr1? If it is a pointer then all you are doing is printing the pointer value. Per your stated problem, I'd say ptr1 is in fact a pointer. std::cout has not facility to work with a pointer as you expect. At that, it would have no way of determining the size of your array.
You would want to (And it hurts my fingers to write like this):
for(size_t i= 0; i < 100; ++i)
std::cout << ptr1[i] <<" ";
But!!!
4) Print out the new array.
So what will it print? There was never an instruction to initialize the array. It will print out what ever garbage is sitting in the array when it was created.
Side note, that the instructor has you doing a:
using namespace std;
Says much, as he/she should never have allowed it.
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.
I have a working code for a function which takes a character and a number and forms a string by duplicating that character that number of times. Here is a piece that works perfectly fine.
char * buildstr(char c, int n)
{
char * pc = new char[n+1];
for (int i = 0; i < n; ++i)
{
*(pc+i) = c;
}
*(pc+n) = '\0';
return pc;
}
But if I use another logic where I directly increment the pointer itself directly then I get an error when I free up the memory in the main function using delete [].
What could be my problem ?
Thanks,
char * buildstr(char c, int n)
{
char * pc = new char[n+1];
for (int i = 0; i < n; ++i)
{
*pc = c;
pc++;
}
*(pc) = '\0';
return pc;
}
The problem is that you're returning the incremented pointer. delete[] has to be invoked with a pointer value that was returned by a call to new[], otherwise you get undefined behaviour. The same applies to calls to free and pointers returned by malloc, calloc etc.
In the second example, you are incrementing the value of the pointer. When you try to delete it, it is pointing to the last position of the array.
This way, when you call delete[] on it, it crashes as it expects pc to point to the address that was originally allocated using new[].
I encourage you to use the first approach as you will be able to keep track of the base address through the lifetime of pc. Moreover, I think it would be easier for you to do this using array notation.
Consider using:
pc[i] = c;
instead of
*(pc+i) = c;
As it is more idiomatic and easy to read. If you are simply exercising your pointer arithmetic, stick to the first approach that you described.
In the first function let's say that your pointer start at 0x00100.
when you do the loop you get to the next adress so for exemple let's say 4 loop:
0x00100
0x00101
0x00102
0x00103
but at the end you return the pointer on the 0x00100 beceause you used index *(pc+i) where i is the index, so it is good.
Now on the second function you are doing the same exept that your are moving your pointer itself without index so you return your pointer at the last adress
0x00103
That is wy your second function doesn't work
I'm currently learning C++, so sorry if I seem a little silly.
My current exercise, that I'm stuck on, requires me to write a function, IndexArray(int n) that returns a pointer to a dynamically allocated integer array with n elements, each of which is initialised to its own index.
(copied from the worksheet).
I've read this several times and don't fully understand it, but they gave an example:
Assuming that intPtr is declared as
int *intPtr;
the statement
intPtr = IndexArray(10);
should produce the following memory configuration:
intPtr -> 0 1 2 3 4 5 6 7 8 9
From this example I'm guessing my function needs to create an array of size n, with values from 0 to n-1, and then another pointer needs to point to that array.
Here's their test code:
int *values1;
values1 = IndexArray(10);
I know how to easily create the array, but I don't fully understand pointers enough to know really what to do. I figured returning an array would work:
int *IndexArray(int n) {
cout << n << endl;
int arrayTemp[n];
for(int i = 0; i < n; i++) {
arrayTemp[i] = i;
}
return arrayTemp;
}
However when tested, values1 array doesn't contain the values from 0-9 (although arrayTemp does right before it's returned).
Any help would be amazing, and hopefully I've given everything you need to help. Thanks! :D
int arrayTemp[n];
Notice that the statement is in a function, so when the function terminates, the arrayTemp[] will not be available any more, it coule be removed : it is a #local# variable!
So, if you want to do that , you could use :
int * arrayTemp = new int[n];
NOTICE : you must delete it any how to avoid memory leaks.
You cannot do this:
int *IndexArray(int n) {
cout << n << endl;
int arrayTemp[n]; //declare a local array
for(int i = 0; i < n; i++) {
arrayTemp[i] = i;
}
return arrayTemp; //return a pointer to a local
}
You cannot return a pointer to a local. The local ceases to exist once you return. The pointer now points to garbage.
Instead, you have to use malloc (C or C++) or new (C++) to dynamically create storage for 10 ints, and since this is dynamically created on the heap it will persist after returning (and will need to be freed if malloced or delete[]d if it was a an array made with new. For just single objects made with new you just use delete )
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?