Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 5 years ago.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Improve this question
EDIT: Working code below
I'll paste my code below, but if someone could please explain to me why what's happening is happening instead of simply writing me out an answer, that'd be much appreciated, thank you!
Im having a compilation error, telling me there is no instance of overloaded function. I can circumvent this compilation error by commenting out the line cin.get(Kingdom.m_name, 32, '\n');, but this is obviously useless, because now my program just terminates after entering the name of the first Kingdom.
I assume the line void read(sict::Kingdom& Kingdom) forces the computer to cycle through my Kingdom array, based on user input.
//header file
#ifndef KINGDOM_H
#define KINGDOM_H
#include <cstdlib>
// TODO: sict namespace
namespace sict
{
// TODO: define the structure Kingdom in the sict namespace
struct Kingdom {
char m_name[32];
int m_population;
};
// TODO: declare the function display(...),
// also in the sict namespace
void display(const Kingdom& pKingdom);
void display(const Kingdom kingdoms[], size_t count);
}
#endif
`
//implementation .cpp
#include <iostream>
#include <cstdlib>
#include "Kingdom.h"
using namespace std;
// TODO: the sict namespace
namespace sict
{
// TODO:definition for display(...)
void display(const Kingdom& pKingdom) {
cout << pKingdom.m_name << ", " << "population " << pKingdom.m_population << endl;
}
void display(const Kingdom kingdoms[], size_t count) {
cout << "------------------------------" << endl;
cout << "Kingdoms of SICT" << endl;
cout << "------------------------------" << endl;
int pop = 0;
for (size_t i = 0; i < count; i++) {
cout << i + 1 << ". ";
display(kingdoms[i]);
pop += kingdoms[i].m_population;
}
cout << "------------------------------" << endl;
cout << "Total population of SICT: " << pop << endl;
cout << "------------------------------";
}
}
And my main,
#include <iostream>
#include <cstring> //for size_t definition
#include <vector>
#include "Kingdom.h"
using namespace std;
using namespace sict;
void read(Kingdom&);
int main() {
int count = 0; // the number of kingdoms in the array
// TODO: declare the pKingdom pointer here (don't forget to initialize it)
Kingdom *pKingdom = nullptr;
cout << "==========\n"
<< "Input data\n"
<< "==========\n"
<< "Enter the number of Kingdoms: ";
cin >> count;
cin.ignore();
if (count < 1) return 1;
// TODO: allocate dynamic memory here for the pKingdom pointer
pKingdom = new Kingdom[count];
for (int i = 0; i < count; ++i) {
cout << "Kingdom #" << i + 1 << ": " << endl;
// TODO: add code to accept user input for Kingdom i
read(pKingdom[i]);
}
cout << "==========" << endl << endl;
// testing that "display(...)" works
cout << "------------------------------" << endl
<< "The 1st Kingdom entered is" << endl
<< "------------------------------" << endl;
display(pKingdom[0]);
cout << "------------------------------" << endl << endl;
// expand the array of Kingdoms by 1 element
count = count + 1;
Kingdom *cpy_pKingdom = nullptr;
// TODO: allocate dynamic memory for count + 1 Kingdoms
cpy_pKingdom = new Kingdom[count];
// TODO: copy elements from original array into this newly allocated array
for (int i = 0; i < count; i++) {
cpy_pKingdom[i] = pKingdom[i];
}
// TODO: deallocate the dynamic memory for the original array
delete[] pKingdom;
// TODO: copy the address of the newly allocated array into pKingdom pointer
pKingdom = cpy_pKingdom;
// add the new Kingdom
cout << "==========\n"
<< "Input data\n"
<< "==========\n";
cout << "Kingdom #" << count << ": " << endl;
// TODO: accept input for the new element in the array
read(pKingdom[count - 1]);
cout << "==========\n" << endl;
// testing that the overload of "display(...)" works
display(pKingdom, count);
cout << endl;
// TODO: deallocate the dynamic memory here
//delete[] pKingdom;
//delete[] cpy_pKingdom;
getchar();
return 0;
}
// read accepts data for a Kingdom from standard input
//
void read(Kingdom& pkingdom) {
cout << "Enter the name of the Kingdom: ";
cin.get(pkingdom.m_name, 32, '\n');
cin.ignore(2000, '\n');
cout << "Enter the number of people living in " << pkingdom.m_name << ": ";
cin >> pkingdom.m_population;
cin.ignore(2000, '\n');
This can be quite the headache, and my hat goes off to all programmers out there that have all gone through this.
There are six overloads of istream::get. The arguments you are passing don't match any of them. That's why the compiler fails to compile that line.
The problem is that you are using char for the name member variable of Kingdom. That does not sound right. A name is usually a string. It char cannot be used to represent a name.
You can change name to be of type std::string or an array of char. If you use an array of char, you can use the function call like you have.
struct Kingdom {
char m_name[32]; // Since you are passing 32 to cin.get
int m_population;
};
You use std::string for name, you need to use std::getline.
struct Kingdom {
std::string m_name;
int m_population;
};
and ...
std::getline(std::cin, Kingdom.m_name);
I would recommend using std::string. They are much easier to work with.
istream::get has the following overloads (courtesy of http://en.cppreference.com/w/cpp/io/basic_istream/get):
(1) int_type get();
(2) basic_istream& get( char_type& ch );
(3) basic_istream& get( char_type* s, std::streamsize count );
(4) basic_istream& get( char_type* s, std::streamsize count, char_type delim );
(5) basic_istream& get( basic_streambuf& strbuf );
(6) basic_istream& get( basic_streambuf& strbuf, char_type delim );
You are calling get with three arguments, and out of the overloads above, only (4) matches.
As you can see, it expects a char pointer as its first argument, where as you are passing a char. (m_name)
I think you meant to define m_name as a char array (char m_name[128] for example), since that would be much more reasonable.
Related
Working code fixed and below
Here's the whole .cpp. Any thoughts why it's printing out pure garbage when the overload void display(const Kingdom kingdoms[], size_t count) function is called?
File Kingdom.h
#ifndef KINGDOM_H
#define KINGDOM_H
#include <cstdlib>
// TODO: sict namespace
namespace sict
{
// TODO: define the structure Kingdom in the sict namespace
struct Kingdom {
char m_name[32];
int m_population;
};
// TODO: declare the function display(...),
// also in the sict namespace
void display(const Kingdom& pKingdom);
void display(const Kingdom kingdoms[], size_t count);
}
#endif
File Kingdom.cpp
#include <iostream>
#include <cstdlib>
#include "Kingdom.h"
using namespace std;
// TODO: the sict namespace
namespace sict
{
// TODO:definition for display(...)
void display(const Kingdom& pKingdom) {
cout << pKingdom.m_name << ", " << "population " << pKingdom.m_population << endl;
}
void display(const Kingdom kingdoms[], size_t count) {
cout << "------------------------------" << endl;
cout << "Kingdoms of SICT" << endl;
cout << "------------------------------" << endl;
int pop = 0;
for (size_t i = 0; i < count; i++) {
cout << i + 1 << ". ";
display(kingdoms[i]);
pop += kingdoms[i].m_population;
}
cout << "------------------------------" << endl;
cout << "Total population of SICT: " << pop << endl;
cout << "------------------------------";
}
}
File main.cpp
#include <iostream>
#include <cstring> //for size_t definition
#include <vector>
#include "Kingdom.h"
using namespace std;
using namespace sict;
void read(Kingdom&);
int main() {
int count = 0; // the number of kingdoms in the array
// TODO: declare the pKingdom pointer here (don't forget to initialize it)
Kingdom *pKingdom = nullptr;
cout << "==========\n"
<< "Input data\n"
<< "==========\n"
<< "Enter the number of Kingdoms: ";
cin >> count;
cin.ignore();
if (count < 1) return 1;
// TODO: allocate dynamic memory here for the pKingdom pointer
pKingdom = new Kingdom[count];
for (int i = 0; i < count; ++i) {
cout << "Kingdom #" << i + 1 << ": " << endl;
// TODO: add code to accept user input for Kingdom i
read(pKingdom[i]);
}
cout << "==========" << endl << endl;
// testing that "display(...)" works
cout << "------------------------------" << endl
<< "The 1st Kingdom entered is" << endl
<< "------------------------------" << endl;
display(pKingdom[0]);
cout << "------------------------------" << endl << endl;
// expand the array of Kingdoms by 1 element
count = count + 1;
Kingdom *cpy_pKingdom = nullptr;
// TODO: allocate dynamic memory for count + 1 Kingdoms
cpy_pKingdom = new Kingdom[count];
// TODO: copy elements from original array into this newly allocated array
for (int i = 0; i < count; i++) {
cpy_pKingdom[i] = pKingdom[i];
}
// TODO: deallocate the dynamic memory for the original array
delete[] pKingdom;
// TODO: copy the address of the newly allocated array into pKingdom pointer
pKingdom = cpy_pKingdom;
// add the new Kingdom
cout << "==========\n"
<< "Input data\n"
<< "==========\n";
cout << "Kingdom #" << count << ": " << endl;
// TODO: accept input for the new element in the array
read(pKingdom[count - 1]);
cout << "==========\n" << endl;
// testing that the overload of "display(...)" works
display(pKingdom, count);
cout << endl;
// TODO: deallocate the dynamic memory here
//delete[] pKingdom;
//delete[] cpy_pKingdom;
getchar();
return 0;
}
// read accepts data for a Kingdom from standard input
//
void read(Kingdom& pkingdom) {
cout << "Enter the name of the Kingdom: ";
cin.get(pkingdom.m_name, 32, '\n');
cin.ignore(2000, '\n');
cout << "Enter the number of people living in " << pkingdom.m_name << ": ";
cin >> pkingdom.m_population;
cin.ignore(2000, '\n');
The obvious offending lines (there may be others) are
cpy_pKingdom = new Kingdom[count + 1];
cpy_pKingdom = pKingdom;
delete[] pKingdom;
pKingdom = cpy_pKingdom;
The assignment cpy_pKingdom = pKingdom is a pointer assignment, and does not copy any array. It also discards the result of the new expression, and means that both cpy_pKingdom and pKingdom have the original value that pKingdom had.
The delete [] pKingdom then releases memory pointed to by pKingdom which is also (because of the preceding assignment cpy_pKingdom = pKingdom) the memory pointed to by cpy_Kingdom.
The net effect of these four lines is that the new Kingom[count + 1] is leaked (it is allocated, never released, but also inaccessible) and that both pKingdom and cpy_pKingdom point at deallocated memory.
Even worse, the next statement that does anything with pKingdom is
read(pKingdom[count + 1]);
which reads data from a file into the non-existent pKingdom[count + 1]. And bear in mind that - even if the previous code had make pKingdom point at the memory allocated by new Kingdom[count + 1] - this would be writing past the end of that memory. Also undefined behaviour.
And then we get to
display(pKingdom, count);
which will access that same non-existent memory to print out the data there.
Displaying the garbage here is a minor consequence of one or more of the preceding instances of undefined behaviour in your code.
Goal state: I'm supposed to display a result where by randomized e.g. Set S = {dog, cow, chicken...} where randomized size can be 1-12 and animals cannot be replicated so once there is cow, there cannot be another cow in Set S anymore.
Error: I've been displaying a correct randomized size of 1-12. However I have duplicated animals even though I tried to check whether the animal exist in set S before I insert it into Set S.
UPDATE: I couldnt get it to run after the various updates by stackoverflow peers.
Constraints: I have to use pointers to compare with pointers - dynamically.
"Important Note
All storages used for the arrays should be dynamically created; and delete them when
they are no longer needed.
When accessing an element of the array, you should access it via a pointer, i.e. by
dereferencing this pointer. Using the notation, for example set [k] or *(set + k)
accessing to the kth element of the set is not allowed."
Do hope to hear your advice, pals!
Best regards,
MM
/*
MarcusMoo_A2.cpp by Marcus Moo
Full Time Student
I did not pass my assignment to anyone in the class or copy anyone’s work;
and I'm willing to accept whatever penalty given to you and
also to all the related parties involved
*/
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
/* Global Declaration */
const int MAX = 12; // 12 animals
const int MAXSTR = 10;
typedef char * Element;
static Element UniversalSet [MAX] = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon",
"Snake", "Horse", "Sheep", "Monkey", "Rooster", "Dog", "Pig"};
/* Functions */
// Construct a set
void option0(int); // Menu Option 0
void constructSet (Element *, int); // Construct a set
bool checkElement (Element *, Element *, int); // Check element for replicates
int main()
{
// Declarations
int mainSelect;
int size=rand()%12+1; // Random construct
srand (time(NULL)); // Even better randomization
cout << "Welcome to MARCUS MOO Learning Center" << endl;
do
{
cout << "0. An example of set" << endl;
cout << "1. Union" << endl;
cout << "2. Intersection" << endl;
cout << "3. Complement" << endl;
cout << "4. Subset of" << endl;
cout << "5. Equality" << endl;
cout << "6. Difference " << endl;
cout << "7. Distributive Law" << endl;
cout << "9. Quit" << endl;
cout << endl;
if (mainSelect==0)
{
option0(size);
}
cout << "Your option: ";
cin >> mainSelect;
cout << endl;
} while(mainSelect!=9);
return 0;
}
/* Functions */
// Option 0 - An example of set
void option0 (int size)
{
// Mini Declaration
int again;
Element *S;
do
{
cout << "Here is an example on set of animals" << endl;
cout << endl;
// Build set S
constructSet (S,size);
// Display set S
Element *S = &S[0];
cout << "Set S = {";
for (int i = 0; i < size; i++)
{
if (i!=size)
{
cout << *S
<< ", ";
}
else
{
cout << *S
<< "}"
<< endl;
}
S++;
}
cout << endl;
cout << "Note that elements in S are distinct are not in order" << endl;
cout << endl;
// Option 0 2nd Part
cout << "Wish to try the following operations?" << endl;
cout << "1. Add an element to the set" << endl;
cout << "2. Check the element in the set" << endl;
cout << "3. Check the cardinality" << endl;
cout << "9. Quit" << endl;
cout << endl;
cout << "Your choice: ";
cin >> again;
} while (again!=9);
}
// Construct a set
void constructSet (Element *set, int size)
{
// Declarations
Element *ptrWalk;
ptrWalk = &set[0];
int randomA=0;
for (int i = 0;i<size;i++)
{
bool found = true;
while (found)
{
randomA = rand()%MAX; // avoid magic numbers in code...
*ptrWalk = UniversalSet [randomA];
// Ensure no replicated animals in set S
found = checkElement (ptrWalk, set, i);
}
set=ptrWalk;
set++;
}
}
bool checkElement (Element *ptrWalk, Element *set, int size)
{
for (int j=0; j<size;j++)
{
if (ptrWalk==&set[j])
{
return true;
}
}
return false;
}
You have 2 different major problems in your code. First has already be given by Federico: checkElement should return true as soon as one element was found. Code should become simply (but please notice the < in j<size):
bool checkElement (char *ptrWalk, int size)
{
for (int j=0; j<size;j++)
{
if (ptrWalk==S[j])
{
return true;
}
}
return false;
}
The second problem is that you should not search the whole array but only the part that has already been populated. That means that in constructSet you should call checkElement(ptrWalk, i) because the index of current element is the number of already populate items. So you have to replace twice the line
found = checkElement (*ptrWalk, size);
with this one
found = checkElement (*ptrWalk, i);
That should be enough for your program to give expected results. But if you want it to be nice, there are still some improvements:
you correctly declared int main() but forgot a return 0; at the end of main
you failed to forward declare the functions while you call them before their definition (should at least cause a warning...)
you make a heavy use of global variables which is not a good practice because it does not allow easy testing
your algorithms should be simplified to follow the Dont Repeat Yourself principle. Code duplication is bad for future maintenance because if forces to apply code changes in different places and omission to do so leads to nasty bugs (looks like this is bad but I've already fixed it - yes but only in one place...)
constructSet could simply be:
// Construct a set
void constructSet (Element *set, int size)
{
// Declarations
//Element *ptrBase;
voidPtr *ptrWalk;
ptrWalk = &set[0];
int randomA=0;
for (int i = 0;i<size;i++)
{
bool found = true;
while (found) {
randomA = rand()%MAX; // avoid magic numbers in code...
*ptrWalk = UniversalSet [randomA];
// Ensure no replicated animals in set S
found = checkElement (*ptrWalk, i);
}
ptrWalk++;
}
}
Main problem is that 'break' is missing in checkElement() once it finds the element. If you do not break the loop, it will compare with other indices and overwrite the 'found' flag.
if (ptrWalk==S[j])
{
found = true;
break;
}
Also, use ptrWalk as temporary variable to hold the string. Add the string to S only after you make sure that it is not present already.
void constructSet (Element *set, int size)
{
// Declarations
//Element *ptrBase;
Element ptrWalk;
//ptrWalk = &set[0];
int randomA=0;
int randomB=0;
bool found = false;
for (int i = 0;i<size;i++)
{
randomA = rand()%12;
ptrWalk = UniversalSet [randomA];
// Ensure no replicated animals in set S
found = checkElement (ptrWalk, i);
if (found==true)
{
do
{
// Define value for S
randomB = rand()%12;
ptrWalk = UniversalSet [randomB];
found = checkElement (ptrWalk, i);
} while(found==true);
S[i] = UniversalSet [randomB];
//ptrWalk++;
}
else
{
// Define value for S
S[i] = UniversalSet [randomA];
//ptrWalk++;
}
}
}
You need to optimize your code by removing unnecessary variables and making it less complex.
I have fixed this with the guidance of my C++ lecturer! You guys may take a reference from this to solve your pointers to pointers dilemma next time! Cheers!
/*
MarcusMoo_A2.cpp by Marcus Moo
Full Time Student
I did not pass my assignment to anyone in the class or copy anyone’s work;
and I'm willing to accept whatever penalty given to you and
also to all the related parties involved
*/
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
/* Global Declaration */
const int MAX = 12; // 12 animals
const int MAXSTR = 10;
typedef char * Element;
static Element UniversalSet [MAX] = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon",
"Snake", "Horse", "Sheep", "Monkey", "Rooster", "Dog", "Pig"};
/* Functions */
// Construct a set
void option0(int); // Menu Option 0
void constructSet (Element *, int); // Construct a set
bool checkElement (Element, Element *, int); // Check element for replicates
// This function is to get a random element
// with storage allocated
Element getAnElement ()
{
Element *p = &UniversalSet [0];
int k = rand () % MAX;
for (int i = 0; i < k; i++)
++p;
Element e = new char [MAXSTR];
strcpy (e, *p);
return e;
}
int main()
{
// Declarations
int mainSelect;
int size=rand()%12; // Random construct
srand (time(NULL)); // Even better randomization
cout << "Welcome to MARCUS MOO Learning Center" << endl;
do
{
cout << "0. An example of set" << endl;
cout << "1. Union" << endl;
cout << "2. Intersection" << endl;
cout << "3. Complement" << endl;
cout << "4. Subset of" << endl;
cout << "5. Equality" << endl;
cout << "6. Difference " << endl;
cout << "7. Distributive Law" << endl;
cout << "9. Quit" << endl;
cout << endl;
if (mainSelect==0)
{
option0(size);
}
cout << "Your option: ";
cin >> mainSelect;
cout << endl;
} while(mainSelect!=9);
return 0;
}
/* Functions */
// Option 0 - An example of set
void option0 (int size)
{
// Mini Declaration
int again;
Element *S;
// You need to assign storage
S = new Element [MAX];
for (int i = 0; i < MAX; i++)
S [i] = new char [MAXSTR];
do
{
cout << "Here is an example on set of animals" << endl;
cout << endl;
// Build set S
constructSet (S,size);
// Display set S
Element *p = &S[0]; // Change to p
cout << "Set S = {";
for (int i = 0; i < size; i++)
{
if (i!=size-1)
{
cout << *p
<< ", ";
}
else
{
cout << *p
<< "}"
<< endl;
}
p++;
}
cout << endl;
cout << "Note that elements in S are distinct are not in order" << endl;
cout << endl;
// Option 0 2nd Part
cout << "Wish to try the following operations?" << endl;
cout << "1. Add an element to the set" << endl;
cout << "2. Check the element in the set" << endl;
cout << "3. Check the cardinality" << endl;
cout << "9. Quit" << endl;
cout << endl;
cout << "Your choice: ";
cin >> again;
} while (again!=9);
}
// Construct a set
void constructSet (Element *set, int size)
{
// Declarations
Element *ptrWalk;
ptrWalk = &set[0];
int randomA=0;
Element temp = new char [MAXSTR];
for (int i = 0;i<size;i++)
{
bool found = true;
while (found)
{
// randomA = rand()%MAX; ..
temp = getAnElement ();
// Ensure no replicated animals in set S
found = checkElement (temp, set, i);
}
// set=ptrWalk;
// set++;
strcpy (*ptrWalk, temp);
++ptrWalk;
}
}
bool checkElement (Element ptrWalk, Element *set, int size)
{
Element *p = &set[0];
for (int j=0; j<size;j++)
{
if (strcmp (ptrWalk, *p) == 0)
{
return true;
}
p++;
}
return false;
}
This is my first problem to ask about, please scrutinize me if necessary :)
I'm trying to solve a problem for a C++ class at school. I have encountered an error I really can't grasp. I'm in taking my baby steps in programming.
The assignment says:
two classes,
inheritance mechanism used,
database holding students using dynamic memory allocation,
a way of enlarging the database without using advanced data structures,
overload stream operators for objects of created class.
This is my code:
#include <conio.h>
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
class Person
{
protected:
char Name[20];
string Surname;
int Age;
public:
virtual void whoAmI()=0;
friend ostream &operator<< (ostream &out_, Person &s); // stream overl.
friend istream &operator>> (istream &in_, Person &s);
friend void resizeArr(Person* oldList, int oldSize, int newSize); // array enlarge
};
class Student :public Person
{
public:
Student(){}
Student(char name[], string surname, int age )
{
strcpy(Name, name);
Surname = surname;
Age = age;
}
virtual void whoAmI() // basically replaced by overloaded ostream
{
//cout << "I am a student\nMy name is " << name <<" "<< surname << "; I'm "<< age << " years old.";
cout << Name << endl;
cout << Surname << endl;
cout << Age << endl;
}
};
istream &operator>> (istream &in_, Person &s) // through reference: stream object and overloading object
{
cout << "New student record: "<< endl;
cout << "Name: " << endl;
in_ >> s.Name;
cout << "Surname: " << endl;
in_ >> s.Surname;
cout << "Age: " << endl;
in_ >> s.Age;
cout << endl;
return in_;
}
ostream &operator<< (ostream &out_, Person &s)
{
out_ << "Name:\t\t" << s.Name << endl << "Surname:\t" << s.Surname << endl <<"Age:\t\t" << s.Age << endl;
return out_;
}
void resizeArr(Student* oldList, int oldSize, int newSize)
{
Student *newList = new Student[newSize];
for(int i = 0; i < oldSize; i++) // COPYING
{
newList[i]=oldList[i];
}
for(int i = oldSize ; i < newSize ; i++) // init rest as blank students to avoid errors
{
newList[i] = Student( "undef" , "undef", 0);
}
delete [] oldList; // free memory used for old array
oldList = newList; // reset pointer to new array
}
int main()
{
int initSize = 2;
int plusSize = 4;
Student *list1 = new Student[initSize];
for (int i=0; i<initSize; i++){ // initialize each cell as a blank student
list1[i] = Student( "undef" , "undef", 0);
}
for (int i=0; i<initSize; i++) // display initial array
{
cout << list1[i] << endl << "------------------------------" << endl; // for the sake of console output clarity
}
resizeArr(list1, initSize, plusSize); // FUNCTION CALL
cout << endl << "\tEnlarger database: " << endl << endl; // for the sake of console output clarity
for (int i=0; i<plusSize; i++) // display enlarged array
{
cout << list1[i] << endl << "------------------------------" << endl; // for the sake of console output clarity
}
getch();
return 0;
}
I have previously prototyped such a mechanism using integer arrays and it worked... now I'm getting a crash for an unknown reason.
Please point me in the right direction.
Edit:
The program compiles and runs, the new array seems to hold the first two elements of the old array, and by the point it reaches the first new element, the program crashes (the memory cell seems to be trolling me and holds a smiley face).
The first two Student objects are copied, the third element causes an error:
The issue lies in the definition of your resize function:
void resizeArr(Student* oldList, int oldSize, int newSize)
Unless otherwise noted, all parameters passed to a function are by value. Even though the first parameter is a pointer, that only allows to modify the memory to which it is pointing, not the pointer itself.
You need to change the declaration of the first parameter to either Student **, with code changed in the method to handle the double dereference, or change it to Student*&.
I suspect that you were lucky that it worked for integer.
You are passing a pointer to a student list to your resizeArr routine, i.e. void resizeArr(Student* oldList, int oldSize, int newSize), but not a pointer to a pointer.
Hence, assigning a new/different memory block to the pointer within resizeArr will let the variable within resizeArr point to the new address, but the pointer that has been passed to resizeArr (i.e list1) is not changed.
I'd suggest to change the logic to Student* resizeArr(Student* oldList, int oldSize, int newSize) and call it like list1 = resizeArr(list1, initSize, plusSize);
This is analogous to the signature of void* realloc (void* ptr, size_t size);.
I'm trying to read names and ages from user, until user inputs "stop". Then just print all these values. Please help me , I'm just the beginner in C++
// Pass.cpp
// Reading names and ages from user and outputting them
#include <iostream>
#include <iomanip>
#include <cstring>
using std::cout;
using std::cin;
using std::endl;
using std::setw;
using std::strcmp;
char** larger(char** arr);
int* larger(int* arr);
void read_data(char*** names, int** ages);
void print_data(char*** names, int** ages);
int main()
{
char** names = new char*[5];
char*** p_names = &names;
int* ages = new int[5];
int** p_ages = &ages;
read_data(p_names,p_ages);
print_data(p_names,p_ages);
}
void read_data(char*** names, int** ages)
{
const char* sent = "stop";
const int MAX = 15;
int count = 0;
char UI[MAX];
cout << "Enter names and ages."
<< endl << "Maximum length of name is " << MAX
<< endl << "When stop enter \"" << sent << "\".";
while (true)
{
cout << endl << "Name: ";
cin.getline(UI,MAX,'\n');
if (!strcmp(UI, sent))
break;
if (count + 1 > sizeof (&ages) / sizeof (&ages[0]))
{
*names = larger(*names);
*ages = larger(*ages);
}
*names[count] = UI;
cout << endl << "Age: ";
cin >> *ages[count++];
}
}
void print_data(char*** names, int** ages)
{
for (int i = 0; i < sizeof(*ages) / sizeof(*ages[0]);i++)
{
cout << endl << setw(10) << "Name: " << *names[i]
<< setw(10) << "Age: " << *ages[i];
}
}
char** larger(char** names)
{
const int size = sizeof(names) / sizeof(*names);
char** new_arr = new char*[2*size];
for (int i = 0; i < size; i++)
new_arr[i] = names[i];
return new_arr;
}
int* larger(int* ages)
{
const int size = sizeof(ages) / sizeof(*ages);
int* new_arr = new int[2 * size];
for (int i = 0; i < size; i++)
new_arr[i] = ages[i];
return new_arr;
}
You are really over complicating things.
Given the original problem:
Write a program that reads a number (an integer) and a name (less than
15 characters) from the keyboard. Design the program so that the data
is done in one function, and the output in another. Store the data in
the main() function. The program should end when zero is entered for
the number. Think about how you are going to pass the data between
functions
The problem wants you to think about passing parameters to functions. A simple solution would be:
#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
// Pass in a char array and an integer reference.
// These values will be modified in the function
void read_data(char name[], int& age)
{
cout << endl << "Age: ";
cin >> age;
cin.ignore();
cout << endl << "Name: ";
cin.getline(name, 16);
}
// Pass a const array and an int value
// These values will not be modified
void print_data(char const *name, int age)
{
cout << endl << setw(10) << "Name: " << name
<< setw(10) << "Age: " << age;
}
int main()
{
char name[16];
int age;
cout << "Enter names and ages."
<< endl << "Enter 0 age to quit.";
do {
read_data(name, age);
print_data(name, age);
} while (0 != age)
}
EDIT: Modified per user3290289's comment
EDIT2: Storing data in an array
// Simplify by storing data in a struct (so we don't have to manage 2 arrays)
struct Person {
char name[16];
int age;
};
// Returns how many People were input
int read_data(Person*& arr)
{
int block = 10; // How many persons to allocate at a time
arr = NULL;
int arr_size = 0;
int index = 0;
while (true) {
if (index == arr_size) {
arr_size += block;
arr = (Person *)realloc(arr, arr_size * sizeof(Person)); // Reallocation
// Should check for error here!
}
cout << endl << "Age: ";
cin >> arr[index].age;
cin.ignore();
if (0 == arr[index].age) {
return index;
}
cout << endl << "Name: ";
cin.getline(arr[index++].name, 16);
}
}
void print_data(Person *arr, int count)
{
for (int i = 0; i < count; i++) {
cout << endl << setw(10) << "Name: " << arr[i].name
<< setw(10) << "Age: " << arr[i].age;
}
}
int main()
{
Person *arr;
int count = read_data(arr);
print_data(arr, count);
free(arr); // Free the memory
}
try this:
#include <iostream>
#include <iomanip>
#include <vector>
#include <sstream>
using std::cout;
using std::cin;
using std::endl;
using std::setw;
using std::strcmp;
void read_data(std::vector<std::string> &names, std::vector<int> &ages);
void print_data(std::vector<std::string> &names, std::vector<int> &ages);
int main()
{
std::vector<std::string> names;
std::vector<int> ages;
read_data(names, ages);
print_data(names, ages);
}
void read_data(std::vector<std::string> &names, std::vector<int> &ages)
{
const char* sent = "stop";
cout << "Enter names and ages."
<< endl << "When stop enter \"" << sent << "\".";
while (true)
{
std::string input;
cout << endl << "Name: ";
std::getline(cin, input);
if (!strcmp(input.c_str(), sent))
break;
names.push_back(input);
cout << endl << "Age: ";
std::string age;
std::getline(cin, age);
ages.push_back(atoi(age.c_str()));
}
}
void print_data(std::vector<std::string> &names, std::vector<int> &ages)
{
for (int i = 0; i < names.capacity() ; i++)
{
cout << endl << setw(10) << "Name: " << names.at(i)
<< setw(10) << "Age: " << ages.at(i);
}
}
One problem I see is this if statement:
if (count + 1 > sizeof (&ages) / sizeof (&ages[0]))
&ages is the address of an int**, a pointer, and so it's size is 8 (usually) as that is the size of a pointer type. The function does not know the size of the array, sizeof will only return the correct answer when ages is declared in the same scope.
sizeof(&ages) / sizeof(&ages[0])
will always return 1
I believe one natural solution about this problem is as follows:
create a "std::map" instance. Here std::map would sort the elements according to the age. Here my assumption is after storing the data into the container, you would like to find about a particular student age/smallest/largest and all various manipulation with data.Just storing and printing the data does not make much sense in general.
create a "std::pair" and take the both input from the user into the std::pair "first" and "second" member respectively. Now you can insert this "std::pair" instance value into the above "std::map" object.
While printing, you can now fetch the each element of "std::map" in the form of "std::pair" and then you can display pair "first" and "second" part respectively.
I have this program, and I'm still getting used to C++ pointers, so It's probably an issue with that. But I am having the program crash when the getStructData() function is called. I've probably messed up something to do with the pointer to the struct that i've used, but I'm really not sure at this point. Any tips or help are appreciated. Thanks, and before people start the mad downvoting, this isn't a homework assignment from my school, I'm just going over other schools homework to practice during the christmas break.
Prog1Struct.h
#ifndef INCLUDED_PROG1STRUCT
#define INCLUDED_PROG1STRUCT
struct Prog1Struct
{
int m_iVal;
double m_dArray[5];
char m_sLine[80];
};
#endif
Prog1Class.h
#ifndef PROG1CLASS
#define PROG1CLASS
#include "Prog1Struct.h"
class Prog1Class
{
private:
Prog1Struct myStruct[5];
public:
/*Prog1Class();
~Prog1Class();*/
void setStructData();
void getStructData(int structureArrayIndex, struct Prog1Struct *info);
void printStruct(int indexPriv);
void printData();
};
#endif
Prog1Class.cpp
#ifndef INCLUDED_PROG1CLASS
#define INCLUDED_PROG1CLASS
#include <iostream>
#include <string>
#include "Prog1Class.h"
#include "Prog1Struct.h"
#include <time.h>
using namespace std;
void Prog1Class::setStructData()
{
for (int i = 0; i<5; i++)
{
cout << "Enter an integer: ";
cin >> myStruct[i].m_iVal;
for (int j = 0; j < 5; j++)
{
cout << endl << "Enter a double: ";
cin >> myStruct[i].m_dArray[j];
}
cout << endl << "Enter a string: ";
cin.ignore(256, '\n');
cin.getline(myStruct[i].m_sLine, 80, '\n');
cout << endl;
}
}
//takes in index for array, and pointer to a struct of the type in Prog1Struct.h. Copies all data from the private struct at the given index into the struct of the pointer argument.
void Prog1Class::getStructData(int structureArrayIndex, struct Prog1Struct *info)
{
*info = myStruct[structureArrayIndex];
cout << "Printing *info from getStructData function" << endl;
cout << info;
}
void Prog1Class::printStruct(int indexPriv)
{
cout << myStruct[indexPriv].m_iVal << " ";
for (int k = 0; k < 5; k++)
{
cout << myStruct[indexPriv].m_dArray[k] << " ";
}
cout << myStruct[indexPriv].m_sLine << " ";
}
int main(void)
{
Prog1Class c;
Prog1Struct *emptyStruct = '\0';
cout << "setStructData called:" << endl;
c.setStructData();
cout << "getStructData called:" << endl;
//error comes here, at getStructData.
c.getStructData(2, emptyStruct);
cout << "printStruct called:" << endl;
c.printStruct(2);
cin.get();
}
#endif
You are trying to assign a value to a null pointer.
Prog1Struct *emptyStruct = '\0';//set emptyStruct to 0 (This means it points at address 0, not holding a 0 value)
cout << "setStructData called:" << endl;
c.setStructData();
cout << "getStructData called:" << endl;
//error comes here, at getStructData.
c.getStructData(2, emptyStruct);//emptyStruct is still = 0
So in the function, info = 0.
void Prog1Class::getStructData(int structureArrayIndex, struct Prog1Struct *info)
{
*info = myStruct[structureArrayIndex];//This line is trying to write to a section of memory you don't have access to (address 0)
I think you want this instead. (untested) This will make info point to myStruct[structureArrayIndex] (Not copy the contents of myStruct[structureArrayIndex] to info). Pointers only point to things (like structs or some other type), they cannot contain a struct.
info = &myStruct[structureArrayIndex];