5

I'm learning struct in C++ and I don't know how to make it not to jump over the first question.

If I'm using char in the struct it will only copy me the first word, if I'm trying to use string it jumps over the first question (ignoring it).

Could you please guide me?

Later edit: I use Microsoft Visual C++ 2010 express edition, and is there a difference between std::getline and cin.getline?

#include <iostream>
#include <conio.h>
#include <string>


using namespace std;


struct melodie{

char artist[50];
char titlu[50];
int an;
int lungime;

};

void main(){
int repetam;
double rezultat;
cout<<"Cate melodii veti introduce: ";
cin>>repetam;
melodie *pointer = new melodie[repetam];
for(int i = 0; i<repetam; i++){
    cout<<endl;
    cout<<"Introduceti artistul melodiei: ";    
    cin.get(pointer[i].artist);
    cout<<"Introduceti titlul melodiei: ";
    cin.getline(pointer[i].titlu);
    cout<<"Introduceti anul melodiei: ";
    cin>>pointer[i].an;
    cout<<"Introuceti lungea melodiei (in secunde): ";
    cin>>pointer[i].lungime;


}
cout<<"Lista melodiilor introduse este:"<<endl;
for(int i =0; i<repetam; i++){
    cout<<"Artistul melodiei este: "<<pointer[i].artist<<endl
        <<"Titlul melodiei este: "<<pointer[i].titlu<<endl
        <<"Anul melodiei este: "<<pointer[i].an<<endl
        <<"Lungimea melodiei (in secunde) este: "<<pointer[i].lungime<<endl;
    cout<<endl;
}

cout<<"Melodiile care au aparut dupa anul 2000 si au lungimea mai mica de 180 de secunde sunt: "<<endl;
for(int i = 0;i<repetam; i++){
    if(pointer[i].an>2000 && pointer[i].lungime<180){
        cout<<"Artist: "<<pointer[i].artist
            <<endl
            <<"Titlul: "<<pointer[i].titlu<<endl<<endl;

        
    }
}



getch();
}
Mircea Mihai
  • 127
  • 1
  • 11
  • 1
    I highly suggest you use `std::string` and just `cin >> str` when you don't want spaces in it, or `getline(cin, str)` when you want a whole line, keeping in mind to discard the leftover newlines when mixing the two. – chris Dec 24 '12 at 08:45
  • cin.ignore() will remove any "leftovers" from the input. Also, you should check the result from your cin >> repetam;, or your new could fail [e.g. repetam hasn't been set to anything meaningful]. Also check that *pointer isn't NULL. – Mats Petersson Dec 24 '12 at 08:55
  • The problem other than `void main()` is addressed in [c++ - Why does std::getline() skip input after a formatted extraction? - Stack Overflow](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction) . – user202729 Jan 31 '21 at 03:02

1 Answers1

2

First off, your could shouldn't compile. There are a number of errors:

  • void main() is non-standard. main() always returns an int and the only portable declarations of main() are int main() and int main(int argc, char* argv[]) (or int main(int argc, char** argv) which is identical to the previous one; of course, the names of the two arguments can be freely chosen).
  • The get() and getline() member function you use take at least one additional argument: The size of the available buffer.

For the rest of the answer I'm assuming these errors are fixed.

Of course, the input isn't "jumping over the first question". Instead, it reads input which was already given but which you probably didn't consider as such: The formatted input using >> stops reading immediately when its respective format is completed (or it failed). For example, when reading an integer it stops once a non-digit is encountered. Thus, when reading the int for repetam the input stream stops reading after the last digit when encountering the newline used to finish this input. The call to get() reads a string up to (and including) the first newline. When entering repetam a newline was entered and, thus, this string is the newline where get() stops.

The more general, when mixing formatted input (i.e., using >>) and unformatted input (i.e., using the named functions get(), getline(), read(), etc.) you typically need to remove unwanted characters. In your example you probably want to get rid of the first newline before calling get() (you need to include <limits> to get access to std::numeric_limits):

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.get(pointer[i].artist, 50);

If your artisti string doesn't start with any space character, you can use

(std::cin >> std::ws).get(pointer[i].artist, 50);

The manipulator std::ws skips all leading whitespace (it would skip spaces, tabs, newlines, etc.) and is somewhat easier to type. Of course, if you need frequently ignore newlines, you can create a manipulator to ignore the characters up to and including the newline as well:

std::istream& skipline(std::istream& in)
{
    return in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
// ...
(std::cin >> skipline).get(pointer[i].artist, 50);

That said, I guess, you didn't really mean to use get() because this function includes the separation character ('\n' by default) into the string. You probably want to use getline() instead. Also, it is easier to deal with std::strings instead of character arrays, i.e., I would use a different definition for the struct:

struct melodi
{
    std::string artist;
    std::string titlu;
    int an;
    int lungime;
};

This way, the strings can be arbitrary size and aren't limited to 49 characters (there needs to be space for a terminating null character in you version). To read a std::string you'd need a non-member function std::getline(), however):

std::getline(std::cin >> skipline, artist);
Dietmar Kühl
  • 141,209
  • 12
  • 196
  • 356
  • Hmmmm oau a lot of thing's i have to study to understand, but because i like it so much i will learn it with pleasure. 1 Question i have, can i use the -> using namespace std ? for the std:: ? And thank you so much, now im trying to fix all the problems and i will come with a feedback Thank you – Mircea Mihai Dec 25 '12 at 08:34
  • Later edit: Thank you very much for the help i learn now the mistakes the program is working now, but i had to make some change's for example when i used std::cin.ignore(std::numeric_limits::max(), '\n'); std::cin.get(pointer[i].artist, 50); the std::cin.get(pointer[i].artist, 50); gave me an error on the dot after cin, this is the error -> c++ test project\test\test\main.cpp(29): error C2664: 'std::basic_istream<_elem> &std::basic_istream<_elem>::get(_Elem *,std::streamsize)' : cannot convert parameter 1 from 'std::string' to 'char *', but i fixed with the – Mircea Mihai Dec 25 '12 at 08:52
  • continue to my last comment, i fixed with this-> std::getline(cin,pointer[i].artist); – Mircea Mihai Dec 25 '12 at 08:53
  • Personally, I prefer to qualify names with their respective namespace (or, if this is lengthy, an alias) but in the source file a using directive is acceptable. With respect to `get()` for `std::string`: There is no such things, i.e., using `std::getline()` is the correct fix. The code in the answer assumed that the type wasn't changed but it is probably better to change the type of the members. – Dietmar Kühl Dec 25 '12 at 10:28
  • Ah ok, thank you so much, you gave me some ideas for my future learning how to optimize and make it better even a simple program. Thank you – Mircea Mihai Dec 26 '12 at 00:13