Solved

IstringStream Problems

Posted on 2003-10-23
23
295 Views
Last Modified: 2012-06-21
Basically, I'm trying to take a string, switching it to integers and printing it out.. But for some reason, no matter what char it finds, it gives it the same value..

code:

#include <iostream> // For COUT
#include <string> // Strings
#include <sstream> // StringStreams
#include <iomanip>

using namespace std;

int main() {
      string name;
      cout << "Enter your name: ";
      getline(cin, name);
      int count = name.length();
      string split;
      int intcode;
      for (int j=0; j <= count; j++) {
            split = name.substr(0, j+1);
            istringstream toint(split);
            toint >> intcode;
      cout << intcode;
      ostringstream tostr(intcode);
      string code;
      tostr << setprecision(15) << code;
      cout << code;
      }
  return 0; // End
}

end code:

thanks alot,

Rob
0
Comment
Question by:masta_mind
23 Comments
 
LVL 4

Expert Comment

by:n_fortynine
Comment Utility
A quick test I can think of...

string num, test;
int i;
istringstream strm(num);
strm >> i;
stringstream buff;
buff << i;
buff >> test;
if(test != num) cout << "num is not an legal integer\n";
else cout << "num is a legal integer\n";
0
 
LVL 15

Expert Comment

by:efn
Comment Utility
If the characters you feed the program can't be converted to an integer, the line

toint >> intcode;

is not going to change intcode, so it will always contain the same thing (uninitialized garbage).

When I fed digits to the program, it behaved reasonably according to the code.  When I entered "123", it put out 112123123, which makes sense the way the loop is coded.

It doesn't make sense to initialize tostr with intcode.  The constructor will take this as a bunch of flags, which is probably not what you want.

The string named "code" is constructed empty by default and never gets any content, so it doesn't do anything useful to put it into either cout or tostr.

--efn
0
 
LVL 13

Expert Comment

by:SteH
Comment Utility
         split = name.substr(0, j+1);
puts the first j elements in the substr. Intcode gives the integer of the first element in the substring which stays the first element of the name. Did you ment
         split = name.substr (j,j+1); ?
0
 

Author Comment

by:masta_mind
Comment Utility
SteH::  Ya, I noticed that, I was thinking that might be the problem, but it wasn't.

efn:: Ya, I see what you mean.  So I came up with this:

#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>

using namespace std;

int main() {
      string name;
      cout << "Enter your name: ";
      getline(cin, name);
      int count = name.length();
      string split;
      int intcode;
      for (int j=0; j <= count; j++) {
            split = name.substr(j, j+1);
            istringstream toint(split);
            int intcode = toint.get(); // NEW LINE
      cout << intcode;
      }
  return 0; // End
}

So I changed it to toint.get.. but my question now is how to use setprecision.  I'm not sure, I have tried a few different combos and none seem to work
0
 

Author Comment

by:masta_mind
Comment Utility
Well, the more I read up on setprecision, it looks as though it doesn't *seem* to change things to the left of the decimal.  So is there any better way cause i want it no matter what name you have the same length of numbers, and I also want to get rid of the -1 after everything.
0
 
LVL 15

Expert Comment

by:efn
Comment Utility
Sorry, I can't tell what you are trying to do here.  Perhaps it would help if you showed some input strings and the integers you would like the program to get from those inputs.

--efn
0
 

Author Comment

by:masta_mind
Comment Utility
Well when I enter my name:

Rob Shaw .. it outputs::

8211198328310497119-1

I am not sure what the -1 means..

And if I enter like RS::

8283-1

So basically, I want to set it so they all have the same length.. is this possible at all?
0
 

Author Comment

by:masta_mind
Comment Utility
I know that each integer is basically one or two numbers so if I enter R it equals 82 and so forth, but I am wondering what other way I could get the same length..
0
 

Author Comment

by:masta_mind
Comment Utility
I also put it in a menu program and am having a hard time getting it to display outside the for statement...

#include <iostream>
#include <algorithm>
#include <string>
#include <stdio>
#include <sstream>
#include <iomanip>

using namespace std;

      int menu(); // Menu Function
       void Validate(); // Program
       void Keygen(); // Program

