accessing an array through pointer - c++

I wanted to create a database like class through OOP. In this class, there are 3 arrays which act as columns in a table.I insert data through insert() function and prints data through printEntries() function. But that function can't access the arrays to retrieve data.
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
using namespace std;
class subject{
public:
int numOfStudents;
string subjectId;
int * marksArray;
int * indexArray;
char * gradeArray;
int index ; // index for inserting data
subject(int students , string subjectName){
numOfStudents = students;
subjectId = subjectName;
this->index =0 ;
//creating and pointing to arrays
int A[numOfStudents]; marksArray = A;
int B[numOfStudents]; indexArray = B;
char C[numOfStudents]; gradeArray = C;
}
void insert(int studentId , int mark , char grade){
indexArray[index] = studentId;
marksArray[index] = mark;
gradeArray[index] = grade;
this->index = this->index +1;
}
int getNumberOfEntries(){
return index ;
}
void printEntries(){
cout<< indexArray[0] << " O" << marksArray[0] << " " << gradeArray[0] << endl;
cout<< indexArray[1] << " OOO" << marksArray[1] << " " << gradeArray[1] << endl;
cout<< indexArray[2] << " OO" << marksArray[2] << " " << gradeArray[2] << endl;
}
};
int main(int argc, char const *argv[]){
subject S(10,"Mathematics");
cout<<S.subjectId<<endl;
cout<<S.numOfStudents<<endl;
S.insert(35,34,'A');
S.insert(33,34,'B');
S.insert(54,34,'C');
S.insert(21,34,'D');
S.insert(14,34,'F');
S.printEntries();
return 0;
}
output is :
Mathematics
10
35 O34 A
0 OOO0

As pointed out by #paddy in the comments to your question, your issue is within the constructor.
//creating and pointing to arrays
int A[numOfStudents]; marksArray = A;
int B[numOfStudents]; indexArray = B;
char C[numOfStudents]; gradeArray = C;
What you are doing is saving the address of the very first element and the rest disappears after you leave the constructor. you are lucky that it's even allowing you to save the first insert and to quote the comment what you are doing is "defined is undefined behavior"
Replacing the pointers with std::vectors and inserting you elements there will be must easier.
class subject
{
public: // It's considered bad practive to have public data members in a class
std::vector<int> marksVector;
std::vector<int> indexVector;
std::vector<char> gradeVector;
// ...
void insert(int studentId , int mark , char grade){
indexVector.push_back(studentId);
marksVector.push_back(mark);
gradeVector.push_back(grade);
// No longer need to worry about index for next insert
}
};

Related

C++ Unable to assign Character Array Variable to String Variable

I am in need of assistance.
I am trying to create a vector structure where the string contents inside of a char array get automatically assign to another STRING variable within the same structure.
After countless hours, I have not been able to figure it out. When I used function such as string(). It doesn't copy anything. I can't seem to assign char variable to string variable. Please advise.
#include <iostream>
#include <ctime>
#include <fstream>
#include <string>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
const int NAME_SIZE = 25;
struct tableInfo
{
char name2[NAME_SIZE];
string name = str(name2); // I need name string to equal name2 character variable
string info;
string link;
};
vector<tableInfo> table(6);
bool compareByWord(const tableInfo &lhs, const tableInfo &rhs);
int main()
{
cin.getline(table[0].name2, 51);
cin.getline(table[1].name2, 51);
cin.getline(table[2].name2, 51);
cin.getline(table[3].name2, 51);
cin.getline(table[4].name2, 51);
sort(table.begin(), table.end(), compareByWord);
cout << table[0].name << endl;
cout << table[1].name << endl;
cout << table[2].name << endl;
cout << table[3].name << endl;
cout << table[4].name << endl;
}
bool compareByWord(const tableInfo &lhs, const tableInfo &rhs)
{
unsigned int length = lhs.name.length();
if (rhs.name.length() < length)
length = rhs.name.length();
int sameLetters = 0;
for (unsigned int i = 0; i < length; ++i)
{
if (sameLetters == length)
return false;
if (tolower(lhs.name[i]) == tolower(rhs.name[i]))
{
++sameLetters;
continue;
}
return(lhs.name[i] < rhs.name[i]);
return(lhs.name[i] < rhs.name[i]);
}
return false;
}
If you want something to happen in a structure (or class), consider making sure it happens by using the constructor. You will need to change your vector so you can no longer default construct the struture, but that's ok.
This works, by enforcing the two fields contain identical data (not withstanding 25 no being long enough):
const int NAME_SIZE = 25;
struct tableInfo
{
tableInfo(char * whatever); //Make it so
char name2[NAME_SIZE];
string name;
string info;
string link;
};
tableInfo::tableInfo(char *whatever)
: name(whatever)
{
strncpy(name2, whatever, NAME_SIZE); //Now they match - unless whatever was too big
}
//vector<tableInfo> table(6);//no longer ok with the non-default constructor
bool compareByWord(const tableInfo &lhs, const tableInfo &rhs);
int main()
{
vector<tableInfo> table;
for (int i = 0; i < 5; ++i)
{
char name2[NAME_SIZE];
cin.getline(name2, 51); //Do you really mean 51?
// It's smaller than NAME_SIZE
table.emplace_back(name2);
}
sort(table.begin(), table.end(), compareByWord);
cout << table[0].name << endl;
cout << table[1].name << endl;
cout << table[2].name << endl;
cout << table[3].name << endl;
cout << table[4].name << endl;
}
How about doing like this:
struct tableInfo
{
char name2[NAME_SIZE];
string name;
string info;
string link;
tableInfo(const char* in_name)
{
memset(name2, 0, NAME_SIZE);
strncpy(name2, in_name, NAME_SIZE - 1);
name = string(name2);
}
};
How to use:
char tmp[NAME_SIZE];
cin.getline(tmp, 51);
table[0] = tableInfo(tmp);
I argue that you don't even need an array in the struct. Just use std::string. getline supports reading into a std::string and you can access individual characters using str[]. If you need to get a pointer to the data you can use str.c_str().
If you really need to use an array in the struct you can create a member function to return a std::string:
struct tableName {
char name[NAME_SIZE];
std::string info;
std::string link;
std::string nameString() const { return name; }
};

