Problem with forming string array using loop - c++

I want to create a string array using loop inputs and then give ASCII based output for each character of the string.
Here is my code
int n;
cin >> n;
string arr[n];
for(int i=0;i<n;++i){
getline(cin,arr[i]);
}
for(int i = 0;i < n; ++i){
for(int j = 0;j < arr[i].length(); ++j){
cout << to_string(arr[i].at(j)) << " ";
}
cout << endl;
}
the program takes n : number of string inputs
but allows me to input only n-1 strings.
What is the problem here?

You are reading n strings, but the first one doesn't contain what you expect.
When you write input in the console, you write something like:
3\nstring1\nstring2
, where \n is the newline character (when you press Enter).
When you do cin >> n, you parse this input string, and you get the integer. Meaning that you remain with
\nstring1\nstring2
in the buffer. And when you do a getline, you parse everything up to the first newline (including the newline). That's why you get the first string empty.
A quick and dirty fix is to read the newline too:
int n;
char newline;
cin >> n >> newline;
, and then loop as you do now.
Some remarks about your code.
string arr[n] is not valid C++. In C++, there is no official support for arrays with variable size like this (some compilers support it, but this doesn't mean it's standard). You should use a std::vector:
std::vector<std::string> arr(n);
(the rest of the code remains the same). An even better way would be to declare it empty, and then use push_back to populate it.
Also, when comparing j < arr[i].length(), you are comparing a variable of type int with a variable of type size_t, which might be bigger than an int and create issues for very long strings. Use size_t as the type for j.

Use a std::vector
A vector is dynamic array. So change:
string arr[n];
to
std::vector<std::string> arr(n);

According to your code snippet what you want to read is a number of strings and then output for each of them the ASCII value of all of its characters:
If you have an input like the following
2
abc
def
you would like to obtains as a result something like the following:
97 98 99
100 101 102
In order to achieve that I see at least a couple of problems with your code.
C++ does not support variable size arrays by default. It means you cannot create an array whose size is not known at compile time (see this answer for more info about it)
In order to output the ASCII of the char you simply need to cast the char to int and that is it.
using getline in this case complicates the code because of the way getline works with newline. Simply use cin>>arr[i] to read each string.
Here is it a version of your code that does what you expect:
int n;
cin>>n;
vector<string> arr(n);
for(int i=0;i<n;++i)
cin>>arr[i];
for(const auto& s : arr){
for(const auto& c : s){
cout<<(int)c<<" ";
}
cout<<endl;
}

If you need a list of strings, you can use vector:
#include<vector>
#include<string>
int n;
cin >> n;
vector<string> arr(n);
for(int i = 0; i < n; ++i){
getline(cin, arr[i]);
}
for(auto& str : arr){
for(auto& c : str){
cout << to_string(c) << " ";
}
cout << endl;
}

Related

Reading space separated input into an array in C++

What is the easiest way to read space separated input into an array?
//input:5
1 2 3 4 7
int main() {
int n;
cin>>n;
int array[n];
for (int i =0;i<n;i++){
cin>>array[i];
}
cout<<array;
return 0;
}
I tried the code above but the output is 0x7ffe42b757b0.
The problem lies with your printing. Since array is a pointer, you are only printing an address value.
Instead, do this:
for (int i =0;i<n;i++){
cout<< array[i] << " ";
}
You can do that by passing std::istream_iterator to std::vector constructor:
std::vector<int> v{
std::istream_iterator<int>{std::cin},
std::istream_iterator<int>{}
};
std::vector has a constructor that accepts 2 iterators to the input range.
istream_iterator<int> is an iterator that reads int from a std::istream.
A drawback of this approach is that one cannot set the maximum size of the resulting array. And that it reads the stream till its end.
If you need to read a fixed number of elements, then something like the following would do:
int arr[5]; // Need to read 5 elements.
for(auto& x : arr)
if(!(std::cin >> x))
throw std::runtime_error("failed to parse an int");
array variable always give base address of an array
for (int i =0;i<n;i++){
cout<< array[i] << " ";
cout<<*(array+i)<< " ";
}
Both cout statements will print same only.
in short
array[i] compiler will internally convert into *(array+i) like this only
in the second cout statement from base address of an array it won't add value,since it is an pointer it will add sizeof(int) each time for an increment

Length of string[] (number of elements in a string)