int main() {
      bool exit = false;
      for (;;) {
        int choice = menu();
        switch(choice) {
            case (1):
              Validate(); //
              break;
            case (2):
              Keygen();
              break;
            case (3):
              exit=true;
              break;
            default:
              cout << "Please select again!\n";
              system("PAUSE");
              break;
            }
      if (exit)
            break;
      }      
}

int menu() {
               int choice;
            system("CLS");
            cin.clear(); // clear all previous cin's
            cout << "*******************************" << "\n"
               << "*             Menu            *" << "\n"
               << "*******************************" << "\n\n";
                  cout << "(1) Validator.\n";
                  cout << "(2) Key Generator.\n";
                  cout << "(3) Quit. \n\n";
                  cout << "Enter Choice --> ";
                  cin >> choice;
                  cout << "\n";
                  return choice;
}

int length(string name) {
      int x = name.length();
      return x;
}

int split(string name) {
         string split;
     int count = length(name);
     int intcode;
     for (int j=0; j <= count; j++) {
          split = name.substr(j, j+1);
          istringstream toint(split);
          intcode = toint.get();
              intcode = intcode;
            }
            return intcode; // outside the for loop i get -1, and inside i get the int for the first letter of string name..
}
// *** //
void Keygen() {
            string name, blank; // declare the strings
      getline (cin, blank);
      cout << "Please Type In Your Name: ";
      getline (cin, name);
      cout << "Key: " << split(name) << endl;
      system("PAUSE");
}
// *** //
void Validate() {
            string name, blank; // declare the strings
            int key;
      getline (cin, blank);
      cout << "Please Type In Your Name: ";
      getline (cin, name);
      cout << "\nPlease Enter The KeyGen: ";
      cin >> key;
      if (key == split(name)) cout << "Valid Keygen!" << endl;
      else cout << "Invalid." << endl;
      system("PAUSE");
}



// outside the for loop i get -1, and inside i get the int for the first letter of string name..
0
 

Author Comment

by:masta_mind
Comment Utility
Also don't worry, this key-generator is for a school project soo nothing illegal.. ;)
0
 
LVL 15

Expert Comment

by:efn
Comment Utility
OK, I can explain the -1.  Let's take the case where you enter "RS".  Then name == "RS" and count == 2.

The first time through the loop, j == 0 and split == "R".  So intcode gets the numeric value of 'R'.

The second time through the loop, j == 1 and split == "S", so intcode gets the numeric value of 'S'.

After the second time through the loop, j is incremented to 2 and j <= count is still true, so the loop runs a third time.  There are only two characters in name, with indexes 0 and 1, so name.substr(2, 3) returns an empty string.  So split is an empty string.  So toint has no character in its buffer.  So toint.get() returns the EOF (end of file) code, which is -1.

As you may have figured out by now, when there are two characters, you only want to run the loop two times, but the test j <= count makes it run three times.

The second parameter to substr is a length, so name.substr(j, j + 1) doesn't make sense.  In the example above, the second time through the loop, it would be getting name.substr(1, 2), but 2 is the length and there are not 2 characters available at position 1.

You can get the numeric value of character j of name much more simply, like this:

int intcode = name[j];

You don't need the stringstream.

I don't understand what you mean by all having the same length.  If you can explain more, I may be able to advise you.

--efn
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 

Author Comment

by:masta_mind
Comment Utility
Well, the whole reason for the program is to have a key-generator so if someone in class wants to log-in they have a special keygen to login as.  So basically, I want every output to be let's say 7 numbers long so if I enter::

Rob Shaw  --> (i get)  123-4567
RS --> 345-1234

Not necessarily those numbers but the same numeric length.
0
 
LVL 15

Expert Comment

by:efn
Comment Utility
OK, it looks like you want to define a mapping from strings to k-digit numbers where k is a constant.  To do that, you need an algorithm, a precise method.  What's your algorithm?

--efn
0
 

Author Comment

by:masta_mind
Comment Utility
I have no idea.. I'm still really new to C++ so...

