c++ dynamic stuct pointer to char array - c++

I'm having trouble dynamically assigning memory to a char array inside a pointer to a struct.
This is a homework assignment that has to use this struct outline:
struct Student
{
char *namePtr;
unsigned int score;
};
this is the part im having trouble with though
/***************************
* takes value from temporary value and puts into dynamic allocated Student array
***************************/
bool updateStructPtr(Student **info, unsigned int index, char *name, unsigned int score)
{
try
{
info[index]->namePtr = new char [strlen(name)+1];
if(DEBUG) cout << "size for dynamic char: " << strlen(name)+1 << endl << endl;
//copy char array into new array
strcpy(info[index]->namePtr, name);
info[index]->score = score;
}
catch (bad_alloc & param)
{
info[index]->namePtr = NULL;
return false;
}
return true;
}
my prof said:
A glance at your code reveals that you do not seem to be dynamically allocating memory for the Student structure as specified in the first sentence of step 3-2 of the algorithm I provided you.
3-2. Dynamically allocate memory for a Student structure. Place the address of this Student structure in the array of structure pointers. You will also need to dynamically allocate just enough memory to store the name. Do not store the quote characters. Populate the fields of the Student structure with the two items from Step 3-1.
The pointers in the pointer array point to random locations in memory and you are trying to use these random addresses. That could certainly explain why the program crashes. Actually there are many ways to crash this program and all steps must be followed carefully to avoid this.
but i have no idea how to fix this or where to begin.

SO isn't really intended for help with your homework.
That being said, the instructions from your teacher are quite elaborate and correct. You'll have to use new Student and new Student[] at one point or another to actually update the Student ** info that is passed to you in order to add that new Student struct you're supposed to add.

I'm guessing Student instances are not allocated before the function is called. You would have to allocate a new instance of Student via new Student and store it into info at index.
info[index] = new Student;

Related

Trying to understand C++ pointers and data type initializations

I am trying to learn C++, I have a fair bit of experience in C# and the 2 languages are so dissimilar and I am having trouble understanding data types and pointer variants of data types and the initialization of them, please consider the code below:
wchar_t *array = new wchar_t[10]; //Declaring a pointer of wchart_t and initializing to a wchar_t array of size 10 ?
auto memAddressOfPointer = &array; //auto is resolving memAddressOfPointer to a pointer of a pointer?
cout << array << endl; //Printing the memory address of array not the object created above?
cout << *array << endl; //Getting the actual value of the object (empty wchar_t array of size 10 in bytes?
cout << &array << endl; //Printing the address of the obj?
cout << memAddressOfPointer << endl; //Printing the address of the obj ?
My question is why would I create a pointer and initialize it? Why not just create an array of wchar_t? like:
wchar_t array [10];
I refer to this stack post as well:
Unable to create an array of wchar_t
Thank you for your consideration.
If you know the size of the number of elements you need to put in the array, then just use the array i.e., wchar_t arr[10];.
If you don't know the size, you can create the array at runtime using dynamic memory allocation with the required size i.e., wchar_t *arr = new wchar_t[required_size]. Once the memory is allocated, you need to deallocate it using delete[] operator for arrays and delete for non-array pointers. However I highly recommend you don't do that and instead either
Use std::wstring in this particular case which will automatically handle this for you.
Use std::vector for everything else if you can. It's a dynamic array which will grow automatically. No manual memory management etc.
In case you have to use pointers, use a smart pointer like unique_ptr or shared_ptr. The advantage of using smart pointers is that they will automatically clean up once they go out of scope.
If you know the extent of the array when writing the program, there's absolutely nothing wrong with wchar_t array [10];. If 10 is a fixed (constexpr) number - stick with that.
What wchar_t *array = new wchar_t[10]; lets you do is to let 10 be a number that you find out in run-time. You can change 10 to x and let x be a number that the user supplies or that you calculate somehow. wchar_t array [x]; when x is not a constexpr is on the other hand not valid C++ (but is available as an exension, called VLA, in some implementations).
Note: One downside with using new is that you need to make sure you delete the same pointer. This is not always simple. Using these raw pointers is therefore not what you usually want to do. Instead, use a smart pointer, like std::unique_ptr<wchar_t[]>, and the resource will be delete[]d when the pointer goes out of scope.
The advantages of creating a pointer instead of an array are the dynamic allocation that you can take advantage of and also the properties of the pointer that might help.
Consider the following code that represent the dynamic allocation and reallocation:
int x;
cin >> x;
int *oldArr = malloc(x * sizeof(int));
for(int i = 0; i < x; i++)
arr[i] = i;
cin >> x;
arr = realloc(arr, x * sizeof(int));
Here is another example that shows one of the pointer features which also you can use along with arrays.
int arr[5] = {1, 2, 3, 4 ,5};
int *ptr = arr;
cout << *ptr;
ptr++;
cout << *ptr;
cout << *(ptr + 1);
Despite these advantages and others, I think that the example you are presenting of using pointers instead of arrays is just for academic purposes to understand how to work with pointers in order to build more complex data structures using pointers in future lessons as you are using constant size arrays.