I want to cout my string, everything works as it should, but when the string is shown, it immediately shows me the "example_4578.exe has stopped running" error. I have noticed that the problem is in the i < str[32].length part, because when I change it to i < 3, it works without any problem. How should I solve this?
std::string str[32];
cin >> str[1];
cout << "str[1]=" << str[1] << endl;
cin >> str[2];
cout << "str[2]=" << str[2] << endl;
for (int i = 0; i < str[32].length; i++)
{
cout << str[i];
}
EDIT 1.
I've made a huge mistake. I actually want to find the "number" of elements/words in "str". In my example, I have only designed two cins. But I actually want to design a "for" loop later on, so that the user can input as many words as he wants, so if he inputs 4 words, I want that code to return those number of words to me. How should I do this? In other words, how can I find out how many elements are in "str"?
Couple of things:
C++ is 0-indexed. What this means is that std::string str[32] has indices that go from 0 to 31, and str[32] should not be accessed. This will cause a crash.
str[31].length() (which is presumably what you wanted) is the length of the last string, not the length of the array. The length of the array is 32, and your loop should read for(int i = 0; i < 32; i++).
The main problem is that you are accessing an element (number 32) that is out of the bounds (0 - 31). To solve this problem and not repeat it again in the future use a range-for loop:
std::string str[32];
for (auto s : str)
std::cout << s;
str[32].length is not what you think.
I guess you meant somthing like: length of a 32-elements array. Right?
What you've written is pointer to funciton length of 33rd element of array.
This is because the types are:
std::string str[32]; // `str` is 32-element array of `std::strings`
str[32]; // `std::string` taken from 33rd position in array `str` (arrays' indexing starts at 0)
std::string has a member function named size_t std::string::length(). When referenced by name, you get its address.
To achieve what you wanted, you'd need to write:
for (int i = 0; i < 32; i++) {
cout << str[i];
}
Unfortunately, plain arrays don't have length (or anything similar) built in. So, you'd either need to use a constant, or (better) use a container, such as std::vector.

C++ Creating a variable sized array from ifstream

Just a heads up: My c++ programming skills and terminology is intermediate at best. So please be gentle ;).
I am working on a multi-sort algorithm for a college class. Originally, I built the program to take in an array of 20 integers, since that was as big as the .txt files were. The final lab is now asking to take in files that have 10, 100, 1000, 10000, 100000 and 1000000 different numbers. I originally used an ifstream inside a for loop to read in the ints. Now that I need to read a variable amount of ints from a file, I have run into issues with this code. I have extensively searched this site and Google to find an answer to this problem. I have tried dozens of different code snippets, to no avail. Here is the code I am currently running that works for 20 ints.
int i;
int A[20];
int length;
char unsortedFilename[200];
ifstream unsorted;
cout << "Please type the full name of the file you would like sorted.\n* ";
cin >> unsortedFilename;
unsorted.open(unsortedFilename);
length = (sizeof(A) / sizeof(*A));
for( i = 0; i < length; i++ )
{
unsorted >> A[i];
cout << A[i] << "\n";
}
insertionSort();
I do have other code mixed in there, but it's error checking, selection of duplicate number removal, etc. I would like it so that code like this would run "i" number of times, where "i" is actually the number of ints in the file. Also, as I mentioned earlier, I will need to input a file that has 1,000,000 numbers in it. I don't believe that an int array will be able to hold that many numbers. Is it going to be as easy as swapping all my ints over to longs?
Thanks for any help you could provide.
As suggested in the comments, use std::vector<int> instead of an array.
Instead of a for loop, use a while loop. Break out of the while loop when there are no numbers to read.
The while loop:
std::vector<int> A;
int item;
while ( unsorted >> item )
{
A.push_back(item);
}
You can sort the std::vector by using std::vector::iterator or simply access the data through the int* returned by A.data().
You can simply read all the numbers into a vector. Then use the vector as you would have used the array.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
int main()
{
std::string unsortedFilename;
std::cout << "Please type the full name of the file you would like sorted.\n";
std::cin >> unsortedFilename;
std::ifstream is(unsortedFilename);
std::istream_iterator<int> start(is), end;
std::vector<int> A(start, end);
std::cout << "Read " << A.size() << " numbers" << std::endl;
}
What you want is a vector.
try this,
int i;
vector<int> A;
int length;
string unsortedFilename;
ifstream unsorted;
cout << "Please type the full name of the file you would like sorted.\n* ";
cin >> unsortedFilename;
unsorted.open(unsortedFilename);
int temp;
for( i = 0; unsorted >> temp; i++ )
{
A.push_back(temp);
cout << A[i] << "\n";
}
insertionSort();
A vector is basically a dynamic array. It automatically grows as more space is needed. That way it doesn't matter if you have 10, 100, or even 100000 items, it'll automatically grow for you.
Also use a string for your file name, some file names are longer than 200 characters.
Good Luck!
will need to input a file that has 1,000,000 numbers in it. I don't believe that an int array will be able to hold that many numbers.
Sure it can. 1 Million ints is ~4Mb of memory, which is a trivial amount. You can even declare it static just as you do now int A[1000000];.
But real problem is that you're assuming a fixed length in your code, rather than determine the length from the input. I guess this is what your assignment is trying to teach you, so I won't show you the solution. But consider using ifstream::eof and make your sort accept the length as an argument...

