Question of dynamic memory allocation and dynamic memory deallocation - c++

I need someone to solve the problem which is a question of dynamic memory allocation and
dynamic deallocation.
Here's a part of code to create database
include <iostream>
#include <string>
using namespace std;
struct subject {
string subname;
int score;
string grade;
float gpa;
};
struct student {
string stuname;
int stunum;
int subnum;
subject *sub;
float avegpa = 0;
};
int main(void){
int i = 0;
cout << "Put number of students : ";
cin >> i;
student* p = new student[i];
.
.
.
delete p->sub;
delete[] p;
return 0;
}
here's my desired result
Now, I have to enter the value of i first, but I hope I can automatically set
the value of i.
In order to try number 1, I pushed back value of i and increased i, but there was an
error. I don't know why.
This is the error message from number 2.
C++ crt detected that the application wrote to memory after end of heap buffer

delete p->sub;
You never initialised p[0].sub. Deleting (or even reading) an uninitialised pointer will result in undefined behaviour. You may delete only what you new.
P.S. Owning bare pointers are a bad idea. I recommend using std::vector to manage dynamic arrays.

Related

Error when trying to print out array in a loop using cout

#include <cstdio>
#include <iostream>
int main (){
int n;
std::cin>>n;
int*a;
for (int i=0;i<n;i++){
std::cin>>a[i];
}
for(int i=0;i<n;i++){
std::cout<<a[i];
}
return 0;
}
I just started working on a problem and I wanted to check if I knew how to read and array and make a sample output array. When I include the second loop program crashes as soon as I enter n and the first number With the following message
3 1
Process returned -1073741819 (0xC0000005) execution time : 4.943 s
Press any key to continue.
int *a; is a pointer to an integer, it is just a pointer to some memory, it has no memory allocated on its own. Since you are dereferencing this pointer a[i] without setting it up first, your compiler should even give you some warning telling that you are using a variable that has not been initialized.
0xC0000005 error code in Windows means access violation. In this case, you are trying to write to some memory which you don't have access to.
You need to allocate memory before you can read or write to it.
If you know beforehand how many entries you will have, you can do static memory allocation, if you don't, then you need to do dynamic memory allocation.
For instance, if you knew that you would need only 20 entries at max, you could easily swap int *a; for int a[20];.
But since you are only getting to know how many entries there will be when the program runs, then you need to go for dynamic memory allocation: int *a = new int[n];.
So your code should be
#include <cstdio>
#include <iostream>
int main (){
int n;
std::cin>>n;
int *a = new int[n];
for (int i=0;i<n;i++){
std::cin>>a[i];
}
for(int i=0;i<n;i++){
std::cout<<a[i];
}
delete[] a; // Release allocated memory.
return 0;
}
You need to allocate memory for a, otherwise the behaviour of the program is undefined. Writing
int* a = new int[n];
would to it, followed by delete[] a; when you're all done (put this just before return 0;).
Alternatively, use a std::vector<int> a(n); and all the memory allocation will be taken care of for you.
Try : int a[20]; rather than int *a;
Your a doesn't point to any valid memory, resulting in undefined behaviour.
What you need is an std::vector :
#include <vector>
int n;
std::cin>>n;
std::vector<int> numbers;
for (int i=0;i<n;i++){
int val;
std::cin>>val;
numbers.push_back(val);
}
for(int i=0;i<n /* or numbers.size()*/ ;i++){
std::cout<< numbers[i];
}
This takes care of dynamic allocation for you so that you don't have to do the dirty stuff yourself.
There are a few issues with your code. Primarily, you request the number 'n' then need to allocate enough space to store that many integers.
The best way to do that is to use vector. You can create this with:
std::vector< int > numbers( n );
You can also create it allocating the memory but waiting until you have data:
std::vector< int > numbers;
numbers.reserve( n );
You also should probably validate your input, for example your input stream (cin) will be invalid if the user enters something that is not an integer, and the original 'n' should be positive if you are going to try to create a vector of that size, and you may need to set a limit or you will suffer a bad_alloc. If you do not mind suffering a bad_alloc you should catch that exception and print an error such as "There is insufficient space to allocate as many numbers".
Of course if you enter a high number like 10 million, you may find the compiler is able to allocate that many but your user will get bored in your loop when you ask him to enter integers 10 million times.
You do not need <cstdio> as a header. You will need <vector> and <iostream>.
int* is a pointer to int, not an array.
To create an array of int, example: int a[100]; - where 100 is the size
Moreover, you should use a std::vector<int> instead:
vector<int> vec;
for (int i = 0; i != n; ++i) {
int temp;
cin >> temp;
vec.emplace_back(temp);
}