Storing and accessing an array of struct from shared memory

I am writing a program on a hotel reservation system and have declared a struct Room as follows:
struct Room {
bool isavailable;
bool ispaid;
string customer;
string date;
};
I use a variable read from an input file to create an array of n structs which is all the rooms in the hotel.
struct Room* rooms = new Room[numOfRooms];
I then create the shared memory space and attach it, but when I try to access it after, it doesn't seem to work.
//creates shared memory space
if((shmid = shmget(shmkey, 1000, IPC_CREAT | 0666)) < 0) {
perror("Failed to allocate shared mem");
exit(1);
}
//attaches shared memory to process
Room* shared_memory;
shared_memory = (Room* ) shmat(shmid, NULL, 0);
if(!shared_memory) {
perror("Error attaching");
exit(0);
}
struct Room *PTR = rooms; //temp pointer to rooms array
cout << "test: " << rooms[1].customer << endl; //print before storing in shared memory
rooms = (struct Room*) shared_memory+sizeof(int); //places rooms array in shared memory
delete [] PTR; //deletes the memory location where rooms was stored before being in shared memory
cout << "test: " << rooms[1].customer << endl; //print after storing in shared mem
As you can see I have a cout statement before moving rooms into shared memory which prints the correct thing, but the after cout is empty. Any help would be greatly appreciated, thanks.
rooms = (struct Room*) shared_memory+sizeof(int); //places rooms array in shared memory
This line does not do what your comment says. First, shared_memory is already declared as Room* shared_memory so the cast is unnecessary. Adding sizeof(int) (let's assume that is 4) to a pointer will make the pointer point to the 4th such element, that is if shared_memory was pointing to the first element of a Room arr[N] array, the expression shared_memory + i is equal to &arr[i]. In this case, shared_memory+sizeof(int) is a pointer to the 4th (or sizeof(int)'th) element -- or rather where that element would be in the shared_memory because you just created the shared memory and haven't put any actual Rooms in there yet.
Finally, rooms = ... just assigns a value to the pointer. So now the rooms variable (which is a pointer, just a number basically) points to the place where the 4th Room object in the shared_memory array would be. It's not copying the array created with new Room[numOfRooms] or anything like that.
See also: How do pointer to pointers work in C?
What you want to do is copy the objects into shared memory. For that in general you could use std::copy like so:
std::copy(&rooms[0], &rooms[numOfRooms], shared_memory);
But the problem will be that std::string contains a pointer to a char array which you can assume to be allocated with new char[length_of_string]. (This is a simplified version of the truth, but enough for this.) The std::copy above will not move this internal array into shared memory, therefore it will not work if you map the shared memory in another process and access the string data. (You might read memory garbage or you might segfault when trying to access unmapped memory.) To solve this, you need to use an allocator type that can allocate from the shared memory, or store strings inline with something like a struct ShortString{ char data[/*max length*/ 20]; }. You'll want to search for or post another question if you need help with that.

dynamic memory allocation to a struct type [duplicate]