c++ - Memory Heap, Set up an array dynamically

i have a problem, i think it has to do with heap memory.
would appreciate help.
this is in tribe header:
Survivor* SurvivorsArray = new Survivor[MaxSurvivorsInTribe];
it's my problem.
when i write
Survivor* SurvivorsArray = new Survivor[MaxSurvivorsInTribe];
i get this problem:
EXE3.exe has triggered a breakpoint.
this is take my in code to:
if (_crtheap == 0) {
#if !defined (_CRT_APP) || defined (_DEBUG)
_FF_MSGBANNER(); /* write run-time error banner */
_NMSG_WRITE(_RT_CRT_NOTINIT); /* write message */
#endif /* !defined (_CRT_APP) || defined (_DEBUG) */
__crtExitProcess(255); /* normally _exit(255) */
}
return HeapAlloc(_crtheap, 0, size ? size : 1);
}
but if i write:
Survivor* SurvivorsArray = new Survivor[100];
so it's work without error.
Currently it only works if I set up a preset array but if I want to get the array size from the user I get an error.
main:
#include <iostream>
#include <string>
using namespace std;
#include "survivor.h"
#include "tribe.h"
int main(){
Tribe t1;
Tribe t2;
char nameTribe1[20];
int maxTribe1;
cout << "Enter name of first tribe: " << endl;
cin >> nameTribe1;
cout << "Enter max of survivors to first tribe(max 100): " << endl;
cin >> maxTribe1;
t1.tribe(nameTribe1, maxTribe1);
char nameTribe2[20];
int maxTribe2;
cout << "Enter name of second tribe: " << endl;
cin >> nameTribe2;
cout << "Enter max of survivors to second tribe(max 100): " << endl;
cin >> maxTribe2;
t2.tribe(nameTribe2, maxTribe2);
return 0;
}
survivor headr:
class Survivor{
public:
char NameOfSurvivor[20];
int Age;
double StartWidgth;
double FinalWidgth;
void survivor(char name[20], int age, double sWidgth);
};
#endif
survivor cpp:
#include "survivor.h"
#include <iostream>
using namespace std;
void Survivor::survivor(char name[20], int age, double sWidgth){
for (int i = 0; i < 20; i++)
NameOfSurvivor[i] = name[i];
Age = age;
StartWidgth = sWidgth;
FinalWidgth = -1;
}//end survivor
tribe header:
class Tribe{
public:
char NameOfTribe[20];
int MaxSurvivorsInTribe;
**Survivor* SurvivorsArray = new Survivor[MaxSurvivorsInTribe];**
int NumbersOfSurvivorsInTribe;
void tribe(char name[20], int maxSurvivor);
};
#endif
tribe cpp:
#include "tribe.h"
#include <string>
#include <iostream>
using namespace std;
void Tribe::tribe(char name[20], int maxSurvivor){
for (int i = 0; i < 20; i++)
NameOfTribe[i] = name[i];
for (int i = 0; i < maxSurvivor; i++){
for (int j = 0; j < 20; j++){
SurvivorsArray[i].NameOfSurvivor[j] = ' ';
}//end for
SurvivorsArray[i].Age = 0;
SurvivorsArray[i].StartWidgth = 0;
SurvivorsArray[i].FinalWidgth = 0;
MaxSurvivorsInTribe = maxSurvivor;
NumbersOfSurvivorsInTribe = 0;
}//end for
}//end tribe
thank's.
You can't perform dynamic allocations inside a class declaration. Move array allocation to to the Tribe constructor.
By the way, unless you're forbidden from using the STL for some reason, it will be much better to use a vector instead of an array.
MaxSurvivorsInTribe seems to be not initialized, when you allocate memory for array. It can have any integer value by default. You can use pointer as a field and initialize it in constructor:
class Tribe{
...
int MaxSurvivorsInTribe;
Survivor* SurvivorsArray;
Tribe(char* name, int maxSurvivor){
MaxSurvivorsInTribe = maxSurvivor;
Survivor* SurvivorsArray = new Survivor[MaxSurvivorsInTribe];
....
}
And don't forget to free memory in destructor:
~Tribe(){
delete Survivor;
}
You need to reed more about classes in c++ and dynamic arrays.
Your constructors aren't formatted correctly, you put:
void tribe(char name[20], int maxSurvivor);
but it should be
Tribe(char name[20], int maxSurvivor);
Since it couldn't be initialized correctly, MaxSurvivorsInTribe wasn't set and couldn't be used.
Then in main, you'll initialize it like this:
char nameTribe1[20];
int maxTribe1;
cout << "Enter name of first tribe: " << endl;
cin >> nameTribe1;
cout << "Enter max of survivors to first tribe(max 100): " << endl;
cin >> maxTribe1;
Tribe t1(nameTribe1, maxTribe1);
Your code is failing because it is trying to call the new function to create the buffer with an undefined size. When you first declare your tribe variables like this:
Tribe t1;
Tribe t2;
You are triggering the implicit default constructor, which is going to attempt to create an object. The value you are using for the array size, MaxSurvivorsInTribe is a local field of the Tribe class that is not then initialized to any value.
You should probably do some code restructuring where you collect the size and name of each tribe before you instantiate your tribe objects, and then provide a constructor that accepts the max size and name values that also allocates the space needed for your array. Something like:
int main(){
char nameTribe1[20];
int maxTribe1;
cout << "Enter name of first tribe: " << endl;
cin >> nameTribe1;
cout << "Enter max of survivors to first tribe(max 100): " << endl;
cin >> maxTribe1;
char nameTribe2[20];
int maxTribe2;
cout << "Enter name of second tribe: " << endl;
cin >> nameTribe2;
cout << "Enter max of survivors to second tribe(max 100): " << endl;
cin >> maxTribe2;
Tribe t1(nameTribe1,maxTribe1);
Tribe t2(nameTribe2,maxTribe2);
}
And for tribe:
class Tribe{
public:
char NameOfTribe[20];
int MaxSurvivorsInTribe = 0;
Survivor* SurvivorsArray = nullptr;
int NumbersOfSurvivorsInTribe = 0;
Tribe(char name[20], int maxSurvivor) : MaxSurvivorsInTribe(maxSurvivor)
{
SurvivorArray = new Survivor[MaxSurvivorsInTribe ];
}
};
As others have noted, you would be even better served if you used a std::vector as your container and even a std::string to hold your name to avoid potential errors.
class Tribe{
public:
std::string NameOfTribe;
int MaxSurvivorsInTribe = 0;
std::vector<Survivor> SurvivorsArray;
int NumbersOfSurvivorsInTribe = 0;
Tribe(std::string name, int maxSurvivor) : MaxSurvivorsInTribe(maxSurvivor), NameOfTribe(name)
{
}
};

Passing array of strings to a function

I am trying to create a program that uses class, arrays, and functions to show information about two students(Name, id#, classes registered). The part I am struggling with is passing arrays to a function. How do I do that?
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
class Student // Student class declaration.
{
private:
string name;
int id;
string classes;
int arraySize;
public:
void setName(string n)
{
name = n;
}
void setId(int i)
{
id = i;
}
void setClasses(string c, int num)
{
classes = c;
arraySize = num;
}
string getName()
{
return name;
}
int getId()
{
return id;
}
void getClasses()
{
for (int counter=0; counter <arraySize; counter++) {
cout << classes[counter] << endl;
}
}
};
int main()
{
//Student 1
string s1Name = "John Doe";
int s1Id = 51090210;
int const NUMCLASSES1 = 3;
string s1Classes[NUMCLASSES1] = {"C++","Intro to Theatre","Stagecraft"};
//Student 2
string s2Name = "Rick Harambe Sanchez";
int s2Id = 666123420;
int const NUMCLASSES2 = 2;
string s2Classes[NUMCLASSES2] = {"Intro to Rocket Science","Intermediate Acting"};
//
Student info;
info.setName(s1Name);
info.setId(s1Id);
//info.setClasses(s1Classes, NUMCLASSES1);
cout << "Here is Student #1's information:\n";
cout << "Name: " << info.getName() << endl;
cout << "ID: " << info.getId() << endl;
//cout << "Classes: " << info.getClasses() << endl;
info.setName(s2Name);
info.setId(s2Id);
// info.setClasses(s2Classes, NUMCLASSES1);
cout << "\n\nHere is student #2's information:\n";
cout << "Name: " << info.getName() << endl;
cout << "ID: " << info.getId() << endl;
//cout << "Classes: " << info.getClasses() << endl;
return 0;
}
The usual way to pass around variable-length lists in C++ is to use an std::vector. A vector is a single object that you can easily pass to a function, copying (or referencing) its contents. If you are familiar with Java, it's basically an ArrayList. Here is an example:
#include <vector>
#include <string>
using namespace std;
class foo {
private:
vector<string> myStrings;
public:
void setMyStrings(vector<string> vec) {
myStrings = vec;
}
}
//...
foo myObj;
vector<string> list = {"foo","bar","baz"};
myObj.setMyStrings(list);
If don't want to use the standard library though, you can pass an array C-style. This involves passing a pointer to the first element of the array, and the length of the array. Example:
void processStrings(string* arr, int len) {
for (int i = 0; i < len; i++) {
string str = arr[i];
//...
}
}
string array[] = {"foo","bar","baz"};
processStrings(array, 3); // you could also replace 3 with sizeof(array)
Passing raw arrays like this, especially if you wanted to then copy the array into an object, can be painful. Raw arrays in C & C++ are just pointers to the first element of the list. Unlike in languages like Java and JavaScript, they don't keep track of their length, and you can't just assign one array to another. An std::vector encapsulates the concept of a "list of things" and is generally more intuitive to use for that purpose.
Life lesson: use std::vector.
EDIT: See #nathanesau's answer for an example of using constructors to initialize objects more cleanly. (But don't copy-paste, write it up yourself! You'll learn a lot faster that way.)
You can pass array of any_data_type to function like this
void foo(data_type arr[]);
foo(arr); // If you just want to use the value of array
foo(&arr); // If you want to alter the value of array.
Use std::vector. Also, don't add functions you don't need. Here's an example of using std::vector
#include <string>
#include <iostream>
#include <vector>
using std::string;
using std::vector;
class Student // Student class declaration.
{
private:
vector<string> classes;
string name;
int id;
public:
Student (const vector<string> &classesUse, string nameUse, int idUse) :
classes (classesUse),
name (nameUse),
id (idUse)
{
}
void print ()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Id: " << id << std::endl;
std::cout << "Classes: ";
for (int i = 0; i < classes.size (); i++)
{
if (i < classes.size () - 1)
{
std::cout << classes[i] << ", ";
}
else
{
std::cout << classes[i] << std::endl;
}
}
std::cout << std::endl;
}
};
int main()
{
Student John ({"C++","Intro to Theatre","Stagecraft"},
"John",
51090210);
John.print ();
Student Rick ({"Intro to Rocket Science","Intermediate Acting"},
"Rick",
666123420);
Rick.print ();
return 0;
}
Name: John
Id: 51090210
Classes: C++, Intro to Theatre, Stagecraft
Name: Rick
Id: 666123420
Classes: Intro to Rocket Science, Intermediate Acting
In the private variables of class Student, you are storing a string:
String classes;
where as you should be storing an array of strings like:
String classes[MAX_NUM_CLASSES];
then in the set classes function, pass in an array of strings as the first argument, so it should be :
void setClasses(string[] c, int num)
{
classes = c; //not sure if simply setting them equal will work, rather copy entire array using a for loop
arraySize = num;
}
This should point you in the right direction
Also, use std::vector instead of string[], it will be easier.

How do you change the value of a single member of a struct pointer?

#include <iostream>
#include <cstring>
using namespace std;
struct Student {
int no;
char grade[14];
};
void set(struct Student* student);
void display(struct Student student);
int main( ) {
struct Student harry = {975, "ABC"};
set(&harry);
display(harry);
}
void set(struct Student* student){
struct Student jim = {306, "BBB"};
*student = jim; // this works
//*student.no = 306; // does not work
}
void display(struct Student student){
cout << "Grades for " << student.no;
cout << " : " << student.grade << endl;
}
How can I change just one member of the structure with a pointer? Why does *student.no = 306 not work? Just a bit confused.
If you have a pointer to a struct, you should use -> to access it's members:
student->no = 306;
This is syntactic sugar for doing (*student).no = 306;. The reason yours didn't work is because of operator precedence. Without the parentheses, the . has higher precedence than *, and your code was equivalent to *(student.no) = 306;.
operator* has very low precedence, so you have to control the evaluation with parenthesis:
(*student).no = 306;
Though it can always be done as:
student->no = 306;
which in my opinion is much easier.
You should use
student->no = 36
While we are at it, it is not a good practice to pass structs by value to functions.
// Use typedef it saves you from writing struct everywhere.
typedef struct {
int no;
// use const char* insted of an array here.
const char* grade;
} Student;
void set(Student* student);
void display(Student* student);
int main( ) {
// Allocate dynmaic.
Student *harry = new Student;
harry->no = 957;
harry->grade = "ABC";
set(harry);
display(harry);
}
void set(Student *student){
student->no = 306;
}
void display(Student *student){
cout << "Grades for " << student->no;
cout << " : " << student->grade << endl;
delete student;
}

C++ simple class declaration program

I got a program to create in C++ in our introduction to C++ class in school. I am doing everything as I got in examples, but still getting errors.
w4x.cpp was given and I have to create Molecule.h and Molecule.cpp. I did that, but I am getting errors because my variables were not declared in scope, but I can't understand why.
// w4x.cpp
#include <iostream>
using namespace std;
#include "w4x.h"
#include "Molecule.h"
int main() {
int n = MAX_MOLECULES;
Molecule molecule[MAX_MOLECULES];
cout << "Molecular Information\n";
cout << "=====================" << endl;
for (int i = 0; i < MAX_MOLECULES; i++) {
if (!molecule[i].read()) {
n = i;
i = MAX_MOLECULES;
}
cout << endl;
}
cout << "Structure Name Mass\n";
cout << "==================================================" << endl;
for (int i = 0; i < n; i++)
molecule[i].display();
}
//Molecule.h
const int MAX_STRUCT = 10;
const int MAX_NAME = 20;
class Molecule {
char name[MAX_STRUCT];
char rate[MAX_NAME];
double weight;
public:
Molecule();
void read(const char*, const char*, double);
void display() const;
~Molecule();
};
//Molecule.cpp
#include <iostream>
#include <cstring>
using namespace std;
#include "Molecule.h"
Molecule::Molecule(){
name[0]= '\0';
rate[0]= '\0';
weight = 0;
}
void::read(const char* n, const char* r, double w) {
weight = w;
strncpy (name, n, MAX_STRUCT);
name[MAX_STRUCT]='\0';
strncpy (rate, r, MAX_NAME);
rate[MAX_NAME]='\0';
cout << "Enter structure : ";
cin.getline (n, MAX_CHARS);
cout << "Enter full name : ";
cin.getline (r, MAX_NAME);
cout << "Enter weight : ";
cin >> w;
}
void::display() const
{
int x;
for ( x=0; x<i; x++)
cout << n << " " << r << " " << w << endl;
}
My first question is, how can I pass char name[MAX_STRUCT]; char rate[MAX_NAME]; double weight; from Molecule.h to Molecule.cpp
The problem with your definitions is here:
void::read(const char* n, const char* r, double w)
and here
void::display() const
What :: says here, is that you are implementing a function within a class. So you need to specify which class and which function! What you are telling it now, is that you are implementing a function inside class void, which is nonexistent.
You should convert them to:
void Molecule::read(const char* n, const char* r, double w)
void Molecule::display() const
Your other question regarding passing class members:
The functions of a class have access to its variables, therefore, you don't need to concern yourself with that. Just use the variables.
Also, if you notice in your w4x.cpp, the function Molecule::read() is called without parameters, so your TAs ask you to implement it without parameters. Indeed, since you have access to Molecule::name, Molecule::rate and Molecule::weight directly, you should read data and write to those variables instead of asking for parameters. Therefore, your read function would look like this:
void Molecule::read()
{
// read into name, rate and weight
}
Furthermore, w4x.cpp expects read to report whether it has been successful or not. This means that you should do error checking in Molecule::read and return 0 if no errors or -1 (for example) in case of errors.