-1

Hi I'm trying to take a c-string from a user, input it into a queue, parse the data with a single space depending on its contents, and output the kind of data it is (int, float, word NOT string).

E.g. Bobby Joe is 12 in 3.5 months \n

Word: Bobby

Word: Joe

Word: is

Integer: 12

Word: in

Float: 3.5

Word: months

Here's my code so far:

int main()
{
    const int maxSize = 100;

    char cstring[maxSize];

    std::cout << "\nPlease enter a string: ";
    std::cin.getline(cstring, maxSize, '\n');

//Keyboard Buffer Function
buffer::keyboard_parser(cstring);

return EXIT_SUCCESS;
}

Function:

#include <queue>
#include <string>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>

namespace buffer
{
    std::string keyboard_parser(char* input)
{
    //Declare Queue
    std::queue<std::string> myQueue;

    //Declare String
    std::string str;

    //Declare iStringStream
    std::istringstream isstr(input);

    //While Loop to Read iStringStream to Queue
    while(isstr >> str)
    {
        //Push onto Queue
        myQueue.push(str);

        std::string foundDataType = " ";

        //Determine if Int, Float, or Word
        for(int index = 0; index < str.length(); index++)
        {
            if(str[index] >= '0' && str[index] <= '9')
            {
                foundDataType = "Integer";
            }
            else if(str[index] >= '0' && str[index] <= '9' || str[index] == '.')
            {
                foundDataType = "Float";
                                    break;
            }
            else if(!(str[index] >= '0' && str[index] <= '9'))
            {
                foundDataType = "Word";
            }
        }

        std::cout << "\n" << foundDataType << ": " << myQueue.front();
        std::cout << "\n";

        //Pop Off of Queue
        myQueue.pop();
        }
}   
}

Right now with this code, it doesn't hit the cout statement, it dumps the core.

I've read about using the find member function and the substr member function, but I'm unsure of how exactly I need to implement it.

Note: This is homework.

Thanks in advance!

UPDATE: Okay everything seems to work! Fixed the float and integer issue with a break statement. Thanks to everyone for all the help!

user3062299
  • 55
  • 2
  • 5
  • 10
  • 2
    Why a C-string? And why do you keep deliberately going off the end of your array by one? Finally, why not use a debugger? – Lightness Races in Orbit Mar 19 '14 at 00:35
  • I don't know, that's the requirement. – user3062299 Mar 19 '14 at 00:36
  • What requirement? From whom? Why? – Lightness Races in Orbit Mar 19 '14 at 00:36
  • Sorry, should have labeled as homework! – user3062299 Mar 19 '14 at 00:41
  • it should be rather `std::cin.getline(cstring, maxSize, '\n');` unless you are asking for trouble... – m.wasowski Mar 19 '14 at 00:47
  • @m.wasowski Still getting seg fault. – user3062299 Mar 19 '14 at 00:50
  • Your code runs when I try it, except that I had to make maxSize const (no C++11 here). I noticed that your prompt/input pair should probably go into the loop (right now the string never changes). It is also weird that you loop maxSize times as if you wanted to iterate char by char through the string, not through different strings. – Peter - Reinstate Monica Mar 19 '14 at 00:54
  • Yeah I keep getting a segmentation fault, no idea what's going on. Using gcc. – user3062299 Mar 19 '14 at 00:58
  • @PeterSchneider Well, the thing is, the user should be able to input a string and the program parses it for them... So it shouldn't be running the prompt multiple times. – user3062299 Mar 19 '14 at 01:03
  • I see. What's your input? – Peter - Reinstate Monica Mar 19 '14 at 01:05
  • Right now I'm just inputting "please work" but it isn't outputting anything at all... Just a seg fault. – user3062299 Mar 19 '14 at 01:10
  • Well, `std::string parseIt(input) {` isn't even valid syntax... – Lightness Races in Orbit Mar 19 '14 at 01:11
  • Yeah I changed it within my code to be 'char &input' but nothing... – user3062299 Mar 19 '14 at 01:13
  • Uhh, `char&` is not the right type for that function. It should be `char*`. – paddy Mar 19 '14 at 01:17
  • Whoa! Okay it works! Thanks! But how do I make it so that it parses the words from the space delimiter? Cause right now it just printed my input 100 times... – user3062299 Mar 19 '14 at 01:19
  • That's because you loop 100 times pushing stuff onto the queue and outputting. You probably want to use something like `string::find`, or use `istringstream` – paddy Mar 19 '14 at 01:21
  • Alright, thanks I'll try that out right now. – user3062299 Mar 19 '14 at 01:24
  • Actually, is it possible to push it onto the queue character by character until it hits a white space and then analyze the contents of the queue from that point? – user3062299 Mar 19 '14 at 01:26
  • Yes, but it's a wasteful and kinda pointless approach. You would push all characters onto the queue (until you hit the string terminator), then pop elements off the queue until you hit whitespace. – paddy Mar 19 '14 at 01:32
  • Unfortunately, that's what the instructor wants us to do for queue practice. How would you implement it? Obviously you'd use the find member function but how exactly? – user3062299 Mar 19 '14 at 01:35
  • Actually, no I would use a string stream, and put whole words in the queue: `for( string s, istringstream iss(input); iss >> s; myQueue.push(s) );`. – paddy Mar 19 '14 at 01:41
  • Works like a charm! Going to update and finish code in a little while. Thanks to everyone for their input! – user3062299 Mar 19 '14 at 01:59
  • Right it all works but now I'm stuck on determining the datatypes... – user3062299 Mar 19 '14 at 02:53
  • Couple notes on your current code... your `for` loop goes over the string setting the data type according to the characters it sees: say is saw `"1.3A2"` -> when `index` is `0` it sees `'1'` so sets `foundDataType` to `"Integer"`, then `index` `1` sees `'.'` and overwrites `"Float"`, then "3" sets "Integer" again, "A" so "Word", '2' so "Integer" - you can't decide using only the final character. Separately, you should support a leading '-' (and probably '+'), and floats in C++ can be written like 1E2 for 1 times 10 to the power of 2, i.e. 100 - you may or may not care to support that. – Tony Delroy Mar 19 '14 at 03:56
  • Thanks, so how would you recommend fixing the if statement? – user3062299 Mar 19 '14 at 04:05
  • Ah-ha! Figured it out, just used a break statement! – user3062299 Mar 19 '14 at 04:13