Memory corruption when cin in c++

I have got class "student.cpp"
#include <iostream>
#include "student.h"
using namespace std;
void student::setMarks(int m1, int m2) {
mark1 = m1;
mark2 = m2;
};
void student::setName(char *n) {
name = n;
};
int student::calc_media(void){
return (mark1+mark2)/2;
};
void student::disp(void){
cout << "Student:" << name << " \n media:"<< calc_media() <<"\n";
};
student::student(){
mark1 = 0;
mark2 =0;
name = "";
};
Header file "student.h":
ifndef CLASY_STUDENT_H
#define CLASY_STUDENT_H
#endif //CLASY_STUDENT_H
class student{
char *name;
int mark1, mark2;
public:
void setName(char *n);
void setMarks(int m1, int m2);
void disp(void);
int calc_media(void);
student();
};
And "main.cpp":
#include <iostream>
#include "student.h"
using namespace std;
int main() {
student s;
char* n;
int m1, m2;
cout << "Enter name:";
cin>> n;
cout << "Enter marks of two subjects:";
cin>> m1;
cin>> m2;
s.setName(n);
s.setMarks(m1, m2);
s.disp();
return 0;
}
I am running this usign Clion and Cmake is :
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
set(SOURCE_FILES main.cpp student.cpp student.h student.cpp student.h)
But when I run, it asks for name, but when I type something then I have got a memory fragmentation error. Whats wrong?
And could someone by the way tell me if it looks okey for C++? I am trying to switch from java to c++.
char* n;
...
cin>> n;
n is a pointer, supposed to point at a particular piece of memory. But you never set it. So it has some undefined value, pointing who-knows-where into some memory that you end up trying to overwrite. Most likely memory you are not allowed to overwrite, causing a segfault.
Don't try to use char* if you don't yet know about manual memory management (and once you do, you'll understand why not to). Use std::string.
From a quick glance, you can pretty much replace char* everywhere with std::string (as long as you #include <string>).
Similar to what others are saying, your variable n is an uninitialized pointer. Pointers, as the name suggests, are just signposts to a particular location in memory - the tell the CPU "go to this memory location for variable x".
Say you have an integer variable var, which is declared like this:
int var;
That variable occupies memory and you can assign it a value like this:
var = 5;
You can also declare a pointer to an integer like this:
int * var_ptr;
Now assuming var_ptr points to a valid integer I can assign a value to it like this:
*var_ptr = 5;
This says "put the number 5 at the memory location pointed to by var". However if var_ptr has not been initialized then it will point to a random location in memory that may overwrite something important, or attempt to write to a protected memory address causing a protection fault (segfault). This is what is happening in your code.
To initialize var_ptr to point to the address of var, we can do this:
var_ptr = &var;
The ampersand is the "address of" operator - it says "don't get me the value of var but instead get me the address of the memory location where var is stored".
So, to prevent your problem, you must initialize n to some valid memory location where you are able to safely write some data.
There are a few ways to do this. As #Stefan points out you can declare n to be a character array:
char n[20];
As #BobTFish points out you need some way to make sure that your input doesn't exceed the size of your array (20 bytes in this case). The solution is std::cin.width(20).
As #BobTFish also mentions, you could also using a std::string, like this:
std::string n;
std:cin >> n;
The std::string object will automatically take care of memory allocation.
If you really must use a char *, you can either take the address of a char array (here I take the address of the first element of the array):
char n_array[20];
char *n = &n_array[0];
std::cin.width(20);
std::cin >> n;
You could also use dynamic memory allocation:
char *n = new char[20];
std::cin.width(20);
std::cin >> n;
delete n;
Notice that if you use dynamic memory allocation you must free the memory using delete when you are done otherwise there will be a memory leak. Local variables (like the array) are allocated on the stack and therefore are automatically freed when the function returns. For this reason, and the overhead of dynamic memory allocation, you would be insane to use it here.

C++ Dumping stack trace to *.exe.stackdump

Was writing some code for an assignment to take integers as input and place them in an array to be printed.
I'm cleaning up all of my pointers as far as I can tell but I keep getting the runtime error:
1 [main] new 3444 cygwin_exception::open_stackdumpfile: Dumping stack trace to new.exe.stackdump
body of code:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int array[10];
int * p = array;
int *readNumbers()
{
int i=0;
for(i=0;i<10;i++)
{
string number;
int numb;
cout << "enter digit " << i << " of 10" << endl;
getline(cin, number);
istringstream (number) >> numb;
array[i]=numb;
}
return p;
delete p;
}
void printNumbers(int *numbers,int length)
{
int i;
for(i=0;i<length;i++)
{
cout << i << " " << *(numbers+i) << endl;
}
}
and the main calling code:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
extern int *readNumbers();
extern void printNumbers(int *,int);
int main()
{
int * q = readNumbers();
printNumbers(q,10);
delete q;
return 0;
}
So just looking for a solution to the stack dump...
Also I'm sure the method I used to apply the string number returned by cin to the values contained in array[10] is not what the question was looking for so any notes on that would be great.
Thanks
It is not a good practice to return a pointer to a memory allocated inside a function, in this case, you are not even allocating it inside a function, you have done it in a global space.
It is a good practice to activate all your warnings during the compile, even treat them as error when you are doing an assignment.
As a tip, you can allocate the memory in your main function and then pass the pointer to the readNumbers function.T This way it remains inside the same scope and it is easier to manage.
also, the same way you pass the lenght of the array to the printnumbers function you should pass it to the readnumbers one instead of hardcoding it.
Your delete are invalid, you can only delete something you've allocated with new.
The first one is harmless because it's after a return, so never executed (BTW you should look at compiler warnings).
The second one might produce your crash.
Also I'm sure the method I used to apply the string number returned by cin to the values contained in array[10] is not what the question was looking for so any notes on that would be great.
That's OK. What's dubious is spreading the size of the array everywhere, what happens if you want to change it ?

Program crashes when running this function

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).

Dynamically allocated string array, then change it's value?

I'm trying to create a string array and use a pointer to modify it. I'm not sure how to declare the pointer since strings can vary in length, and I think this is what causes the error.
My code looks something like this:
#includes <string>
#includes <iostream>
using namespace std;
string *users = NULL;
int seatNum = NULL;
cin >> seatNum;
users = new string[seatNum];
string name;
cin >> name;
users[seatNum] = name;
It throws me an Write Access Violation when I try to change its value. From what I've read it's because strings are compiled as read-only, so my question is how would I/what would I do to change it? Easy-to-understand explanations would be preferable.
You're accessing memory beyond the range of the allocated array
users = new string[seatNum];
users[seatNum] = name;
The first element is [0]. The last is [seatNum-1]
You have created an array of seatNum elements. Array element indexing starts at 0 therefore the range of valid indexes is [0, seatNum - 1]. By accessing users[seatNum] = ... you are effectively going past the last valid element of the array. This invokes UB (undefined behavior).
I see you have already made the right choice of using std::string instead of C-style strings. Why not make the same choice over arrays?
#include <string>
#include <array>
#include <iostream>
int main(int, char*[]) {
int seatNum = 0;
std::cin >> seatNum;
std::vector<std::string> users(seatNum);
std::cin >> users[0];
return 0;
}
Try to avoid pointers and C-style arrays, especially dynamic ones.
A few things:
int seatNum will be allocated on the stack and will never be NULL. You should set it to 0.
You are setting users[seatNum] which is out of bounds causing your program to crash. You
can only use indices from 0 to seatNum-1.
Updated: Chris is correct. I looked into it and strings are indeed mutable in C++.
firstly you cannot set null value to int type data
int seatNum = NULL; // wrong
int seatNum = 0; // right
secondly string bounds from 0 to seatnum -1
users[seatNum-1] = name; // right