This question already has answers here:
c++ memory error when using malloc/realloc/free on std::string
(2 answers)
Closed 4 years ago.
I am trying to allocate memory to structure dynamically but i am getting error while allocation the memory dynamically
#include <string>
using namespace std;
#define MAX_GRADES 5
typedef struct _Student
{
string id;
string name;
double grades[MAX_GRADES];
double average;
}Student;
Student *update_list;
int main()
{
Student *n = (*Student) malloc(sizeof(n));
return 0;
}
main.cpp: In function ‘int main()’:
main.cpp:26:24: error: expected primary-expression before ‘)’ token
Student *n = (*Student) malloc(sizeof(Student));
^
TL;DR version
Use
Student *n = new Student;
instead of
Student *n = (*Student) malloc(sizeof(n));
Explanation
This is a typo
Student *n = (*Student) malloc(sizeof(n));
^ wrong side.
You want
Student *n = (Student*) malloc(sizeof(n));
^ needs to be here.
This will compile. Normally I would leave a comment and vote to close but there are two things wrong with this solution that you'll find at runtime.
n is a pointer. sizeof(n) will give the size of a pointer which is guaranteed to be shorter than a string (unless the string implementation is incredibly awesome and doing things I can't even imagine). You would want sizeof(*n) to get the size of a Student if the next point didn't render this point useless.
std::string is a fairly complex class. It is only valid if at least one of its many constructors successfully initializes the class. malloc is a C function. C doesn't know what a constructor is, so no string constructor is run. This leaves id and name ticking time bombs waiting to blow your program up. Do not malloc a C++ class unless you know the class is a POD type or will be using placement new before use.
Use new here or do not dynamically allocate at all.
Student *n = (*Student) malloc(sizeof(n));
(*Student) is not a type, you want (Student*). Also, sizeof n gives the size of a pointer on your system, not the size needed for one or more Students. Correct way:
Student *n = (Student*) malloc(sizeof(*n));
However, as pointed out in the answer of user4581301, your Student is not POD so you have to use new to ensure constructors are being called:
Student *n = new Student;
or, if you want more than one Student
Student *n = new Student[42];
Please remember that all memory allocated using new must be deallocated using delete and all memory allocated using new[] with delete[].
But the use of raw owning pointers is considered bad practice and should be avoided in favour of smart pointers like std::unique_ptr<> and std::shared_ptr<> or containers:
The C++-way would be using std::vector<Student>.
Also, there is no reason to use a typedef for a structure in C++.
There are three mistakes in your code:
The cast right before malloc should be (Student *): this is the correct type of n, i.e., a pointer to Student.
The size to allocate is sizeof(Student): sizeof(n) would give you the size of a pointer, most probably too small for Student.
Most important: you should never use malloc to allocate memory for a struct which contains a complex object like a string. You must use instead new, see the discussion here.
A correct code would be
#include <string>
using namespace std;
#define MAX_GRADES 5
struct Student
{
string id;
string name;
double grades[MAX_GRADES];
double average;
};
Student *update_list;
int main()
{
Student *n = new Student;
delete n;
return 0;
}
I have added a delete n at the end: it is not necessarily to run the code correctly, but it is a good practice to not forget to delete the allocated memory.
Even better, rather than using a #define to fix the size of the array grades you should use a template parameter: in this way MAX_GRADES does not propagate in all the following code. Finally, in general it is better to avoid using namespace std; in the header part. This is because, if you ever split the declaration of Student in a separate header file, than every code file which include such a header will "inherit" the using namespace std; which could, possibly, collide with other included headers.
In summary an even better version of your code is
#include <string>
template <unsigned int MAX_GRADES>
struct Student
{
std::string id;
std::string name;
double grades[MAX_GRADES];
double average;
};
Student<5> *update_list;
int main()
{
Student<5> *n = new Student<5>;
delete n;
return 0;
}
The problem is in this part of the code:
int main()
{
Student *n = (*Student) malloc(sizeof(n));
return 0;
}
Understanding that '*' operator is an indirection operator in C++ would help in identifying the problem.
https://msdn.microsoft.com/en-us/library/caaw7h5s.aspx
You are not trying to extract value of Student structure, instead you are trying to type cast void * returned from malloc. Correct way to do it is:
Student *n = new Student (correct C++ way of doing things - using new operator)
This will give you a pointer to dynamically created Student structure. If you intend to create a dynamic array of Student, you would do:
Student *n = new Student[5]
Depending on your usage, you might want to consider an easy and C++ STL way of doing as: std::vector<Student> or std::list<Student>.
Look up for STL (Standard Template Libraries) in C++ and you should be able to get more details.
If you are in c++, don't use "malloc" to allocate memory if you can use "new":
Student* student = new Student();
In addition to allocating space, "new" will also call the struct's constructor which will allow for initialization. The syntax is also less error-prone.
You'll also notice my variable naming. In my example I chose "student" instead of "n" because it's more descriptive to the reader.

Taking value of Array size from user

I am doing an assignment for my university course and having the following trouble in my code:
cout << "Enter number of values you want to enter" << endl;
int Arraysize;
cin >> Arraysize;
int input_Arr[Arraysize];
The compiler gives an array saying that the array size has to be a constant. I have tried dynamically giving an array size, but that gives the same error. The only way it allows a variable as array size is , when the variable is made a const.
Can you tell me what is the way to get array size from the user and then declare array of that size?
Also , if you do so by dynamic memory allocation, please explain your code at each step.
Variable sized arrays are not standard C++, thus the compiler is not happy.
You have two options:
1) Use an std::vector, which dynamically grows in size automatically. However, since this is HW, you might not be allowed to use it just yet.
2) Use dynamic allocation of memory for your array, by using new and delete, like this:
#include <iostream>
using namespace std;
int main() {
int Arraysize;
cin >> Arraysize;
int *input_Arr = new int[Arraysize];
// Here you have an array called `input_Arr`, of size `Arraysize`, ready to be used (eg filled).
// when you are done with using the array, you must free the dynamic memory
delete [] input_Arr;
return 0;
}
The two points that require your attention are:
int *input_Arr = new int[Arraysize];
What it does? It dynamically allocates memory for an array called input_Arr, that will store ints. Its size is Arraysize.
Every time memory is allocated dynamically, it must gets free'd by the program. To do that, we use this code:
delete [] input_Arr;
which deletes an array called input_Arr.
If you want to use Dynamic allocation in C++, use keywords new and delete
code for this case will be
{
int size;
cin>>size;
int *my_array = new int[size]; //dynamic allocation
...
delete [] my_array; //don't forget to use delete at the end of your code
}

