d2jsp
d2jsp Forums > Programmer's Haven > C/C++/C# > C++ Question
Add Reply New Topic New Poll
Yakir
#1 Sep 10 2019 08:47am
Group: Trade Moderator
Posts: 21,404
Joined: Dec 20 2005
Gold: 13,065.00
Trader: Mediator
So I have this assignment to create an array of class with dynamic memory.
Problem is that every time I try to get input from the user inside a for loop, I get memory error
Here's the code itself with comments aswell so you will understand what I'm aiming to do in each line
Code
#include <iostream>
#include <cstdlib>
#include <cstring>

using namespace std;
#pragma warning(disable : 4996)


class Web {
private:
char *webName;
char *webLink;
char *webDesc;

public:
Web();
Web(char * ,char * ,char *);
~Web();

void setWeb(char *,char *,char *);
char getWeb(char * ,char *,char *);
void displayWeb();

};
// Empty Constructor
Web::Web() { webName=NULL,webLink=NULL,webDesc=NULL; }
// Full Constructor
Web::Web(char *w, char *l, char *d) { strcpy(webName, w); strcpy(webLink, l); strcpy(webDesc, d); }
Web::~Web() {}

// Getters & Setters
void Web::setWeb(char *w, char*l, char *d) { strcpy(webName, w); strcpy(webLink, l); strcpy(webDesc, d); }
char Web::getWeb(char *,char *,char *) { return *webName; return *webLink; return *webDesc; }

// Display
void Web::displayWeb() { cout << "Webname is: " << " Url: " << " Description: " << getWeb(webName,webLink,webDesc) << endl; }


int main() {

// Declaring variables
char *name = NULL;
char *link = NULL;
char *desc = NULL;
int webInsertNumber = 0;

// Receiving amount of website to enter
cout << "Enter amount of website you wish to add:";
cin >> webInsertNumber;
// Allocate array of class of size recieived before
Web *arr;
arr= new (nothrow) Web[webInsertNumber];
if (arr == nullptr) {
cout << "Memory problems :(" << endl;
}
else {
for (int i = 0; i < webInsertNumber; i++)
{
// Enter each input to a variable
cout << "Enter Web name: ";
cin >> name;
cout << "Enter URL: ";
cin >> link;
cout << "Enter Description: ";
cin >> desc;
// Calling function to set variable to array
arr->setWeb(name, link, desc);
// Move pointer by one
arr++;
}
}
return 0;
}


Thanks in advance :)
Xaysia
#2 Sep 10 2019 10:33am
Group: Member
Posts: 13,806
Joined: Dec 9 2007
Gold: 590.00
Trader: Trusted
char *name = NULL;
cin >> name;

This is the problem. You try to store the input to a NULL memory slot. You need to allocate memory for the variables "name", "link" and "desc" in order to store the input.
The correct way of allocating memory (static memory) on the stack would be:

Code
char str[15];
cout << "enter a string";
cin >> str;


This creates a char array of 16 chars (starting from 0). However, this will become a problem later on since it will become a dangling pointer when you string-copy the variables (in your constructor).
To fix that, you need to first allocate the memory needed on the heap (dynamic memory) using malloc.
An example of that would be:

Code
char *name = (char *)malloc(sizeof(char)*100+1);
char *link = (char *)malloc(sizeof(char)*100+1);
char *desc = (char *)malloc(sizeof(char)*100+1);


This will allocate memory for a 101 bytes. Since 1 char is 1 byte, you need 100 bytes to store a 100 byte string. This will allow you to store a string consisting of 100 chars.
Note that when you ask for user input, an extra invisible char will be added to the output string which is called the null terminator (which marks the end of a string) and has the size of 1 char.
You need to allocate memory for that null terminator as well, which results in allocating memory for an extra char, aka 101 chars. If you are unsure, just allocate more memory than necessary.

Now that you have allocated your memory on the heap, you can just dereference the pointer instead of using strcpy in your class "Web". This means that you can just point the memory that you have allocated for the variable "name" in the main() function to the variable "name" in your class "Web".

However, for the next iteration, you will overwrite the data since you haven't allocated more memory for the new input. You need to allocate memory in every iteration instead (or on the stack at first, and store it in the heap in the constructor)
You can worry about freeing memory later on once you understand how the stack/heap works and once you've figured out how pointers work. :)

This post was edited by Xaysia on Sep 10 2019 10:58am
Yakir
#3 Sep 10 2019 11:50pm
Group: Trade Moderator
Posts: 21,404
Joined: Dec 20 2005
Gold: 13,065.00
Trader: Mediator
Quote (Xaysia @ Sep 10 2019 07:33pm)
char *name = NULL;
cin >> name;

