I'm having trouble with wrapping my head around pointers, and using pointers in structs. To start, I don't know if I am using the pointer properly in the struct. Additionally, when I run my program, it seems to crash when it reaches readRecords, so there must be something wrong with it. Since I don't quite know how to use pointers very well, I am probably doing something wrong here... I just don't know what. Is there some way that I can edit this function so that I don't get crashes? Also, I have to keep these functions, as they are part of my project requirements.
struct testScores
{
string name;
string idNum;
int testNum;
int *tests; // This is supposed to be a dynamically allocated array
double average;
char grade;
};
[...]
void arrStruct(testScores*& sPtr)
{
sPtr = new testScores[];
}
void readRecords(ifstream& data, int record, testScores*& sPtr)
{
for (int count = 0; count < record; count++)
{
data >> sPtr[count].name;
data >> sPtr[count].idNum;
data >> sPtr[count].testNum;
sPtr[count].tests = new int[sPtr[count].testNum]; // tests is dynamically allocated (?)
for (int tCount = 0; tCount < sPtr[count].testNum; tCount++)
data >> sPtr[count].tests[tCount];
}
}
sPtr = new testScores[];
This appears to be illegal syntax - array new requires a subscript to know how much space to allocate.
Usually this is at least 1, in your case the compiler probably interprets this as new testScores[0] which does return a valid pointer, but without allocating any memory from the heap.
Of course any subsequent access to memory pointed to by sPtr is out-of-bounds and causes undefined behaviour (in your case a crash).
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.
I am trying to read from a file and put each new line/entry in to an array. However, I am more primarily familiar with C# and C++ isn't my thing. The reason I need to do this is for a project and I am the only one that is willing to do this part.
I do not know how to properly convert character types or if it is possible. I have tried searching around the internet but have not found any answers regarding something like my issue here. Also, because I do not know what causes an illegal sizeof operand I do not know what is wrong here.
#include "..\STDInclude.h"
// TODO: Fill that list with names
char* Bots::NameList[] = {};
void Bots::GetNames()
{
using namespace std;
ifstream file("bot_names.txt");
if (file.is_open())
{
for (int i = 0; i < 48; i++)
{
file >> Bots::NameList[i];
}
}
}
void Bots::Initialize()
{
// Replace staff array with custom one
*(char***)Addresses::BotArray1 = Bots::NameList;
*(char***)Addresses::BotArray2 = Bots::NameList;
*(char***)Addresses::BotArray3 = Bots::NameList;
// Apply new array size
int size = (sizeof(Bots::NameList) / sizeof(Bots::NameList[0]));
*(BYTE*)Addresses::BotArraySize1 = size;
*(BYTE*)Addresses::BotArraySize2 = size;
*(BYTE*)Addresses::BotArraySize3 = size;
*(BYTE*)Addresses::BotArraySize4 = size;
}
Arrays in C++ are of fixed size. So when you write char* Bots::NameList[] = {} , you have an empty array of c-strings (aka char*).
Worse, when you later write file >> Bots::NameList[i]; you are writing null terminated c-strings to uninitialized pointers, which will cause memory corruption.
Unless fundamental rewrite, this code is doomed to fail. I strongly suggest that you replace use of char* with std::string and that you switch from fixed size arrays to vectors.
std::vector<std::string> Bots::NameList;
void Bots::GetNames()
{
...
for (int i = 0; i < 48; i++)
{
string s; // space separated strings ? sure ?
file >> s; // or getline(file, s) if you want lines
NameList.push_back(s);
}
}
}
Aditional remark:
I can't tell for sure, as I don't know the definition of Addresses members, but statements like the following are relatively suspicious:
*(char***)Addresses::BotArray1 = Bots::NameList;
It suggests that Addresses::BotArray1 is an array or a pointer. But the fact that you are casting with (char***) suggest that you tried to fix a type mismatch. And dereferencing the casted pointer will make sense only if BotArray points already to a valid char** pointer in which the address of NameList should be stored.
In C++ an array must be sized when created and then it is fixed, so char* Bots::NameList[] = {}; is a zero element array and is stuck that way. Worse, in file >> Bots::NameList[i] nothing ever allocated storage for Bots::NameList[i], so your program is writing into uninitialized memory. Probably a BOOM waiting to happen. I'm going to suggest something completely different.
in the Bots class definition:
std::vector<std::string> NameList;
Then later...
void Bots::GetNames()
{
std::ifstream file("bot_names.txt");
if (file.is_open())
{
for (int i = 0; i < 48; i++)
{
std::string temp;
file >> temp;
NameList.push_back(temp);
}
}
}
Addresses::BotArray1..N must also become std::vectors and Addresses::BotArraySize1..N are made redundant because vectors know their size.
[edit] Outside of this get method (see below), i'd like to have a pointer double * result; and then call the get method, i.e.
// Pull results out
int story = 3;
double * data;
int len;
m_Scene->GetSectionStoryGrid_m(story, data, len);
with that said, I want to a get method that simply sets the result (*&data) by reference, and does not dynamically allocate memory.
The results I am looking for already exist in memory, but they are within C-structs and are not in one continuous block of memory. Fyi, &len is just the length of the array. I want one big array that holds all of the results.
Since the actual results that I am looking for are stored within the native C-struct pointer story_ptr->int_hv[i].ab.center.x;. How would I avoid dynamically allocating memory like I am doing above? I’d like to point the data* to the results, but I just don’t know how to do it. It’s probably something simple I am overlooking… The code is below.
Is this even possible? From what I've read, it is not, but as my username implies, I'm not a software developer. Thanks to all who have replied so far by the way!
Here is a snippet of code:
void GetSectionStoryGrid_m( int story_number, double *&data, int &len )
{
std::stringstream LogMessage;
if (!ValidateStoryNumber(story_number))
{
data = NULL;
len = -1;
}
else
{
// Check to see if we already retrieved this result
if ( m_dStoryNum_To_GridMap_m.find(story_number) == m_dStoryNum_To_GridMap_m.end() )
{
data = new double[GetSectionNumInternalHazardVolumes()*3];
len = GetSectionNumInternalHazardVolumes()*3;
Story * story_ptr = m_StoriesInSection.at(story_number-1);
int counter = 0; // counts the current int hv number we are on
for ( int i = 0; i < GetSectionNumInternalHazardVolumes() && story_ptr->int_hv != NULL; i++ )
{
data[0 + counter] = story_ptr->int_hv[i].ab.center.x;
data[1 + counter] = story_ptr->int_hv[i].ab.center.y;
data[2 + counter] = story_ptr->int_hv[i].ab.center.z;
m_dStoryNum_To_GridMap_m.insert( std::pair<int, double*>(story_number,data));
counter += 3;
}
}
else
{
data = m_dStoryNum_To_GridMap_m.find(story_number)->second;
len = GetSectionNumInternalHazardVolumes()*3;
}
}
}
Consider returning a custom accessor class instead of the "double *&data". Depending on your needs that class would look something like this:
class StoryGrid {
public:
StoryGrid(int story_index):m_storyIndex(story_index) {
m_storyPtr = m_StoriesInSection.at(story_index-1);
}
inline int length() { return GetSectionNumInternalHazardVolumes()*3; }
double &operator[](int index) {
int i = index / 3;
int axis = index % 3;
switch(axis){
case 0: return m_storyPtr->int_hv[i].ab.center.x;
case 1: return m_storyPtr->int_hv[i].ab.center.y;
case 2: return m_storyPtr->int_hv[i].ab.center.z;
}
}
};
Sorry for any syntax problems, but you get the idea. Return a reference to this and record this in your map. If done correctly the map with then manage all of the dynamic allocation required.
So you want the allocated array to go "down" in the call stack. You can only achieve this allocating it in the heap, using dynamic allocation. Or creating a static variable, since static variables' lifecycle are not controlled by the call stack.
void GetSectionStoryGrid_m( int story_number, double *&data, int &len )
{
static g_data[DATA_SIZE];
data = g_data;
// continues ...
If you want to "avoid any allocation", the solution by #Speed8ump is your first choice! But then you will not have your double * result; anymore. You will be turning your "offline" solution (calculates the whole array first, then use the array elsewhere) to an "online" solution (calculates values as they are needed). This is a good refactoring to avoid memory allocation.
This answer to this question relies on the lifetime of the doubles you want pointers to. Consider:
// "pointless" because it takes no input and throws away all its work
void pointless_function()
{
double foo = 3.14159;
int j = 0;
for (int i = 0; i < 10; ++i) {
j += i;
}
}
foo exists and has a value inside pointless_function, but ceases to exist as soon as the function exits. Even if you could get a pointer to it, that pointer would be useless outside of pointless_function. It would be a dangling pointer, and dereferencing it would trigger undefined behavior.
On the other hand, you are correct that if you have data in memory (and you can guarantee it will live long enough for whatever you want to do with it), it can be a great idea to get pointers to that data instead of paying the cost to copy it. However, the main way for data to outlive the function that creates it is to call new, new[], or malloc. You really can't get out of that.
Looking at the code you posted, I don't see how you can avoid new[]-ing up the doubles when you create story. But you can then get pointers to those doubles later without needing to call new or new[] again.
I should mention that pointers to data can be used to modify the original data. Often that can lead to hard-to-track-down bugs. So there are times that it's better to pay the price of copying the data (which you're then free to muck with however you want), or to get a pointer-to-const (in this case const double* or double const*, they are equivalent; a pointer-to-const will give you a compiler error if you try to change the data being pointed to). In fact, that's so often the case that the advice should be inverted: "there are a few times when you don't want to copy or get a pointer-to-const; in those cases you must be very careful."
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");
}
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?