Wondering about scope in C++ with structures and functions - c++

I'm writing a program that allows me to put my name in and pull up different semesters and for me to put grades in and then be able to calculate my class average and GPA, just for my own reference in my courses.
What I am having a problem with is with structures and how they work with a multifunction program. In my courses we have not covered this and I have spent a while now searching for answers and cannot find one. Below is my current code:
using namespace std;
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char gettingName();
class Student{
public:
double semesterClass[20][20]; //first is for semester, second is for which class
char name[20];
int semester;
int numOfCourses;
};
int main(int argc, char **argv)
{
Student info;
gettingName();
cout << "Hi my name is: " << name.info << endl;
return 0;
}
char gettingName()
{
Student info;
char YesNo[5];
char boolean[1] = {'T'};
char yes[3] = {'Y','e','s'};
char yes2[3] = {'Y','E','S'};
char yes3[3] = {'y','e','s'};
char yes4[1] = {'Y'};
char yes5[1] = {'y'};
while(boolean[0] == 'T'){
cout << "What is your name? ";
cin >> info.name;
cout << endl;
cout << "Is your name " << info.name << "?"<<endl; //accepted input will be Y,y,YES,Yes,yes
cin >> YesNo;
//if input does not equal any of the accepted inputs, then loop until it does
if((strcmp(YesNo,yes) == 0) || (strcmp(YesNo,yes2) == 0) || (strcmp(YesNo,yes3) == 0) || (YesNo[0] == yes4[0]) || (YesNo[0] == yes5[0])){
boolean[0] = 'F';
}
}
return 0;
}
My question: how might I go about fixing the scope so that I can call the 'gettingName' function, get the person to input their name, (get it right (that already works)) and then be able to access and print it in the main function?

There are a lot of issues with your code, but I will try to help out the best I can. In general C++ scope for local variables is at the block level. So any time you see a ending bracket }, the scope has ended.
Some specific issues with your code that I noticed:
This line should be: "cout << "Hi my name is: " << info.name <<
endl;", not name.info
The boolean loop can be handled much more efficiently. You should try to list all of the acceptable options in one data structure like an array and then loop through the array.
Lastly when creating a function that doesn't need to return anything,
you can use the type void instead of char. So it could be void gettingName(), instead of char gettingName().
As an example to show you a quick and easy way to do what I think you wanted, I simplified your code a bit. I also decided to use std::string rather than char arrays as they are easier to work with:
class Student{
public:
std::string name;
};
std::string gettingName();
int main()
{
Student Info;
Info.name = gettingName();
cout << "Hi my name is: " << Info.name << endl;
return 0;
}
std::string gettingName()
{
std::string name;
cout << "What is your name? ";
cin >> name;
cout << endl;
return name;
}

Your code not really is object oriented. To fix the scope, you'll have to put gettingName inside your class to make it a member function (which is btw the term to Google for). You will also have to change the implementation which then needs to include the class name for identification:
char Student::gettingName()
{
...
}
From main you'd call it then via
info.gettingName();

Related

Class vector has no member

