Why can't my integers be transferred to an array? - c++

I want to make a program that works with integers that were inputted using space and not enter. when you input the integers 12 80 33 99 with space between each one of them, then the code will separate the integers and put them into an array.
I'm using codeblocks, C++
int main(){
int A;
int j [10] ={0,0,0,0,0,0,0,0,0,0};
cin >> A;
string As;
bool code = true;
int hasil [A][10];
getline(cin,As);
for (int i = 0 ; i < A ; i++){
while (code){
if( cin.get() != '\n'){
cin >> hasil[i][j[i]];
j[i]++;
}else{ code = false;}
}}
for (int i = 0 ;i < A ; i++){
for (int x = 0; x != j[i]; x++){
cout << hasil[i][x]<< " " ;
}
cout << " " << endl;
}
return 0;}
When I input 25 17 70 88, I expected the output to be 25 17 70 88 too, but the actual output was 5 17 70 88. Where is my first 2?

Your 2 was eaten by the call to cin.get() which reads one character which your code then throws it away.

I can't understand exactly what you are trying to do but i can see an error in your code which might cause undefined behaviour. int hasil[A][10] is a static array which means compiler must know its size at compile time, however A is not a compile time constant. If you don't know the size of your array you should use a pointer instead or even better a std container such as std::vector.
To make your code more readable you can also delete the code variable and replace your first for loop body with
while(cin.get() != '\n)
{
cin >> .....
...
}

Related

Reading in data from .txt file into structs

I have a file and I want to read in those elements into structs.
The file is structured like this:
n
m
lat1 lon_1
...
lat_n lon_n
nodeStart_1 nodeTo_1 nodeweight_1
...
nodeStart_m nodeTo_m nodeweight_m\
And this is the content of my file:\
3
4
48.5 6.6
48.3 5.5
48.3 4.8
23 24 25
26 27 28
29 30 31
29 41 43\
The numbers inside the file are just random ones.
n and m are integers, lan and lon are floats and the m edges are integers as well.
I have n nodes and m edges. So the 2nd to the n+2nd line should be read into nodeGr and all the m lines after that should be read into edgeGr.
These are my structs:
struct edgeGr{
int s,t,c;
}
struct nodeGr{
float lat, lon;
};
And here is my code, which doesn't work properly:
The problem is with reading in the nodes. I got it to work with lat and lon being integers but not with them being floats. When lat and lon are floats my edges are behaving weird and just become 000. I am not sure what exactly is wrong anymore since I tried way too many things and none of them work. Can you help me or give me some hints?
EDIT: it now works but the while loop is being executed twice, why is that?
void readGraph(std::ifstream & in, struct edgeGr edges[], struct nodeGr nodes[]){
int n;
int m;
while (!in.fail()){
in >> n;
in >> m;
for (int i = 0; i < n; i++) {
//TODO: get this to work
in >> nodes[i].lat >> nodes[i].lon;
}
for (int i = 0; i < m; i++) {
in >> edges[i].s >> edges[i].t >> edges[i].c;
std::cout << edges[i].s << edges[i].t << edges[i].c << '\n';
//This prints out all my edges just fine but twice and only if lat and lon are integers.
}
}
in.close();
std::cout << m << " " << n;
};
int main() {
std::ifstream in("test.txt");
nodeGr nodes[3]; //3 should be n
edgeGr edges[4]; //4 should be m
readGraph(in, edges, nodes);
std::cout << '\n' << edges[1].s <<" "<< edges[1].t <<" "<< edges[1].c << '\n';
return 0;
}
it now works but the while loop is being executed twice, why is that?
while (!in.fail()){
Because the read doesn't fail in the first iteration.
If you want to have the content of the loop be executed once, you can easily achieve that by moving it outside the loop.
Note that hard-coding the size of the array, and the accepting user input to access indices of the array without validation is a recipe for buffer overflow.

Segmentation fault while reading a large array from a file. C++/gcc

In the following code I'm trying to find the frequencies of the rows in fileA which have the same value on the second column. (each row has two column and both are integers.) Sample of fileA:
1 22
8 3
9 3
I have to write the output in fileB like this:
22 1
3 2
Because element 22 has been repeated once in second column(and 3 repeated 2 times.)
fileA is very large(30G). And there are 41,000,000 elements in it(in other words, fileB has 41,000,000) rows. This is the code that I wrote:
void function(){
unsigned long int size = 41000000;
int* inDeg = new int[size];
for(int i=0 ; i<size; i++)
{
inDeg[i] = 0;
}
ifstream input;
input.open("/home/fileA");
ofstream output;
output.open("/home/fileB");
int a,b;
while(!input.eof())
{
input>>a>>b;
inDeg[b]++; //<------getting error here.
}
input.close();
for(int i=0 ; i<size; i++)
{
output<<i<<"\t"<<inDeg[i]<<endl;
}
output.close();
delete[] inDeg;
}
I'm facing segmentation fault error on the second line of the while loop. On the 547387th iteration. I have already assigned 600M to the stack memory based on this. I'm using gcc 4.8.2 (on Mint17 x86_64).
Solved
I analysed fileA thoroughly. The reason of the problem as hyde mentioned wasn't with hardware. Segfault reason was wrong indexing. Changing the size to 61,500,000 solved my problem.
In the statement:
while(!input.eof())
{
input>>a>>b;
inDeg[b]++;
}
Is b the index of your array?
When you read in the values:
1 22
You are discarding the 1 and incrementing the value at slot 22 in your array.
You should check the range of b before incrementing the value at inDeg[b]:
while (input >> a >> b)
{
if ((b >= 0) && (b < size))
{
int c = inDeg[b];
++c;
inDeg[b] = c;
}
else
{
std::cerr << "Index out of range: " << b << "\n";
}
}
You are allocating a too huge array in to the heap. It´s a memory thing, your heap cant take that much space.
You should split your in and output in smaller parts, so at example create a for loop which goes every time 100k , deletes them and then does the next 100k.
in such cases try a exception handling, this is a example snippet how to manage exception checking for too huge arrays:
int ii;
double *ptr[5000000];
try
{
for( ii=0; ii < 5000000; ii++)
{
ptr[ii] = new double[5000000];
}
}
catch ( bad_alloc &memmoryAllocationException )
{
cout << "Error on loop number: " << ii << endl;
cout << "Memory allocation exception occurred: "
<< memmoryAllocationException.what()
<< endl;
}
catch(...)
}
cout << "Unrecognized exception" << endl;
{

Reading integer input from file into a dynamic array and printing it

I am attempting to write a program that reads in integers from an input file and outputs a dynamic array. This array would be the size of the input. For verification, I'd also like to print the array. The output will be passed to a function to create a sorted linked list.
I tried the following, but it did not work:
istringstream input(R"inp(
23 43 12 67
18 15 22
12 xxx 23 12 xx 34556 11 11 www
)inp");
int get, count = 0;
while (input >> get)
count++;
cout << "Number of integers: " << count << endl;
int *array = new int [count];
for (int i = 0; i < count; i++)
{
input >> array[i];
}
for (int i = 0; i < count; i++)
{
cout << *(array+i) << endl;
}
delete[] array;
Here's an online example of my code.
The problem is that the output shows some weird numbers, completely unrelated to the input:
Number of integers: 8
-1217944384
-1217944384
-1
538976266
540226080
824193844
Where did I go wrong?
As πάντα ῥεῖ pointed out, the solutions that I did provide are not totally safe, that's why I will provide a third example, using boost::spirit.
See the points fast fix and good solution, as well as πάντα ῥεῖ's answer to get it working without using boost.
my personal favourite solution: note that this example does require to have read the text file into a string.
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
template<typename Iterator>
bool
parse_numbers(Iterator first, Iterator last, std::vector<int>& v)
{
bool r =
boost::spirit::qi::parse(first, last,
// Begin grammar
(boost::spirit::qi::int_[boost::phoenix::push_back(
boost::phoenix::ref(v), _1)]
% *(boost::spirit::qi::char_("a-zA-Z")
| boost::spirit::ascii::space)));
if (first != last) // fail if we did not get a full match
return false;
return r;
}
const std::string s = "23 43 12 67 \n18 15 22\n12 xxx 23 12 xx 34556 11 11 www";
std::string::const_iterator start = s.begin(), stop = s.end();
std::vector<int> results;
parse_numbers(start, stop, results)));
for(int i : results)
std::cout << value << ' ';
the result would be, as expected:
23 43 12 67 18 15 22 12 23 12 34556 11 11
The above example is partially built on the example given in the boost::spirit documentation.
input >> get moves the current curser position, so after your while loop you have nothing left to read.
fast fix:
ifstream input;
input.open("file.txt");
int get, count = 0;
while (input >> get)
count++;
input.close();
input.open("file.txt");
int *array = new int [count];
for (int i = 0; i < count; i++)
{
input >> array[i];
}
for (int i = 0; i < count; i++)
{
cout << *(array+i) << endl;
}
input.close();
delete[] array;
To close and reopen the stream should work, but there are more efficient solutions out there...
good solution:
One could be to read and insert into a dynamically growing vector for example. See the documentation for further reference.
std::vector<int> dataArray;
while (input >> get)
{
dataArray.insert(dataArray.end(), get);
}
for(auto&& value : dataArray)
{
std::cout << value << std::endl;
}
That would have multiple advantages:
allocating the vector on the stack prevents you from being forced to call delete. An alternative would be a standard smart pointer.
the for each loop works even without counting the elements. If you need the number of elements you could just ask the vector about his size.
Your code has several misconceptions and flaws:
(1) After applying this loop to count your inputs
while (input >> get)
count++;
the input stream's state is left over the result of last extraction operation (input >> get) that has failed. Thus no further input can be read, without completely resetting the stream.
(2) The second loop you're showing
for (int i = 0; i < count; i++) {
input >> array[i];
}
uses the input stream in invalid state (the whole stream was already read to input.eof()), and thus reading from it results in 'weird values' (in other words: It's undefined behavior at this point).
I would write the following proven code to solve this
// Your literal input file formatting goes here
istringstream input(R"inp(
23 43 12 67
18 15 22
12 xxx 23 12 xx 34556 11 11 www
)inp");
int current;
vector<int> allIntInputs;
while (input >> current || !input.eof()) {
if(input.fail()) {
input.clear();
string crap;
input >> crap; // read anything up to the next
// whitespace delimiter (the default deleimiters)
continue; // with the next item
}
// Everything's fine we'll add another number
allIntInputs.push_back(current);
}
// Print all integer values extracted
cout << "Integer values read from input:" << endl;
for(vector<int>::iterator it = allIntInputs.begin();
it != allIntInputs.end();
++it) {
if(it != allIntInputs.begin()) {
cout << ' ';
}
cout << *it;
}
cout << endl;
Output
Integer values read from input:
23 43 12 67 18 15 22 12 23 12 34556 11 11

C++ file writing/reading

I'm trying to create an array, write array to the file and than display it. It seems to be working but i get just part of the output (first 3 elements) or i get values over boundaries.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int arr[20];
int i;
for (i = 0; i < 5; i++)
{
cout << "Enter the value to the array: " << endl;
cin >> arr[i];
}
ofstream fl("numbers.txt");
if (!fl)
{
cout << "file could not be open for writing ! " <<endl;
}
for (i = 0; i < arr[i]; i++)
{
fl<<arr[i]<<endl;
}
fl.close();
ifstream file("numbers.txt");
if(!file)
{
cout << "Error reading from file ! " << endl;
}
while (!file.eof())
{
std::string inp;
getline(file,inp);
cout << inp << endl;
}
file.close();
return 0;
}
The terminating condition in the for loop is incorrect:
for(i=0;i<arr[i];i++)
If the user enters the following 5 ints:
1 0 4 5 6
the for loop will terminate at the second int, the 0, as 1 < 0 (which is what i<arr[i] would equate to) is false. The code has the potential to access beyond the bounds of the array, for input:
10 11 12 13 14
the for loop will iterate beyond the first 5 elements and start processing unitialised values in the array arr as it has not been initialised:
int arr[20];
which could result in out of bounds access on the array if the elements in arr happen to always be greater than i.
A simple fix:
for(i=0;i<5;i++)
Other points:
always check the result of I/O operations to ensure variables contain valid values:
if (!(cin >> arr[i]))
{
// Failed to read an int.
break;
}
the for loop must store the number of ints read into the arr, so the remainder of the code only processes values provided by the user. An alternative to using an array, with a fixed size, and a variable to indicate the number of populated elements is to use a std::vector<int> that would contain only valid ints (and can be queried for its size() or iterated using iterators).
while (!file.eof()) is not correct as the end of file flag will set only once a read attempted to read beyond the end of the file. Check the result of I/O operations immediately:
while (std::getline(file, inp))
{
}
its like hmjd said
for(i=0;i<arr[i];i++)
looks wrong
it should look like this
int size;
size=sizeof(your array);
for(i=0;i<size;i++)
Try this:
//for(i=0;i<arr[i];i++)
for(i=0;i<5;i++)
[EDITED]
I would initialize the array with 0 like this: int arr[20] = {0}; In this case you can use for example:
while ((arr[i] != 0 || i < sizeof(arr))
i<array[i]
It is wrong beacuse it comapres with the content of the array ,it does not check the size of array .

Assign last number of a text file to a variable C++

I am doing a program that outputs a list of prime numbers with fstream.
I have this so far:
int export_list (int lim = 50)
{
int x;
last_in_txt = ????????????; // assigns last number on txt
ofstream file ("Primes.txt" , ios::app);
if (file.is_open()) // if it opens correctly
{
for (x = last_in_txt ; x < lim ; x++)
{
if (check_prime (x)) // returns 1 when x is prime, returns 0 when not
{
file<< x << " ";
}
}
cout << "Done!" << endl << pressenter;
cin.get();
}
else
{
cout << "Unable to open file" << endl << pressenter;
cin.get();
}
return(0);
}
So, as you can see, this should append a list of prime numbers to Primes.txt, starting with the prime 1234547.
Primes.txt looks like this:
2 3 5 7 11 13 17 19 23 29 31 37 (...) 1234543 1234547
My question is how do I assign 1234547 (which is the last number of the txt) to the variable last_in_txt?
Other (not so important) question:
Should I save the numbers the way I'm currently doing, or should I store each number in a separate line?
One simple way: keep reading and assign until the whole file is read.
For example,
int last_in_txt = 0;
{
ifstream infile("Prime.txt");
int k;
while(infile >> k) {
last_in_txt = k;
}
}
// Now last_in_txt is assigned properly, and Prime.txt is closed
This works well no matter the numbers in Prime.txt are separated by space characters (' ') or by newline characters ('\n').
My suggestion is that you write using binary format into the text file(using wb in C). In this case you will know how many bytes does the last number occupy and you will be able to use seekg and tellg to get it. If you use plain text format you will have to read char by char from the end and this is more error-prone and also slower.