This is the problem. You try to store the input to a NULL memory slot. You need to allocate memory for the variables "name", "link" and "desc" in order to store the input.
The correct way of allocating memory (static memory) on the stack would be:

Code
char str[15];
cout << "enter a string";
cin >> str;


This creates a char array of 16 chars (starting from 0). However, this will become a problem later on since it will become a dangling pointer when you string-copy the variables (in your constructor).
To fix that, you need to first allocate the memory needed on the heap (dynamic memory) using malloc.
An example of that would be:

Code
char *name = (char *)malloc(sizeof(char)*100+1);
char *link = (char *)malloc(sizeof(char)*100+1);
char *desc = (char *)malloc(sizeof(char)*100+1);


This will allocate memory for a 101 bytes. Since 1 char is 1 byte, you need 100 bytes to store a 100 byte string. This will allow you to store a string consisting of 100 chars.
Note that when you ask for user input, an extra invisible char will be added to the output string which is called the null terminator (which marks the end of a string) and has the size of 1 char.
You need to allocate memory for that null terminator as well, which results in allocating memory for an extra char, aka 101 chars. If you are unsure, just allocate more memory than necessary.

Now that you have allocated your memory on the heap, you can just dereference the pointer instead of using strcpy in your class "Web". This means that you can just point the memory that you have allocated for the variable "name" in the main() function to the variable "name" in your class "Web".

However, for the next iteration, you will overwrite the data since you haven't allocated more memory for the new input. You need to allocate memory in every iteration instead (or on the stack at first, and store it in the heap in the constructor)
You can worry about freeing memory later on once you understand how the stack/heap works and once you've figured out how pointers work. :)


So basically I needed to allocate the size of the actual string I'm going to receive as input from the user on each variable ( name,link,desc ) right?
Should I do this on every iteration of the for loop or lets say I decide on the maximum size once and that's it?

I don't mind override the data stored in those variables as I'm going to store them in the class called Web and using the function setWeb(); to allocate the memory.
but if I need to allocate the memory for each variable in main, shouldn't I do the same in the function aswell?

Thanks :)
Xaysia
#4 Sep 11 2019 06:01am
Group: Member
Posts: 13,806
Joined: Dec 9 2007
Gold: 590.00
Trader: Trusted
Quote (Yakir @ 11 Sep 2019 07:50)
So basically I needed to allocate the size of the actual string I'm going to receive as input from the user on each variable ( name,link,desc ) right?
Should I do this on every iteration of the for loop or lets say I decide on the maximum size once and that's it?

I don't mind override the data stored in those variables as I'm going to store them in the class called Web and using the function setWeb(); to allocate the memory.
but if I need to allocate the memory for each variable in main, shouldn't I do the same in the function aswell?

Thanks :)


Yes. You need to allocate the memory for the variables that will store the input from the console. Either dynamically (char *a = malloc()) or statically (char a[len]). What you choose to do doesn't really matter.
The important thing is that you allocate memory dynamically in your class (using malloc), since this data will be "saved" and should not be overwritten.

In main(), you can allocate new space every iteration, but it's less overhead to just allocate once and then overwrite the data in the variables in main() rather than allocating and freeing every iteration.

No problems bud :)
Yakir
#5 Sep 12 2019 05:51am
Group: Trade Moderator
Posts: 21,404
Joined: Dec 20 2005
Gold: 13,065.00
Trader: Mediator
Quote (Xaysia @ Sep 11 2019 03:01pm)
Yes. You need to allocate the memory for the variables that will store the input from the console. Either dynamically (char *a = malloc()) or statically (char a[len]). What you choose to do doesn't really matter.
The important thing is that you allocate memory dynamically in your class (using malloc), since this data will be "saved" and should not be overwritten.

In main(), you can allocate new space every iteration, but it's less overhead to just allocate once and then overwrite the data in the variables in main() rather than allocating and freeing every iteration.

No problems bud :)


So how should I allocate the memory of the array storing the class?
Code
// Receiving amount of website to enter
cout << "Enter amount of website you wish to add:";
cin >> webInsertNumber;
// Allocate array of class of size recieived before
Web *arr;
arr= new (nothrow) Web[webInsertNumber];
if (arr == nullptr) {
cout << "Memory problems :(" << endl;
}
else {


I want to have X number of stored information on each web depends on the size of the input the user entered.
I thought by new I will be able to do it but I can't move the pointer to the second position and then getting the same memory error.
Go Back To C/C++/C# Topic List
Add Reply New Topic New Poll