I'm collecting names and test scores to populate a vector. Both the function and main method can't recognize the struct's members. How can I get it to see the members? Or is there a better way to populate a vector of structs with user input using a function?
I've searched other similar posts, but it seems like it's just a simple code error I missed.
#include <iostream>
#include <vector>
using namespace std;
const int classSize = 1;
struct StudentType {
string studentFName;
string studentLName;
int testScore;
char grade;
};
vector<StudentType> collectStudentData(vector<StudentType> students[classSize]) {
for (int i = 0; i < classSize; i++) {
cout << "Student " << i << "'s name and test score" << endl;
cin >> students[i].studentFName >> students[i].studentLName >> students[i].testScore;
}
return students[classSize];
};
int main() {
vector<StudentType> students[classSize] = {};
students[classSize] = collectStudentData(students);
cout << students[1].studentFName << students[1].studentLName << students[1].studentFName;
};
'studentFName': is not a member of 'std::vector>'
This line creates an array of vectors:
vector<StudentType> students[classSize] = {};
What you want is this a single vector:
vector<StudentType> students;
Where that gets initialized to a zero-length array.
When it comes to adding data you don't need to return from the other method, you can pass in a reference and add to it:
void collectStudentData(vector<StudentType>& students) {
for (int i = 0; i < classSize; i++) {
// Read in one at a time
StudentType student;
cout << "Student " << i << "'s name and test score" << endl;
cin >> student.studentFName >> student.studentLName >> student.testScore;
// Add to the array
students.push_back(student);
}
}
Ideally classSize is either passed in as an argument, or you just type a blank line to end input. Using a global variable is really messy and should be strongly discouraged.
vector<StudentType> students[classSize]
Is one issue. You are not declaring a function that takes a vector, you are declaring a function that takes an array of vectors.
Secondly, if you only applied that change you would be passing an empty vector, you can initialize vector to be a particular size by passing in the size to the constructor.
Furthermore, it seems that you would benefit from passing the students vector by reference
vector<StudentType>& students
instead, the & creates a reference. Right now your code is copying the vector when it is passed into the function
#include <iostream>
#include <vector>
using namespace std;
const int classSize = 1;
struct StudentType {
string studentFName;
string studentLName;
int testScore;
char grade;
};
void collectStudentData(vector<StudentType>& students) {
for (int i = 0; i < classSize; i++) {
cout << "Student " << i << "'s name and test score" << endl;
cin >> students[i].studentFName >> students[i].studentLName >> students[i].testScore;
}
return students;
};
int main() {
vector<StudentType> students{classSize};
collectStudentData(students);
cout << students[0].studentFName << students[0].studentLName << students[0].studentFName;
};
If you wanted to improve the code further, you would use an iterator in the for loop instead, and preferably you wouldn't need to construct the vector in main, and pass it into a function to mutate it. You could just construct it and return it from the function.

C++ pass empty vector of structs to a function

I am trying to pass an empty vector of structures to a function which will read from a file and it will return the number of records read -- it will be an integer.
I initialize the vector of structures in main and when I attempt to pass it to the function as I would regularly do it:
int read_records(vector<player> player_info)
It gives me a "player is undefined" error. I have found a way to go around it as you will see in my code below but logic leads me to believe that there should be a way to pass the empty vector without having to fill in the first subscript.
The code is below. Please note that the read function is not yet complete as I am still wondering about the vector of structs.
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <fstream>
using namespace std;
//function prototypes
int read_records(struct player* player_info);
/*
* Define a struct called player that will consist
* of the variables that are needed to read in each
* record for the players. 2 strings for the first
* and last names and 1 integer to hold the statistics
*/
struct player
{
string first;
string last;
int stats;
};
int main(void)
{
int sort_by, records_read;
vector<player> player_info(1);
player * point = &player_info[0];
cout << "Welcome to Baseball player statistics program!" << endl;
cout << "How should the information be sorted?" << endl;
cout << "Enter 1 for First Name" << endl;
cout << "Enter 2 for Last Name" << endl;
cout << "Enter 3 for Points" << endl;
cout << "Enter your selection: ";
cin >> sort_by;
//read the records into the array
records_read = read_records(point);
system("Pause");
return 0;
}
int read_records(struct player* player_info)
{
//declare the inputstream
ifstream inputfile;
//open the file
inputfile.open("points.txt");
//handle problem if the file fails to open for reading
if (inputfile.fail())
{
cout << "The player file has failed to open!" << endl;
exit(EXIT_FAILURE);
}
else
{
cout << "The player file has been read successfully!" << endl;
}
return 5;
}
Define the type player before you attempt to declare functions that need to know about that type.
struct player
{
string first;
string last;
int stats;
};
int read_records(vector<player> player_info);
Your workaround was successful because naming player in struct player* acts as a [forward] declaration, in a way that naming it in vector<player> does not. (The whys and wherefores of this are too broad for this answer and are covered elsewhere on SO and in your C++ book.)
As an aside, I doubt you want to take that vector by value.
Why don't you put struct player definition before int read_records(vector<player> player_info).