Not reading a string properly

I am practising user input handling. My goal is to have the user enter a line of integers separated by space (" "), read them as integers, store them and work on them later. I stumbled upon an interesting problem (Atleast in my oppinion) the way I am doing it, it seems that it is always not reading the last digit which was entered by the user. I will post the entire program here (since there are some extra libreries that are included).
I have left some comments in the program
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
using namespace std;
int main()
{
//this vector will store the integers
vector<int> a;
// this will store the user input
string inp;
getline(cin, inp);
// this string will temporarily store the digits
string tmp;
//be sure that the reading part is okay
cout << inp << endl;
//until you meet something different than a digit, read char by char and add to string
for(int i = 0; i < inp.length(); i++)
{
if(isdigit(inp[i]))
{
tmp +=inp[i];
}
else
{
// when it is not a character, turn to integer, empty string
int value = atoi(tmp.c_str());
a.push_back(value);
tmp = "";
}
}
// paste the entire vector of integers
for(int i = 0; i < a.size(); i++)
{
cout << a[i] << endl;
}
return 0;
}
Replace this line
for(int i = 0; i <inp.length(); i++)
by
for(int i = 0; i <= inp.length(); i++)
DEMO IDEONE
The problem with your code is: In example 25 30 46 whenever i=7, tmp=46. You are not pushing 46 in vector as inp[8] is a newline character, so your for loop terminates after i become 7.
Please Note: i <= inp.length() runs perfectly in most of the compilers as \0 is used/treated as sentinel.However, there are few compilers(like Microsoft Visual C++) that may show Assertion error: string subscript out of range.
If the very end of the line is a digit, you don't hit the else on the last iteration, and that last number never gets pushed into the vector.
The simplest solution would be to replicate the non-digit logic after the loop:
if (!tmp.empty()) // If tmp has content, we need to put it in the vector.
{
int value = atoi(tmp.c_str());
a.push_back(value);
tmp = "";
}
Although I'm sure you can think of a nicer way of structuring it.
Here's a version I came up with using std::stringstream, that also avoids atoi:
int main()
{
std::vector<int> ints;
std::string line;
std::getline (std::cin, line);
std::cout << "Read \"" << line << "\"\n";
std::stringstream ss(line);
int remaining = line.size();
while (remaining)
{
if(std::isdigit(ss.peek())) // Read straight into an int
{
int tmp;
ss >> tmp;
ints.push_back(tmp);
}
else
{
ss.get(); // Eat useless characters
}
remaining = line.size()-ss.tellg();
}
for (auto i : ints)
std::cout << i << '\n';
return 0;
}
Running:
$ ./a.out <<< "12 34 56"
Read "12 34 56"
12
34
56
Note, this is specifically made to work with any old gibberish between the numbers:
$ ./a.out <<< "12-abc34-56"
Read "12-abc34-56"
12
34
56
If there will only be whitespace, this is even easier, as reading ints from a stringstream will ignore that automatically. In which case you just need:
int tmp;
while (ss >> tmp)
{
ints.push_back(tmp);
}
Your program need a string which is ended with a non-digit character to work correctly. Try this string "1 12 14587 15 " because in your algorithm when your forgot the last space, your program store the number into the tmp string but don't save it into the vector. To correct that you need to add a last push_back just after your first loop.
You update a with new value only when when non digit is found. Thus if you have string ending with digits, tmp will contain digital string but you will never get to else that should perform push_back. You may fix this by adding following code after for loop
if(!tmp.empty()){
// when it is not a character, turn to integer, empty string
int value = atoi(tmp.c_str());
a.push_back(value);
tmp = "";
}
Before starting the loop, add a space to the string to be sure to push the last number: inp.push_back(' ')
Your loop is finished after last digit is read, so the last digit is never turned to integer. Just add some code after original for loop.
for(int i = 0; i < inp.length(); i++)
{
/* ...... */
}
// add this to read the last digit
if(tmp.length() > 0){
int value = atoi(tmp.c_str());
a.push_back(value);
tmp = "";
}
You never push back your last value. For instance, consider this input
40 36
Then while you are reading, you push back at the first space. But you never push 36 since there are no more characters.
After the end of your for() loop you can try this:
if(!tmp.empty()) {
a.push_back(tmp);
}
When the last digit of the last number is stored in tmp, after that the loop ends because you have read the last character of the entire string. When the loop ends tmp still contains the last number.
1) You can convert and add the last number to vector after the loop. The last number still available in tmp.
2) Or you can explicitly add non-digit character in the end of the string before the loop.
you ommit input. change your code to reflrct this:
//this vector will store the integers
vector<int> a;
// this will store the user input
string inp;
getline(cin, inp);
// this string will temporarily store the digits
string tmp;
//be sure that the reading part is okay
cout << inp << endl;
//until you meet something different than a digit, read char by char and add to string
for(int i = 0; i < inp.length(); i++)
{
if(isdigit(inp[i]))
{
tmp =inp[i];
int value = atoi(tmp.c_str());
a.push_back(value);
}
else
{
tmp = "";
}
}
// paste the entire vector of integers
for(int i = 0; i < a.size(); i++)
{
cout << a[i] << endl;
}
return 0;
or replace in loop:
for(int i = 0; i <inp.length(); i++)
by
for(int i = 0; i <= inp.length(); i++)