I figured you might be able to do something like test for different string lengths and ****.. or maybe at least have it test if less then 5 chars then it says invalid input.  [since i don't know algorithms too well]
0
 

Author Comment

by:masta_mind
Comment Utility
The only other problem I seem to be having is inside my menu program, trying to get it to return the code, because I can't get it to work outside the for statement..
0
 
LVL 15

Accepted Solution

by:
efn earned 20 total points
Comment Utility
For a simple approach, you could just add up all the characters:

     int intcode = 0;
     for (int j=0; j < count; j++) {
          intcode += name[j];
          }

If you want to avoid negative numbers, you can use unsigned integers.

The code you have now sets intcode to the value of each character successively, ending with the -1 EOF character.  So each assignment to intcode wipes out any previously assigned value.

When you read it in, you can check the length of the string read.  That would mean that if the name were short, the number might have to be entered with leading zeros.

--efn
0
 

Author Comment

by:masta_mind
Comment Utility
Ahh thank you!
0
 

Author Comment

by:masta_mind
Comment Utility
I dunno if you can also look up at my for statement to return intcode in my void Keygen thing and tell me how I can get it out of there to return it..


Thanks..
0
 

Author Comment

by:masta_mind
Comment Utility
My new menu code is:


#include <iostream>   // for cout function
#include <string>        // for string related stuff

using namespace std;

      int menu();         // declare menu function
       void Validate();   // declare validator function
       void Keygen();     // declare keygenerator function

int main() {
      bool exit = false;
      for (;;) {
        int choice = menu();
        switch(choice) {
            case (1):
              Validate();
              break;
            case (2):
              Keygen();
              break;
            case (3):
              exit=true;
              break;
            default:
              cout << "Please select again!\n";
              system("PAUSE");
              break;
            }
      if (exit)
            break;
      }      
}

int menu() {
               int choice;
            system("CLS");
            cin.clear();
            cout << "*******************************" << "\n"
               << "*             Menu            *" << "\n"
               << "*******************************" << "\n\n";
                  cout << "(1) Validator.\n";
                  cout << "(2) Key Generator.\n";
                  cout << "(3) Quit. \n\n";
                  cout << "Enter Choice --> ";
                  cin >> choice;
                  cout << "\n";
                  return choice;
}

int length(string name) {
      int x = name.length();
      return x;
}

int split(string name) {
         string split;
     int count = length(name);
     int intcode;
     for (int j=0; j<count; j++) {
              split = name.substr(j, count-j);
          intcode = name[j];
       }
             return intcode;
}

void Keygen() {
 string name, blank; // declare the strings
      getline(cin, blank);
      cout << "Please Type In Your Name: ";
      getline(cin, name);
      if (length(name) < 5) {
             cout << "Invalid Input.." << endl;
      } else {  // if length >= 5
             cout << "Key: " << split(name) << endl;
      }
 system("PAUSE");
}

void Validate() {
 string name, blank; // declare the strings
            int key;
      getline(cin, blank);
      cout << "Please Type In Your Name: ";
      getline(cin, name);
      if (length(name) < 5) {
             cout << "Invalid Input.." << endl;
      } else {  // if length >= 5
      cout << "\nPlease Enter The KeyGen: ";
      cin >> key;
      if (key == split(name)) cout << "Valid Keygen!" << endl;
      else cout << "Invalid." << endl;
      }
 system("PAUSE");
}
0
 
LVL 15

Expert Comment

by:efn
Comment Utility
Sorry, I don't understand your last question.
0
 

Author Comment

by:masta_mind
Comment Utility
Well, when I enter a name after selecting keygenerator in my menu program there, it returns :: 119 instead of the actual number...

Basically because I put it outside the for statement,but if I put it in, I get an even weirder number..

0
 
LVL 15

Expert Comment

by:efn
Comment Utility
This is your loop for calculating intcode:

     for (int j=0; j<count; j++) {
            split = name.substr(j, count-j);
          intcode = name[j];
      }

name is a string.  name[j] is a character.  Each iteration of the loop assigns a different character to intcode, wiping out whatever was there before.  At the end of the loop, intcode will contain the numeric value of the last character in the string.  You could do the same thing in one statement without a loop:

intcode = name[name.length() - 1];

Presumably you have a loop because you want each character of the name to have some effect on the integer in which it is encoded.  Just assigning each character to the integer won't do that.  I suggested one way to do it in a previous comment.  Bear in mind, though, that if you use that algorithm, you may get what you consider a weird number.

--efn
0
 

Author Comment

by:masta_mind
Comment Utility
Ahh.. Alright, so I can can use algorithms better to get to my answer.  Thanks alot..


lol about the weird number part.. The only reason I called it a weird number was because whatever name I would enter, I would get [123] <--always and [xxx] for the rest..
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now