How do i take the initials of all the parts of one's name except the last name?

Hi i am trying to write a c++ program where the user will enter a name lets say for example: Tahmid Alam Khan Rifat and the computer will print the formatted version of the name which in this case will be: Mr. T. A. K. Rifat. I have included the code below. You will be able to see that I got close but still not exactly what i wanted. Please help.
#include<iostream>
#include<string>
using namespace std;
class myclass{
private:
string name,temp;
string p;
int i,j,sp;
public:
void work(){
cout << "Enter the name of the male student: ";
getline(cin,name);
cout << endl;
cout << "The original name is: ";
cout << name;
cout << endl << endl;
cout << "The formatted name is: " << "Mr." << name[0] << ".";
for(i=0;i<name.size();i++){
if(name[i]==' '){
sp=i;
for(j=sp+1;j<=sp+1;j++){
temp=name[j];
cout << temp << ".";
}
}
}
for(i=sp+2;i<name.size();i++){
cout << name[i];
}
cout << endl;
}
};
int main(){
myclass c;
c.work();
}
I guess the easiest way to solve this is to tokenize your string, print the first character from it, except from the last, where you print its full size.
To tokenize, you can do something like that:
std::vector<std::string> tokenize(std::istringstream &str)
{
std::vector<std::string> tokens;
while ( !str.eof() ) {
std::string tmp;
str >> tmp;
tokens.push_back(tmp);
}
return tokens;
}
Now you can easily transverse the tokens:
int main()
{
std::string name;
cout << "Enter the name of the male student: ";
getline(cin,name);
cout << endl;
cout << "The original name is: ";
cout << name;
cout << endl << endl;
std::istringstream str(name);
std::vector<std::string> tokens = tokenize(str);
for ( int i = 0 ; i < tokens.size() - 1; ++i)
std::cout << tokens[i][0] << ". ";
cout << tokens[tokens.size() - 1] << endl;
}
I hope this helps :)
It is probably a simpler version (originally I wrote this in C, you could easily convert it to C++ though, since the logic remains the same).
I have accepted the name and then inserted a space at the beginning of the string and one more space at the end, before the NULL character ('\0')
The program checks for a space.
When it encounters one, it checks for the next space that occurs in the string.
Now occurrence of this space helps us to identify an important determining factor as to what the next action should be.
See, if there is an null character after this subsequent space, then we can conclude that the subsequent space was the one we inserted at the end of the string.
That is, the space which occurs after the primary space, which came before the surname. Bingo!
You get the precise index of the array, from where the surname starts! :D
Looks long, but really is simple. Good luck!
#include<stdio.h>
#include<string.h>
void main()
{
char str[100]; /*you could also allocate dynamically as per your convenience*/
int i,j,k;
printf("Enter the full name: ");
gets(str);
int l=strlen(str);
for(i=l;i>=0;i--)
{
str[i+1]=str[i]; //shifting elements to make room for the space
}
str[0]=' '; //inserting space in the beginning
str[l+1]=' '; str[l+2]='\0'; //inserting space at the end
printf("The abbreviated form is:\n");
for(i=0;i<l+1;i++) //main loop for checking
{
if(str[i]==' ') //first space checker
{
for(j=i+1; str[j]!=' ';j++) //running loop till subsequent space
{
}
if(str[j+1]!='\0') //not the space after surname
{
printf("%c.",str[i+1]); //prints just the initial
}
else
for(k=i+1;str[k]!='\0';k++) //space after surname
{
printf("%c", str[k]); //prints the entire surname
}
}
}
}
Change your loop to the following:-
for(i=0;i<name.size();i++)
{
if(name[i]==' ')
{
initial = i + 1; //initial is of type int.
temp = name[initial]; //temp is char.
cout << temp << ".";
}
}
Try ravi's answer to make your code work, but I wanted to point out that there are more intuitive ways to program this which would make maintenance and collaboration easier in the future (always a good practice).
You can use an explode() implementation (or C's strtok()) to split the name string into pieces. Then just use the first character of each piece, disregarding the last name.
I think your question has already been answered. But in the future you could consider splitting up your program into more simple tasks, which makes things easier to read. Coupled with descriptive variable and function names, it can make a program easier to comprehend, and therefore to modify or fix later on.
Disclaimer - I am a beginner amateur programmer and this is just for ideas:
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
// I got this function from StackOverflow somewhere, splits a string into
// vector of desired type:
template<typename T>
std::vector<T> LineSplit(const std::string& line) {
std::istringstream is(line);
return std::vector<T>(std::istream_iterator<T>(is), std::istream_iterator<T>());
}
class Names {
private:
std::vector<std::string> full_name_;
void TakeInput() {
std::cout << "Enter the name of the male student: " << std::endl;
std::string input;
getline(std::cin,input);
full_name_ = LineSplit<std::string>(input);
}
void DisplayInitialsOfFirstNames() const {
std::cout << "Mr. ";
for (std::size_t i = 0; i < full_name_.size()-1; ++i) {
std::cout << full_name_[i][0] << ". ";
}
};
void DisplayLastName() const {
std::cout << full_name_.back() << std::endl;
}
public:
void work() {
TakeInput();
DisplayInitialsOfFirstNames();
DisplayLastName();
};
};
int main(){
Names n;
n.work();
}

I have an invalid initialization of reference of type int& from expression of type in passing argument 1

Im trying to lean structures and I think I am doing something wrong when I use the structure and trying to call it into a function.
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
//Structure
struct Inventory
{
int NumberPartsBin;
};
//Function Prototypes.
void choiceMenu();
void AddParts(int &);
void RemoveParts(int &);
int main()
{
char Election;
int choice;
Inventory Parts = {10};
const int Valve_Choice = 1,
Quit_Choice = 2;
I am trying to to resolve this problem with one item, but I will use arrays for 10 items.
do {
choiceMenu();
cin>> choice;
if (choice >= Valve_Choice & choice <= Quit_Choice)
{
switch(choice){
case Valve_Choice:
cout<<"Enter A for Add Parts or R to Romove Parts";
cin >> Election;
if (Election=='A')
{
AddParts(Parts);// My problem is here
}
if else (Election =='R'){
RemoveParts(Parts);}
else{
cout << "Invalid Entry. Try Again";
cin >> Election; }
break;
case Quit_Choice:
cout<<"Program Ending";
return;
else
{
cout<<"Enter a valid choice!!;
cin >> choice;
}
}
}
while (choice >= Valve_Choice & choice < Quit_Choice);
system("pause");
return 0;
// Bin Choice
void choiceMenu()
{
// We use ofstream to create and write on a text file.
ofstream outputFile;
outputFile.open("C:\\Users\\Alexander MR\\Desktop\\CompanyABCPayRoll.txt");
// The headed of the document.
outputFile << " Inventoy\n";
outputFile << " = = = = = = = = \n";
outputFile << " *Choose the part of your preference.\n";
outputFile << " 1. valves = " << Parts.NumberPartsBin << endl;
outputFile << " 11. Choose 2 to quit the Program" << endl;
outputFile.close();
}
I am not sure of my function either.
my function to add parts
void AddParts(int &Parts1)
{
int Enter1;
Parts1.NumberPartsBin = Parts1.NumberPartsBin + Enter1;
}
My function to remove parts
void RemoveParts(int &Parts2)
{
int Enter2;
Parts2.NumberPartsBin = Parts2.NumberPartsBin - Enter2;
}
Reading the question with only parts of the code formatted is quite hard. The first thing I saw was:
void RemoveParts( int &Parts2 ) {
int Enter2;
Parts2.NumberPartsBin = Parts2.NumberPartsBin - Enter2;
}
This makes no sense at all. If Parts2 is an int, then you will never be able to say Parts2.NumberPartsBin. The second thing is int Enter2;. You never give it a value, but in the next line you want to subtract it from something‽
I'm guessing (at least with this function) that you are trying to do something like this:
void RemoveParts( Inventory& inventoryItem, int amountOfParts ) { // inventoryItem is passed by reference, amountOfParts is passed by value
inventoryItem.NumberPartsBin = inventoryItem.NumberPartsBin - amountOfParts;
}
Looking at your code, I'm guessing you're quite new to all of this. I'm no guru, but please:
Capitalize class/struct names and start variable names with a lowercase. ( like parts or election)
If you want to change the value that comes into a function, pass it by reference, but if it is something like an int or a char, simply pass it by value.
p.s. it's if, else if, else and not if else which will otherwise be the next error in your code.

Does my source code shows my own understanding of structures in c++? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I'd like to know if I am in fact in the right direction, I am currently learning the C++ language and reading this book called Jumping into C++ by Alex Allain and there's a practice problem at the end of the chapter regarding structures, to create a contact book program the user should be able to not just fill out a single structure, but should be able to add new entries, each with a separate name and phone number. Let the user add as many entries as he or she wants—is this easy to do? Add the ability to display all, or some of the entries, letting the user browse the list of entries.
so far below is what I've done, I'd like to know if my source code is in fact right and does it show my understanding about structures and overall c++?
#include "stdafx.h"
#include "iostream"
#include "string"
using namespace std;
struct user{
string name;
int phone_num;
};
int _tmain(int argc, _TCHAR* argv[])
{
int input, number; // will hold the users input at the beginning of the program
int counter = 0; // keep track of the array position
int const arraySize = 10; // size of the array
user new_username[arraySize]; // will hold the users details
string name; // will hold the users input for the name
cout << "CONTACTS\n";
do{
cout << "+ADD [1] -EXIT[0]";
cin >> input;
if(input == 1){
//cout << counter;
cout << "\nName: ";
cin >> name;
new_username[counter].name += name;
cout << endl << "\nPhone: ";
cin >> number;
new_username[counter].phone_num = number;
counter++;
//set_user(counter);
}
cout << "Name Number\n";
cout << "--------------\n";
for(int j=0; j < arraySize; j++){
cout << new_username[j].name;
cout << " -- ";
cout << new_username[j].phone_num;
cout << "\n";
}
cout << "\n";
}while(input != 0);
cout << "\n";
system("PAUSE");
return 0;
}
Stackoverflow isn't meant to be used for code reviews, but there's a different site for this (although still in beta): https://codereview.stackexchange.com/
Just some quick things I noticed:
Your program ignores invalid input (enter 2, 3 or any other number instead of 1 or 0).
You don't check whether your user array is full.
This is not really object oriented.
As for basic understanding... I guess yes, but that's not actually hard to start with.
To fulfill "allow the user to add as many entries as they want" you'll have to use a dynamic array (ask the user how many entries he'd like to add) or use some dynamic storage (e.g. a linked list).
If you want the user to be able to add as many contacts as he/she wants, you can use powerful standard template mechanisms.
For this application, I would recommend looking at either
std::vector
or
std::map
This is how you would use them: (keep in mind this is pseudo code and won't compile)
#include <vector>
typedef struct {
std::string name;
double phoneNumber;
} YourStruct;
int main( int argc, char **argv ) {
std::vector<YourStruct> structVector;
do {
int input;
std::cin >> input;
if (input) {
//(read user input for name and number)
YourStruct yourStruct;
yourStruct.name = (user input)
yourStruct.phoneNumber = (user input)
// insert into the vector
structVector.push_back(yourStruct)
}
} while (input != 0)
// now to print what you have:
for (int i = 0; i < structVector.size(); i++) {
std::cout << structVector[i].name << ", " << structVector[i].number << std::endl;
}
}
The benefit to using vectors is that it automatically resizes and keeps track of how large it is without you having to use a counter item.
Now, for something a bit trickier. We're going to use a map to use the "key" value to get the name. The following code won't compile but it is functionally how you would perform the task:
#include <map>
int main(int argc, char** argv) {
std::map<std::string,double> myMap;
// the string is the "key" value, which can be the name of the person
// while the "independent" is the phone number
do {
// determine if the user wants to put another entry in the map
if (insert) {
std::string name = (user input name)
double number = (user input number)
myMap[name] = number;
}
} while (input != 0)
// now we can iterate through the map
std::map<std::string,double>::iterator it;
for (it = myMap.begin(); it != myMap.end(); ++it) {
std::cout << it.first << ", " << it.second << std::endl;
}
// also, you can look up by name
it = myMap.find("Tony Stark");
if (it != myMap.end()) { // if this condition is met, it means you found one
std::cout << it.first << ", " << it.second << std::endl;
}
}
Overall, your code looks good. However, it is not C++. You're programming like a C programmer. The beauty of C++ (besides polymophisim, of course) is the powerful template libraries.
I've just given you a small taste of what you can do with templates. Please comment if you have any questions of concerns. We've all been where you are, kudos for teaching yourself out of a book.
From your question and the code it seems like you are a new programmer, therefore I'll explain you the answer and I'll give you some notes on your code.
In order to solve the problem of "as many items" there are few approaches. The most easy one, and probably a pretty good solution is to use map, in any language it have different names. But usually the name is dictionary, associative arrays...
Using the map will help you with dealing with:
As many items
Sorted order by name
It will be easier for you to filter, it depends what you would like to do, and how sophisticated is your filter.
The other approaches I talked about i though of, are much more basic, and consist much more code, but they give you the feeling of how you can implement the map object by yourself, but this is a different question.
In the link I mention above, the example is for phone entry. But if you still want to use struct, you can have the key as the name and the value to be the struct itself. One justification for that can be that later on you plan to add address and company name.
Some notes regarding your code.
#include "stdafx.h"
#include "iostream"
#include "string"
using namespace std;
//use meanigful name, instead of user it can be phoneEntry
struct user{
string name;
//Starting using the following conventions using the capital letter in variable names for example phoneNumber
//int won't be god for phone number since some times you will need star or hash, or a leading zero, maybe a plus sign. It is better touse string for tat as well. And of course every time that you get a user input you should validate it
int phone_num;
};
//Why the name of the function is not main, why its _tmain
int _tmain(int argc, _TCHAR* argv[])
{
//Keep going with your comments, with time you would imbrase your own style based on things that you will see. But in general commenting is very important
//Give meanigful name, instead input userCommand for example
int input, number; // will hold the users input at the beginning of the program
int counter = 0; // keep track of the array position
int const arraySize = 10; // size of the array
//Again meangful names
user new_username[arraySize]; // will hold the users details
string name; // will hold the users input for the name
cout << "CONTACTS\n";
do{
cout << "+ADD [1] -EXIT[0]";
cin >> input;
if(input == 1){
//cout << counter;
cout << "\nName: ";
cin >> name;
new_username[counter].name += name;
cout << endl << "\nPhone: ";
cin >> number;
new_username[counter].phone_num = number;
counter++;
//set_user(counter);
}
cout << "Name Number\n";
cout << "--------------\n";
for(int j=0; j < arraySize; j++){
cout << new_username[j].name;
cout << " -- ";
cout << new_username[j].phone_num;
cout << "\n";
}
cout << "\n";
}while(input != 0);
cout << "\n";
system("PAUSE");
return 0;
}
I hope it helped