adding string objects to an array via loop

What i'm trying to do is create a template array class that will store values of a data type into an array. I have it working fine with int values, however working with string objects things start to break down.
I've taken out the block of code and tried it on it's own and I do get the same error. I'm sure I've learnt this, and I'm almost positive that the answer is something simple, trying to wrap my head around the pace in which we're learning c++ is a little crazy at times!
My best guess right now, is that I would need to tokenize the string and look for spaces. I tend to over think things though which lead to more confusion - thus me seeking out a answer here!
The code:
// Test String: Hello World this is a String Object
int stringSize = 7;
int count = 0;
string s[stringSize];
cout << "\nEnter " << stringSize << " one-word string values:\n";
while (count < stringSize) {
string tmpVal;
cin >> tmpVal;
s[count] = tmpVal;
count ++;
}
string s[stringSize]; is illegal because stringSize is not a constant. You must either use dynamic memory (i.e. string* s = new string [stringSize];), include stringsize as a template argument (don't do this, it doesn't actually solve the problem), use a fixed size value, or use an existing structure (I'd suggest vector, as in Bill's answer). The code below works fine on my compiler:
int main(int argc, char *argv[]) {
int stringSize = 7;
int count = 0;
string* s = new string [stringSize];
cout << "\nEnter " << stringSize << " one-word string values:\n";
while (count < stringSize) {
string tmpVal;
cin >> tmpVal;
s[count] = tmpVal;
count ++;
}
delete[] s;
}
I am a little confused as to exactly what you're looking for, but I suggest looking into the standard library.
Perhaps something like:
list<string> s;
and then, in the loop use push_back.
I am also confused what is your actual question, because your code works. However, FWIW, I would suggest the following. The changes are: (1) use of const (already suggested by others), (2) use of size_t, (3) change of variable name stringSize to numStrings (because of this I was confused at first glance), and (4) avoiding string copy.
#include <iostream>
#include <string>
using namespace std;
int main()
{
const size_t numStrings = 7;
size_t count = 0;
string s[ numStrings ];
cout << "\nEnter " << numStrings << " one-word string values:\n";
while (count < numStrings) {
cin >> s[ count ];
count++;
}
return 0;
}
Why not read in the entire line, then find all spaces and using the substr method, split the string?
You will need the following methods:
getline()
find_first_of()
substr()
Also, searching around this site for splitting strings in c++ will give you a lot of tips.
First of all, the size of your array should be constant:
const int stringSize = 7;
Secondly, as dbrien said, you should use std::vector unless you're doing this for the learning experience:
std::string tmpVal;
std::vector<std::string> s;
cout << "\nEnter " << stringSize << " one-word string values:\n";
while (cin >> tmpVal)
{
s.push_back(tmpVal);
}
First, the array dimension must be constant, so it should be const int stringsize = 7; Also, I would suggest using std::vector rather than std::list, additionally What was the error?
Not sure what error you're getting, but this is wrong because you need to use a constant integral value to allocate arrays on the stack.. Change:
int stringSize = 7;
int count = 0;
string s[stringSize];
... to:
const int stringSize = 7;
int count = 0;
string s[stringSize];
You can and probably should also use a vector instead of using C-style arrays, or trying to hand roll your own templated array class:
vector<string> s;
const int stringSize = 7;
cout << "\nEnter " << stringSize << " one-word string values:\n";
while (s.size() < stringSize) {
string tmpVal;
cin >> tmpVal;
s.push_back(tmpVal);
}
So it turns out it was the compiler. I was using xCode and getting:
cin_cout(7307) malloc: *** error for object 0x1000072c0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Running the same block in Visual c++ seemed to be ok... Sorry for my stupidity and thanks kindly for all the quick feedback!