Thread: User input to char array including white space

  1. #1
    Registered User
    Join Date
    Mar 2012
    Posts
    45

    User input to char array including white space

    Hi everyone,
    I have a program that is like a media library and has the user input titles, authors, etc. for books or recordings. What I have works so far, but when you input something with a space it breaks it up and only saves the first word. I looked it up and tried multiple things like cin.get(), but I couldn't make it work because the length is user-defined. I also tried getline() which gives me a red squiggly line saying "Error: no instance of overloaded function "getline" matches the argument list". I know using strings would fix this problem, but I was instructed to use char arrays. Here is my code:

    Code:
    #include <iostream>
    #include <string>
    #include "holding.h"
    #include "book.h"
    #include "recording.h"
    
    using namespace std;
    
    Holding* holdFunction(){
        char* title;
        title = new char;
        char* performer;
        performer = new char;
        char* author;
        author = new char;
        char format;
        char type;
        int callNumber;
    
        cout << "Enter B for book, R for recording: ";
        cin >> type;
    
        switch(type){
        case 'B' : 
        {
            cout << "Enter book title: ";
            cin >> author;
            cout << endl << "Enter book author: ";
            cin >> author;
            cout << endl << "Enter call number: ";
            cin >> callNumber;
            Book* book = new Book(title,callNumber,author);
            return book;
            break;    
        }
        case 'R' : 
        {
            cout << "Enter recording title: ";
            cin >> title;
            cout << endl << "Enter performer: ";
            cin >> performer;
            cout << endl << "Enter format: (M)P3, (W)AV, (A)IFF: ";
            cin >> format;
            cout << endl << "Enter call number: ";
            cin >> callNumber;
            Recording* record = new Recording(title,callNumber,performer,format);
            return record;
            break;
        }
        default:
            cout << "You entered an invalid type!" << endl;
            return NULL;
        }
    }
    
    int main(){
        Holding* arr[5];
    
        cout << "Enter holdings to be stored in a list:" << endl << endl;
    
        for(int i = 0; i < 5; i++){
            arr[i] = holdFunction();
        }
    
        cout << "Here are the holdings:" << endl << endl;
    
        for(int i = 0; i < 5; i++){
            arr[i]->print(cout);
        }
        cin.get();
        return 0;
    }
    I bolded the areas that I'm talking about. Let me know if you need to see the classes/headers, although I don't think those are the problem.

    Thanks for any help!!
    -Ryan

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    You probably used the wrong getline() function. There are two of these functions, one that works with std::string and the other that works with C-strings.

    Jim

  3. #3
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Code:
        char* title;
        title = new char;
        char* performer;
        performer = new char;
        char* author;
        author = new char;
    Nothing will help if you continue to assign *a single char* to fields that should have a massive length.

    Also, <string> is for the string class. Right now you are using C-strings, which require the <cstring> library.

  4. #4
    Registered User
    Join Date
    Mar 2012
    Posts
    45
    I tried both of these functions, and realized that I need to use the C-strings one but my problem is that the length of the array isn't defined until runtime so I can't just write "cin.getline(author, 30)". I tried "cin.getline(author, strlen(author))" but that didn't work either.

  5. #5
    Registered User
    Join Date
    Mar 2012
    Posts
    45
    Quote Originally Posted by whiteflags View Post
    Code:
        char* title;
        title = new char;
        char* performer;
        performer = new char;
        char* author;
        author = new char;
    Nothing will help if you continue to assign *a single char* to fields that should have a massive length.

    Also, <string> is for the string class. Right now you are using C-strings, which require the <cstring> library.
    How can I initialize the char arrays when I don't know how long they will be?

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by ryanmcclure4
    I tried both of these functions, and realized that I need to use the C-strings one but my problem is that the length of the array isn't defined until runtime so I can't just write "cin.getline(author, 30)". I tried "cin.getline(author, strlen(author))" but that didn't work either.
    Then use std::string and the non-member function std::getline. You can obtain a null terminated C-style string from a std::string object where necessary, but I don't see why it is necessary here.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Quote Originally Posted by ryanmcclure4 View Post
    How can I initialize the char arrays when I don't know how long they will be?
    You have to make a guess, then start filling the string in parts. If you require more space, you are supposed to ask for more, and then copy over what you already have, plus the new part.

  8. #8
    Registered User
    Join Date
    Mar 2012
    Posts
    45
    Quote Originally Posted by laserlight View Post
    Then use std::string and the non-member function std::getline. You can obtain a null terminated C-style string from a std::string object where necessary, but I don't see why it is necessary here.
    When i use std::getline I still get the error. I've never used the std:: in the body of a program before, always written the global "using namespace std;". Do I need to get rid of that if I want to use std::?

    Thanks whiteflags, I'll do that.

  9. #9
    Registered User
    Join Date
    Mar 2012
    Posts
    45
    Like I said above, I can't use c++ strings; only c-style strings.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by ryanmcclure4
    When i use std::getline I still get the error. I've never used the std:: in the body of a program before, always written the global "using namespace std;". Do I need to get rid of that if I want to use std::?
    No, the using directive is okay. You are probably just calling the function wrongly. For example:
    Code:
    #include <iostream>
    #include <string>
    
    int main()
    {
        using namespace std;
    
        string line;
        if (getline(cin, line))
        {
            cout << "You entered: " << line << endl;
        }
    }
    EDIT:
    Quote Originally Posted by ryanmcclure4
    Like I said above, I can't use c++ strings; only c-style strings.
    Why not?

    EDIT #2:
    Oh, it looks like this is some silly requirement from a misguided instructor. Ask your instructor what is the maximum length of a string that will be used. If that is up to you, come up with some reasonable maximum and enforce it with the member version of getline. If you really have to read in strings of variable length, then write a function to do it similiar to what whiteflags described, but you need to be very careful to get it right. Actually, it might be good if you just wrote your own string class and used it. If you're going to do manual memory management like this, you're almost certainly going to get it wrong.
    Last edited by laserlight; 11-28-2012 at 12:04 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Quote Originally Posted by ryanmcclure4 View Post
    When i use std::getline I still get the error. I've never used the std:: in the body of a program before, always written the global "using namespace std;". Do I need to get rid of that if I want to use std::?

    Thanks whiteflags, I'll do that.
    For the record, laserlight is also right. I could repeat what he said, but I won't. Another reason you could get the error you are talking about is because you accidentally called the getline function with the parameters in the wrong order. Seek help from a reference until you can finally remember the order of getline's parameters. I occasionally forget, myself.

  12. #12
    Registered User
    Join Date
    Mar 2012
    Posts
    45
    Quote Originally Posted by laserlight View Post
    EDIT #2:
    Oh, it looks like this is some silly requirement from a misguided instructor. Ask your instructor what is the maximum length of a string that will be used. If that is up to you, come up with some reasonable maximum and enforce it with the member version of getline. If you really have to read in strings of variable length, then write a function to do it similiar to what whiteflags described, but you need to be very careful to get it right. Actually, it might be good if you just wrote your own string class and used it. If you're going to do manual memory management like this, you're almost certainly going to get it wrong.
    I would write my own class as you said, but his instructions were "Note: Please do not use the C++ String class to create any String objects in your constructors." I can't think of a reason why he wouldn't want us to use them, unless maybe he just wanted us to practice using C-strings?

    I set an initial value of 100 for each char array and that seems to be working...if something goes wrong with that down the line I'll write the function whiteflags described.

    Thanks for all the advice!

  13. #13
    Registered User
    Join Date
    Mar 2012
    Posts
    45
    Alright, I've run into another little problem. When I run the program it prints "Enter B for book, R for recording", and for example if I type 'B' and press enter it prints "Enter book title", new line, and "Enter book author" without letting you input anything for the title. So it seems that it is taking the newline character after 'B' as the book title? I tried cin.ignore('\n'); in multiple places but it didn't fix anything.

    Code:
    cout << "Enter B for book, R for recording: ";
        cin >> type;
        switch(type){
        case 'B' : 
        {
            cout << "Enter book title: ";
            csis << "Enter book title: ";
            cin.getline(title, 99);
            csis << title;
            cout << endl << "Enter book author: ";
            csis << endl << "Enter book author: ";
            cin.getline(author, 99);
            csis << author;
            cout << endl << "Enter call number: ";
            csis << endl << "Enter call number: ";
            cin >> callNumber;
            csis << callNumber;
            Book* book = new Book(title,callNumber,author);
            return book;
            break;    
        }
        case 'R' : 
        {
            cout << "Enter recording title: ";
            csis << "Enter recording title: ";
            cin.getline(title, 99);
            csis << title;
            cout << endl << "Enter performer: ";
            csis << endl << "Enter performer: ";
            cin.getline(performer, 99);
            csis << performer;
            cout << endl << "Enter format: (M)P3, (W)AV, (A)IFF: ";
            csis << endl << "Enter format: (M)P3, (W)AV, (A)IFF: ";
            cin >> format;
            csis << format;
            cout << endl << "Enter call number: ";
            csis << endl << "Enter call number: ";
            cin >> callNumber;
            csis << callNumber;
            Recording* record = new Recording(title,callNumber,performer,format);
            return record;
            break;
        }
        default:
            cout << "You entered an invalid type!" << endl;
            return NULL;
        }
    Am I still doing something wrong here?

    EDIT: putting cin.ignore('\n') after
    Code:
            csis << "Enter book title: ";
            cin.ignore('\n');
    works and fixes the problem for the book, but when I use it for the record like this:

    Code:
            csis << "Enter recording title: ";
            cin.ignore('\n');
    it lets me type in a title, then I press enter and it goes to a new blank line and I have to type something else and press enter again for the next line to print.

    EDIT 2: I figure out for both of these, if I type in a one-word title the problem persists, however if I type in two or more words it works fine.
    Last edited by ryanmcclure4; 11-28-2012 at 12:49 PM.

  14. #14
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    I would write my own class as you said, but his instructions were "Note: Please do not use the C++ String class to create any String objects in your constructors."
    This forbids use of std::string, but technically not another class that you wrote.

    In any case, I can't tell you what is wrong. You didn't show me anything too interesting, but...
    I tried cin.ignore('\n'); in multiple places but it didn't fix anything.
    That's because you are calling it incorrectly. You really need to be married to a reference until you start remembering things. Please take note of the *giant* list to the left.

  15. #15
    Registered User
    Join Date
    Mar 2012
    Posts
    45
    Thanks, sorry about that I'll read those before I ask questions, this fixed the problem:
    Code:
    csis << "Enter book title: ";
    cin.ignore(1,'\n');

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Printing out char elements in an array from user input
    By hencherz in forum C Programming
    Replies: 11
    Last Post: 02-23-2012, 08:48 AM
  2. Input from file no white space characters
    By Dan17 in forum C++ Programming
    Replies: 5
    Last Post: 05-09-2006, 08:28 AM
  3. space problem with user input
    By codebrawler in forum C++ Programming
    Replies: 5
    Last Post: 01-08-2006, 02:01 PM
  4. fgets - user input including spaces
    By MethodMan in forum C Programming
    Replies: 24
    Last Post: 03-12-2004, 07:36 PM
  5. White space problems in file input
    By cxs00u in forum C++ Programming
    Replies: 4
    Last Post: 03-20-2002, 11:06 PM