Null Pointers & Object Pointers

I was given instructions to show that a pointer variable can contain a pointer to a valid object, deleted object, null, or a random value. Set four pointer variables a,b,c, and d to show these possibilities. The the thing im not sure about are the pointer objects. Can someone explain what I need to do to show case these pointers. or if I did it right.
#include <iostream>
#include <string>
#include <time.h>
using namespace std;
class Pointer
{
public:
Pointer()
{
int num = 2;
}
Pointer(int num)
{
this->numb = num;
}
void set(int num)
{
numb = num;
}
int Get()
{
return numb;
}
private:
int numb;
};
int main ()
{
Pointer point;
Pointer* a;
a = &point;
Pointer*b = new Pointer(10);
delete b;
int* c = NULL;
srand(unsigned(time(0)));
int randNum = rand()%100;
int *d;
d = &randNum;
cout <<"Pointer a: " << a << endl;
cout <<"Pointer b: " << b << endl;
cout <<"Pointer c: " << c << endl;
cout <<"Pointer d: " << *d << endl;
//(*a) = (*b);
return 0;
}
Not a complete answer, because this is homework, but here’s a hint: once you generate random bits (The C++ STL way to do this is with <random> and perhaps <chrono>), you can store them in a uintptr_t, an unsigned integer the same size as a pointer, and convert those bits to a pointer with reinterpret_cast<void*>(random_bits). The results are undefined behavior. Trying to dereference the pointer might crash the program, or it might appear to work and corrupt some other memory location, or it might do different things on different runs of the program, but nothing you do with it is guaranteed to work predictably. This is Very Bad.
If “random” really means arbitrary, for this assignment, you could just declare a pointer off the stack (that is, inside a function and not static) and not initialize it. Ask your instructor if you aren’t sure.
That’s a very common source of irreproducible bugs, and I would recommend you get into the habit now of always initializing your pointer variables when you declare them. Often, that lets you declare them int * const, which is good practice, but even if you need to wait to assign a real value to them, if you initialize your pointers to NULL or nullptr, you will always see immediately in the debugger that the value is uninitialized, and you will always crash the program if you try to use it uninitialized.
I would like to first point out what the word NULL means or nullptr, which is what you should be using in C++11. The null pointer just assigns the pointer to an inaccessible address or location in the memory. This allows for safer code, because the "dangling pointers" left over could be bad.
A header file and another cpp file to define the class
Class Something{
// Class implementation here
};
Now lets go to the main.cpp file
#include "The header you made.hpp" // (.h or .hpp)
int main(int argc, char *argv[]){
Something objOne;
Something *objPointer = &objOne;
// Do stuff with objPointer
// Like use your member functions
Something *objPointerTwo = &objOne;
// Now objPointerTwo points to the same object
// Lets try some runtime allocation of memory
Something *objHeap = new Something();
// Do something with the pointer
// Watch this
delete objHeap;
objHeap = nulltpr;
// Now what happens when you try to access methods again with objHeap
// Your program will display a segmentation fault error
// Which means you are trying to mess with memory
// that the compiler does not want you too
}
All right so what is this memory? Well to put it simply you have the heap and the stack. All the stuff you put into your program is put into the stack when it is compiled. So when the program runs the code follows main and traces the stack kind of like a stack of boxes. You may get need to search through all the top ones to get to the bottom. Now what if a person didn't know for example how many students were going to be in the class that year. Well the program is already running how do you make more room? This is where the heap comes in. The new keyword allows you to allocate memory at runtime, and you can "point" to memory on the "heap" if you will. Now while this is all good and cool, it can be potentially dangerous which is why people consider C++ and C dangerous languages. When you are done using that memory on the heap you have to "delete" it so when the pointer moves, the memory does not get lost and cause problems. It is kind of like a sneaky ninja and it goes and causes trouble.
A good way to think about how pointers can be good for objects is if you create say a deck class, well how many cards does the user want we wont know until runtime, so lets have them type in the number, and we can allocate it on the heap! Look Below
int main(void){
int count;
Deck *deck = nullptr;
std::cout << "Enter amount of cards please:";
std::cin >> count;
deck = new Deck(count); // RUNTIME ALLOCATION ON HEAP!!!!
// This is so cool right, you can have a deck of any size
// Do stuff with deck
// Now that we are done with the deck don't forget to delete it
// We do not need all those cards on the heap anymore so....
delete deck; // Ahhh almost done
deck = nullptr; // Just in case since dangling pointers are weird
}
The key thing to understand here is, what is a pointer, what is it pointing to, and how do they work with the memory!