2 Answers2

1

Your queue is sensible: it contains std::strings. Unfortunately, each of those is initialised by you passing cstring in without any length information and, since you certainly aren't null-terminating the C-strings (in fact, you're going one-off-the-end of each one), that's seriously asking for trouble.

Read directly into a std::string.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • While this is all true and I heartily agree with your advice, I wonder: afaik getline() terminates the char array after the terminator has been encountered by writing a 0 char. With the apparently manual input it's likely that the input is shorter than 99 chars so that the index issue of "n+1" instead of "n-1" shouldn't be a problem. So with input consisting of short lines, cstring should be 0 terminated. – Peter - Reinstate Monica Mar 19 '14 at 00:47
  • Now I'm getting a segmentation fault with the queue. I'm totally new to queues so I'm not sure how to properly use them. – user3062299 Mar 19 '14 at 00:48
  • What book or other resource do you use? – Peter - Reinstate Monica Mar 19 '14 at 00:56
  • Right now, I'm using Data Structures and Other Objects Using C++ by Michael Main and Walter Savitch, fourth edition. – user3062299 Mar 19 '14 at 01:00
0

std::istreams are very useful for parsing text in C++... often with an initial read of a line from a string, then further parsing from a std::istringstream constructed with the line content.

const char* token_type(const std::string& token)
{
    // if I was really doing this, I'd use templates to avoid near-identical code
    // but this is an easier-to-understand starting point...
    {
        std::istringstream iss(token);
        int i;
        char c;
        if (iss >> i && !(iss >> c)) return "Integer";
    }
    {
        std::istringstream iss(token);
        float f;
        char c; // used to check there's no trailing characters that aren't part
                // of the float value... e.g. "1Q" is not a float (rather, "word").
        if (iss >> f && !(iss >> c)) return "Float";
    }
    return "Word";
}

const int maxSize = 100;  // Standard C++ won't let you create an array unless const
char cstring[maxSize];
std::cout << "\nPlease enter a string: ";
if (std::cin.getline(cstring, maxSize, '\n'))
{
    std::istringstream iss(cstring);
    std::string token;
    while (iss >> token) // by default, streaming into std::string takes a space-...
        token_queue.push(token);    // ...separated word at a time

    for (token_queue::const_iterator i = token_queue.begin();
         i != token_queue.end(); ++i)
        std::cout << token_type(*i) << ": " << *i << '\n';
}
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • @PeterSchneider Oh jeez... half asleep still... fixed. Re `getline` et al - the assignment apparently asks for "C" strings and `queue`s, and I think the OP's interpretation of what's expected there's sane, so have retained that. Cheers. – Tony Delroy Mar 19 '14 at 01:32
  • Thank you for this, I'm going to see if it does exactly what I need it to do and modify as needed. – user3062299 Mar 19 '14 at 01:38
  • I also took the liberty to fix the wrong string length in getline (or did you try to make a case for strings ? ;-) ) – Peter - Reinstate Monica Mar 19 '14 at 01:45
  • @PeterSchneider: I cut-and-pasted without reading...! :-/ Thanks! – Tony Delroy Mar 19 '14 at 02:02
  • @user3062299 `iss >> i` consumes any leading whitespace in the input stream's buffer (there won't be any because `iss >> token` had already ensured tokens had no whitespace), then reads characters until it's either managed to extract an integral value or failed (e.g. successes "1X" -> 1, "0.2" -> "0", "-3" -> -3, "+4" -> 4; failures "X1", "--2", "E10", "-+2"). The state of the `istringstream` afterwards reflects whether the parsing succeeded, and in a boolean context the object will evaluate `true` or `false` accordingly, which is why use in `if` is convenient. – Tony Delroy Mar 19 '14 at 03:39