I'm trying to store a string entered by the user into a dynamic array. For "normal" arrays, you simply use the get function as I've used it here and everything works fine. However it seems that this doesn't work for dynamic arrays. When compiled, the program basically just skips the whole input segment and moves on to what comes after it. It doesn't even pause to let me type anything. So how do I store cin input into a dynamic array? Note: This is for a specific assignment, so please don't tell me to use a string or a non-dynamic array; I can't.
int arraySize;
cout << "Enter a maximum length for the string: ";
cin >> arraySize;
arraySize += 1;
char *inputPtr;
inputPtr = new char[arraySize];
cout << "Enter a string to be converted: ";
cin.get(inputPtr, arraySize);
When interacting with a human it is best to do so a line at a time.
The std::cin is line buffered so people type the answer followed by return. Thus you should adapt the same behavior in your code.
std::string arraySizeString;
std::getline(std::cin, arraySizeString); // Get user input.
// Convert input to type we want.
int arraySize;
std::stringstream arraySizeStream(arraySizeString)
if (! (arraySizeStream >> arraySize))
{
// Error user did not enter a number.
// You may want to check if the user entered more than just a number
throw 1;
}
// Now read the lines into a dynamically size array (or vector).
std::vector<std::string> data(arraySize);
for(int loop = 0; loop < arraySize; ++loop)
{
std::getline(std::cin, data[loop]);
}
The problem you are having is that operator>> when used on a string only reads a "white space" seporated word from the input (it leaves the '\n' on the input stream). So if you combine operator>> with other read operations you need to remember to take this fact into consideration and compensate.
This is not a problem of dynamic array. When you enter the size of array, the new line character is stored into a buffer. When it comes to the last line (cin.get), it is taken that new line character and exit the program.
Try
cin >> inputPtr;
instead of
cin.get(inputPtr, arraySize);
Related
I wish to limit the number of characters that the user can enter, using cin. I might wish to limit it to two characters, for instance. How might I do this?
My code looks like this:
cin >> var;
You can use setw()
cin >> setw(2) >> var;
http://www.cplusplus.com/reference/iostream/manipulators/setw/
Sets the number of characters to be used as the field width for the
next insertion operation.
Working example provided by #chris: http://ideone.com/R35NN
hmm you could make 'var' a character array and use a while loop to read input until the array was full maybe?
char var[somenumber + 1];
int count = 0;
while(count < somenumber){
cin >> var[count];
count++;
}
var [somenumber] = '\0';
Hello everyone I'm having trouble with strlen and arrays, it keeps saying my string length is only one? If anyone could help it would be great here's my code:
#include <iostream>
using namespace std;
#include <cstring>
int main()
{
char word1[20];
int len = strlen(word1);
cout << "enter a word!\n";
cin.get(word1, 20, '\n'); cin.ignore(50,'\n');
cout << len;
}
Just read the back and forth in the comments, updating my answer to try and give some more intuition behind what's going on.
char word1[20]; Sets a place in your computer's memory that can eventually be filled by data up to 20 characters. Note that this statement alone does not "clear" the memory of whatever is currently there. As sfjac has pointed out, this means that literally anything could be in that space. It's highly unlikely that whatever is in this space is a character or anything your code could readily understand.
int len = strlen(word1); Creates an integer and sets it equal to the value of the number of characters currently in word1. Note that, because we have not specified any content for word1, you're taking the length of whatever happened to be in that memory space already. You've limited the maximum to 20, but in this case, whatever data junk is in there is giving you a length of 1.
cout << "enter a word!\n"; Prompt the user for a word
cin.get(word1, 20, '\n'); cin.ignore(50,'\n'); Get the word, store it in word1. At this point, word1 is now defined with actual content. However - you've already defined the variable len. The computer does not know to automatically redefine this for you. It follows the steps you provide, in order.
cout << len; Print the value stored in len. Because len was created prior to the user entering their data, len has absolutely nothing to do with what the user entered.
Hope this helps give you some intuition that will help beyond this one question!
#Chris is correct but perhaps a small explanation. When you declare a character array like char word1[20] on the stack, the array will not be initialized. The strlen function computes the length of the array by counting the number of characters from the address of word1 to the first null byte in memory, which could be pretty much anything.
I highly recommend using std::string for text.
If you must use character arrays:
Define a named identifier for the capacity.
Define the array using the named identifier.
The capacity should account for a terminating nul, '\0', character to
mark the end of the maximum text length.
Using the above guidelines you have the simple program:
int main(void)
{
std::string a_word_string;
std::string line_of_text_string;
const unsigned int c_string_capacity = 32U;
char c_string[c_string_capacity];
// The std::string functions
cout << "Enter some text: ";
getline(cin, line_of_text_string); // read a line of text
cout << "\nEnter a sentence: ";
cin >> a_word_string;
cin.ignore(10000, '\n'); // Ignore remaining text in the buffer.
// The C-style string functions
cout << "Enter more text: ";
cin.read(c_string, c_string_capacity);
c_string[c_string_capacity - 1] = '\0'; // Insurance, force end of string character
cout << "You entered " << (strlen(c_string)) << " characters.\n";
return EXIT_SUCCESS;
}
The std::string class is more efficient and can handle dynamically size changes.
The length of the array is the value of c_string_capacity which was used when defining the array.
The length of the text in the array is defined as strlen(c_string), which is the number of characters before the terminating nul is found.
You have to calculate len after reading in word1, otherwise you are left with undefined behaviour.
char word1[20];
cout << "enter a word!\n";
cin.get(word1, 20, '\n'); cin.ignore(50,'\n');
int len = strlen(word1);
cout << len;
It's a good idea to always initialize objects when you declare them. Since objects inside of a scope are not guaranteed to be initialized.
In C++11 for example, you can do this:
char arr[10]{}; // this will initialize the objects in the array to default.
char arr[10]{0}; // the same.
I'm practicing with c string / pointers and can't solve this simple problem. cin.getline() isn't prompting user input for the first iteration, but does so for the consecutive strings. (I arbitrarily chose 10 as the char limit).
Am I overlooking something extremely simple?
void getStrings() {
int num;
cout << "How many strings? ";
cin >> num;
const int numStrings = num;
char** stringSet = (char**) malloc(numStrings * sizeof(char*));
for (int i = 0; i < numStrings; i++) {
*(stringSet + i) = (char*) malloc(10);
cout << "String " << i << ": ";
cin.getline(stringSet[i], 10);
cout << endl;
}
Setting aside the fact that it's generally inadvisable to use bare pointers in C++ when things like the standard library's std::string are available, you should not use malloc. For example: Instead of (char*) malloc(10), you should write new char[10] and remember to delete[] *(stringSet+i) at the end of your program.
That said, the line:
cin >> num
... extracts only the first number it comes across. It will fail (and cin will set its fail bit, and will need to be reset with cin.reset()) if it encounters any non-whitespace characters before it encounters a number.
But it stops extracting from the input after that. In your input stream is still whatever whitespace or other characters were still present in your input. For example, if you ran this program and typed "2 foobar" before pressing enter, it would immediately print:
String 1: foobar
String 2:
This is because the stream still contains "foobar\n".
In order to get the behavior you're looking for you will probably want to add this before your loop:
cin.ignore();
That will clear the stream of anything that's there.
cin >> num;
This will prompt the user for some input. Assuming the user does what's expected of them, they will type some digits, and they will hit the enter key. The digits will be stored in the input buffer, but so will a newline character, which was added by the fact that they hit the enter key. cin will parse the digits to produce an integer, which it stores in the num variable. It stops at the newline character, which remains in the input buffer. Later, you call getline, which looks for a newline character in the input buffer. It finds one immediately, so it doesn't need to prompt the user for any more input. So it appears that the first call to getline didn't do anything, but actually it did.
What do you mean by " isn't prompting user input for the first iteration"? I read that to mean "isn't printing the prompt for the input of the first string", but based on your code, I think it means "is printing the prompt for the input of the first two strings before it reads input."
cin >> num reads a number, the whole number, and nothing but the number. It does not read whatever follows the number, like a newline. So the first getline reads the newline character which you've already typed.
By the way, you should use cerr instead of cout for user prompts.
cout should be reserved for actual output. That makes scripting much easier, because you can redirect cout independent of cerr, and because you don't want to capture prompts in the program results anyway.
I currently have a function that takes a array of 4 characters and returns another value based on that sequence of characters.
What I want is to have the user input a whole line of characters and then create a loop to go over each "sub- group of characters" and then return the result for all of them.
My initial thinking is to somehow use push_back to keep adding the arrays to a vector.
I don't know how long the entire array will be, but it should be a product of 3.
As an example, right now I am able to do :
char input [4] ;
cin >> input;
int i = name_index[name_number(input)];
cout << name[i].fullName;
But what I would like is the user ti input multiple name abbreviations at once
I would change your sample from this:
char input [4] ;
cin >> input;
int i = name_index[name_number(input)];
cout << name[i].fullName;
To this:
string input;
cin >> input;
const int i = name_index[name_number(input)];
cout << name[i].fullName;
Then you can start using a vector to track multiple inputs:
vector<string> inputs;
string line;
while (cin >> line)
{
if (line == "done")
break;
inputs.push_back(line);
}
for (unsigned int i = 0; i < inputs.size(); ++i)
{
cout << "inputs[" << i << "]: " << inputs[i] << endl;
//const int index = name_index[name_number(inputs[i])];
//cout << name[index].fullName;
}
You asked for an explanation of line. The line while (cin >> line) tries to take text from the standard input and put it into line. By default, this will stop when it encounters whitespace (space, tab, return, etc.) If it succeeds, then the body of the while loop is executed and we add what was input to the vector. If not, then we assume we're at the end of input and stop. We can then process the vector. (In the code linked below, I just output it since I don't know what name_index or name_number are.
(Working code here)
The way cin works, is it will accept any amount of input and separate them each by spaces, when you ask for specific input it prompts the user to give input, and then only takes the very first string (up until the space). If there are any more input after that, another cin >> input will just retrieve that value without prompting the user again. You can tell when the actual end of the input is reached when there is only a newline character left. This code should allow you to type in multiple strings separated by spaces and then process them all at once after the user enters the text:
char input[4];
do // Start our loop here.
{
// Our very first time entering here, it will prompt the user for input.
// Here the user can enter multiple 4 character strings separated by spaces.
// On each loop after the first, it will pull the next set of 4 characters that
// are still remaining from our last input and use it without prompting the user
// again for more input.
// Once we run out of input, calling this again will prompt the user for more
// input again. To prevent this, at the end of this loop we bail out if we
// have come accros the end of our input stream.
cin >> input;
// input will be filled with each 4 character string each time we get here.
int i = name_index[name_number(input)];
cout << name[i].fullName;
} while (cin.peek() != '\n'); // We infinitely loop until we reach the newline character.
EDIT: Also, keep in mind that allocating only 4 characters to input does not account for the end of string character '\0' that will be tacked on the end. If the user inputs 4 characters then it will actually access bad memory when it assigns the string to your input. There are 4 characters + 1 end character which means you need a minimum of 5 characters allocated for your input. The best way is to just use std::string as it will size itself properly even if the user enters more than 4 characters.
i am experiencing much trouble reading in files from input into an array struct. here is the code if someone can tell me what im doing wrong i can figure it out. the loop is supposed to be reading 2 strings, and 1 int, and skipping possible blank lines. but when i run it, it reads the first set and doesnt read nothing after that.
struct Instruments
{
string model;
string maker;
int year;
};
int main()
{
int size;
Instruments data[20];
int i =0;
ifstream fin;
fin.open("input.txt");
for (i=0; i<20; i++)
{
do{
getline(fin, data[size].model);
getline (fin, data[size].maker);
fin >> data[size].year;
size++;
}
while (data[size].model.length() > 0);
}
fin.close();
for(int i=0;i<size; i++)
{
cout << data[i].model << "model"<<endl;
cout << data[i].maker << "maker" << endl;
cout << data[i].year<< " year" << endl;
}
return 0;
}
There are multiple issues here:
Your first 'for' loop is using i as the loop counter but size as the array index.
After this call:
fin >> data[size].year
it will read to the end of the number and any whitespace that follows will form part of your next read, so if you are expecting to start the next record at the next line, do a blank getline() here too.
Aside from that.
Use vectors not arrays
Have a method to read from a stream into your struct, and if that succeeds, use push_back() to add it to your vector.
That doesn't necessarily mean you have to loop until the read fails, it may be that you know in advance how many you wish to read. But you should still do it this way.
size variable is not initialized. In C++, variables are not automatically initialized.
You must add:
int size = 0;
This is just a guess. In addition to the missing initialization of size, the following:
do{
.....
}
while (data[size].model.length() > 0);
looks also quite suspect to me: as soon as data[size].model has some content (which it does after the first read, this will evaluate to true and you probably have an infinite loop.
If you craft the for loop correctly, you don't need the do-while loop.