I am newbie to programming and I am trying to pass an array into a function and add all the elements together and return the sum. The problem is that I am getting a garbage value for the sum. I have researched on how to pass arrays to functions and I do not know if I'm supposed to use a pointer to pass arrays. I am not good with pointers anyways.
Here is my code
#include <cmath>
#include <cstdlib>
using namespace std;
float mean(int);
int sum(int ARRZO[5]);
int total;
int main()
{
int ARRZ[5];
char *inname = "example.txt";
ifstream infile(inname);
if (!infile) {
cout << "There was a problem opening file " << inname << " for reading." << endl;
return 0;
}
cout << "Opened " << inname << " for reading." << endl;
for(int i=0; i<11; i++)
{
while (infile >> ARRZ[i])
{
cout << "Value from file is " << ARRZ[i] << endl;
}
}
total=sum(ARRZ);
cout<<"the sum of the elements in the array is"<<total<<endl;
system("PAUSE");
return 0;
}
int sum(int ARRZO[])
{
int sumz=0;
for (int i=0; i<5; i++)
{
sumz+=ARRZO[i];
cout<<ARRZO[i];
}
cout<<sumz<<endl;
return sumz;
}
You are actually reading all the values from the file in ARRZ[0] because of the inner loop. By the time you get to i=1, you are at the end of the file, and not reading anything.
Remove one loop, and increment i when you have read successfully a value.
I'm not sure what you think this pair of nested loops is supposed to do:
for(int i=0; i<11; i++)
{
while (infile >> ARRZ[i])
{
cout << "Value from file is " << ARRZ[i] << endl;
}
}
But (as #aliexisdm pointed out) the inner loop reads the entire content of the file. What he didn't (at least directly) point out is that you're reading every one of those values into the first element of your array. Then you're getting back to the outer loop, incrementing i, and trying to read the file again -- but since the stream's failbit has been set, all your subsequent attempts at reading are guaranteed to fail.
After that, you add up the 5 items in the array, but since you haven't read anything into 4 of them (and never initialized its contents) you end up with the last item you read from the file + 4 garbage values, giving still further garbage as the result (well, usually anyway -- you really have undefined behavior, so the program could crash and burn instead, but with most current computers, you'll just get some meaningless number).
I, however, would advise changing the program a bit more than just removing one loop and incrementing in the loop that's left. Instead, I'd remove all the (explicit) loops, and make some attempt at making real use of what the standard library provides.
You can read the numbers from the file in one fell swoop:
std::ifstream infile(inname);
std::vector<int> ARRZ ((std::istream_iterator<int>(infile)),
std::istream_iterator<int>());
Then you can sum them all with std::accumulate:
int sum = std::accumulate(ARRZ.begin(), ARRZ.end(), 0);
Finally, you can print out the result:
cout << "The sum of the elements in the array is: " << sum << "\n";
Since, however, you only read the values from the file to add them together, you don't really need to store them at all. You could just add them together and print out the result:
cout << "The sum of the elements in the file is: "
<< std::accumulate(std::istream_iterator<int>(infile),
std::istream_iterator<int>(), 0);
The whole job reduced to one step...
Related
I was studying the STL and decided to write some code to practice the writing and reading of files. The problem consists of creating a list of int (0, 1,...,9), save it in a binary file, and finally load it again.
There are 5 basic code blocks:
1. create list
2. present list
3. save list
4. load list
5. present list again
It seems simple and straightforward; however, the code seems to get in an infinite loop.
int main(){
list<int> numbers;
/////// Create list of 10 integers ///////
for(int i=0; i<10; i++){
numbers.push_back(i);
}
/////// Present List ///////
cout << "List created: [";
list<int>::iterator it;
for(it = numbers.begin(); it != numbers.end(); it++){
if(*it != 9){
cout << *it << ", ";
}
else{
cout << *it;
}
}
cout << "]" << endl;
/////// Save list ///////
string fileName = "test.bin";
ofstream outputFile;
outputFile.open(fileName, ios::binary);
if(outputFile.is_open()){
outputFile.write(reinterpret_cast<char *>(&numbers), sizeof(numbers));
outputFile.close();
cout << "List saved to file." << endl;
}
else{
cout << "Could not open file named " << fileName << endl;
}
/////// Load list ///////
list<int> anotherList;
ifstream inputFile;
inputFile.open(fileName, ios::binary);
if(inputFile.is_open()){
inputFile.read(reinterpret_cast<char *>(&anotherList), sizeof(anotherList));
inputFile.close();
cout << "List loaded from file." << endl;
}
else{
cout << "Could not open file named " << fileName << endl;
}
/////// Present List ///////
cout << "List loaded: [";
for(it = anotherList.begin(); it != anotherList.end(); it++){
if(*it != 9){
cout << *it << ", ";
}
else{
cout << *it;
}
}
cout << "]" << endl;
return 0;
}
The problem is in the "Load List" code block, since, if I comment it out, everything works fine.
Am I saving the object correctly? What am I doing wrong?
Thanks in advance.
The problem lies in the flawed logic of reinterpret_cast<char *>(&numbers). Why?
std::list manages its storage using pointers. It simply holds a pointer to a chain of elements consisting of some objects and a pointer to the next element. You cannot simply treat it like a sequence of bytes and expect it to maintain its functionality.
What you instead need to do is to loop over the elements and write them to the file one by one:
#include <fstream>
#include <iostream>
#include <list>
int main() {
std::fstream file{};
file.open("data.txt", std::ios::binary | std::ios::out);
std::list<int> ints{2, 4, 5, 6, 8, 1, 3, 5, 7, 9};
for (int i : ints) {
file.write(reinterpret_cast<char*>(&i), sizeof(i));
}
file.flush();
file.close();
file.open("data.txt", std::ios::binary | std::ios::in);
ints.clear();
std::cout << "Before reading the file, size of the list is: " << ints.size() << '\n';
for (int i; file.read(reinterpret_cast<char*>(&i), sizeof(i)); ints.push_back(i));
for (int i : ints) {
std::cout << i << ' ';
}
}
Clarification of the second for loop:
for (int i; file.read(reinterpret_cast<char*>(&i), sizeof(i)); ints.push_back(i));
We declare a variable i since we need a place where we read the data. This one should be quite clear. We do not need to initialize i, since the condition of the loop will take care of that (although it would probably be a good practice to do it anyway).
The condition part: file.read(reinterpret_cast<char*>(&i), sizeof(i)). This may seem tricky at first, but it really isn't! First of all, we have a method call. We call std::basic_istream::read, specifying the two arguments - first, the memory address where to read the variable, and second, the number of bytes we want to read. The trick is that the read method not only reads and saves the data - it also returns the stream, so essentially after the data processing, we are left with the condition file. But it's not a bool, is it? Correct, it's not a bool (neither an int), but stream objects can be implicitly converted to bool, which is exactly what happens here! The rules are as follows: if the stream is in a correct state, the conversion returns true. It returns false otherwise. An incorrect state may be cauased, for example, by failure to read, which happens, for example, when you already have read the whole file. Essentially, this part both reads from the file and checks whether the reading process executed successfully. It's both the reading logic and the condition!
The third part: ints.push_back(i). Notice that this part only executes if the condition (reading from the file) executed successfully. It simply adds the read int (i) to the ints container.
All in all, you can read the for loop in the following way:
create a variable i, which will store, one by one, the variables from the file
as long as reading from the file is successful...
...add the read value to the container
outputFile.write(reinterpret_cast<char *>(&numbers), sizeof(numbers));
What you actually print is the binary representation of the list object itself. Unfortunately, it does not contain the data of the list directly, but instead looks similar to something like this:
template <typename T>
class list
{
struct node
{
node* next;
node* previous;
T data;
};
node* m_head;
node* m_tail;
size_t m_size;
public:
// ...
};
No direct link to the data. Even worse: With std::list, the data can get shattered all over your memory (in contrast to std::vector which assures contiguous data).
So you only can iterate over your list again (either with the iterator variant you chose already before or, more convenient, with a range based for loop):
for(auto n : numbers)
{
outputFile.write(reinterpret_cast<char*>(&n), sizeof(n));
}
Reading is different; you don't know the size in advance, do you? Well, there are ways to retrieve it (seekg, tellg), but that's more of interest if you want to read all the data into contiguous memory at once (you could reserve sufficient of in a std::vector), but that's another issue.
For the list approach:
int n;
while(inputFile.read(reinterpret_cast<char*>(&n), sizeof(n)))
{
anotherList.push_back(n);
}
I have finished writing a program that included reversing, expanding and shifting arrays using the pointer requirement asked by the professor. Everything compiles but the answer from the expand function does not return what I wish: adding 0s after the old user input array which asks for the size of the array and the numbers you wish to put into the array. I think my problem may lie from the fact that I include a pointer on something that might not have a reference in the program. Below is my code:
// *numPtr refers to my old user input array and int tamaño is the size of the array
void expandArray(int *numPtr, int tamaño) {
int *nuevoArray = new int[tamaño *2];
for (int i = 0; i<tamaño; i++) {
nuevoArray[i] = numPtr[i];
}
for (int i = tamaño; i < (tamaño*2); i++) {
nuevoArray[i] = 0;
}
std::cout << nuevoArray << " ";
}
As I said, my theory of the code not compiling the way I wish is because I use the *nuevoArray and it has no reference in my main code, but then again, I am just a beginner with C++. I was thinking of just doing a vector, but I think I would not follow the pointer requirements placed by the professor.
If you want to print the contents of nuevoarray, just use a for loop like this:
for (int i = 0; i < (tamaño*2); i++) {
std::cout << nuevoArray[i] << " ";
}
std::cout << "\n";
Also, since you are using new[] to create the array, you should not forget to delete[] it!
you can print your array by using
for (int i = 0 ; i < tamano * 2 ; ++i) {
std::cout << nuevoArray[i] << " ";
}
std::cout << std::endl;
or in c++11
for (auto i : nuevoArray) {
std::cout << i << " ";
}
std::cout << std::endl;
PS: The std::endl will return to the start of the new line and flush the cout buffer.
Your code does appear to be allocating a larger array and correctly copying data from numPtr into the new array and also correctly filling the remainder of the new array with zeros.
You don't explicitly say what you expect this function to output, but I'm guessing you expect it to print out the contents of the new array, and that you believe there's a problem because instead of that, you're seeing it print something like "0x7fb46be05d10".
You're not correctly printing the array out. Instead you're printing the memory address of the first element out. If you want to see the contents, then you need to loop over the elements of the array and print each one out individually.
Here's a function showing one way of doing that:
#include <algorithm>
#include <iterator>
void printArray(int *arr, int n) {
std::copy(arr, arr + n, std::ostream_iterator<int>(std::cout, " "));
}
Now you can replace the line std::cout << nuevoArray << " "; in your existing code with printArray(nuevoArray, tamaño*2);
(Also it sounds like whoever is teaching you C++ should take a look at this presentation from the recent C++ conference, CppCon 2015: Stop Teaching C)
I am basically trying to store everything after a certain index in the array.
For example, I want to store a name which is declared as char name[10]. If the user inputs in say 15 characters, it will ignore the first five characters and store the rest in the char array, however, my program crashes.
This is my code
char name[10];
cout<< "Starting position:" << endl;
cin >> startPos;
for(int i= startPos; i< startPos+10; i++)
{
cout << i << endl; // THIS WORKS
cout << i-startPos << endl; // THIS WORKS
name[i-startPos] = name[i]; // THIS CRASHES
}
For example, if my name was McStevesonse, I want the program to just store everything from the 3rd position, so the end result is Stevesonse
I would really appreciate it if someone could help me fix this crash.
Thanks
Suppose i is equal to 3. In the last iteration of the loop, i is now equal to 12, so substituting 12 in for i, your last line reads
name[12-startPos] = name[12];
name[12] is out of bounds of the array. Based on what you have shown so far, there is nothing but garbage stored in name anyway before you start doing this assignment, so all you're doing is reorganizing garbage in the array.
Please in future: post full compilable example.
A simple answer is that your array maybe is out of bound, since you don't provide full example its hard to know exactly.
Here is a working example:
#include <iostream>
using namespace std;
int main() {
int new_length, startPos;
int length = 15;
char name[15]= "McStevesonse";
cout<< "Starting position:" << endl;
cin >> startPos;
if(new_length <1){ // you need to check for negative or zero value!!!
cout << "max starting point is " <<length-1 << endl;
return -1;
}
new_length=length-startPos;
char newname[new_length];
for(int i= 0; i<new_length; i++){
newname[i] = name[i+startPos]; // THIS CRASHES
}
cout << "old name: " << name << " new name: " << newname << endl;
return 0 ;
}
To put it simply, change this:
for(int i= startPos; i< startPos+10; i++)
To this:
for(int i= startPos; i<10; i++)
You should be fine with that.
Explanation:
At some point, when you use the your old loop, this name[i-startPos] = name[i] would eventually reach an array index out of bounds and causes the crash.
Don't forget to clean up/hide the garbage:
Doing so, would cause the output to produce some kind of garbage outputs. If you got a character array of 'ABCDEFGHIJ', and have chosen 3 as the starting position, the array would be arranged to 'DEFGHIJHIJ'. In your output, you should atleast hide the excess characters, or remove by placing \0's
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <fstream>
using namespace std;
void make_array(ifstream &num, int (&array)[50]);
int main(){
ifstream file; // variable controlling the file
char filename[100]; /// to handle calling the file name;
int array[50];
cout << "Please enter the name of the file you wish to process:";
cin >> filename;
cout << "\n";
file.open(filename);
if(file.fail()){
cout << "The file failed to open.\n";
exit(1);
}
else{
cout << "File Opened Successfully.\n";
}
make_array(file, array);
file.close();
return(0);
}
void make_array(ifstream &num, int (&array)[50]){
int i = 0; // counter variable
while(!num.eof() && i < 50){
num >> array[i];
i = i + 1;
}
for(i; i>=0; i--){
cout << array[i] << "\n";
}
}
Alright, so this it my code so far. When I output the contents of the array, I get two really large negative numbers before the expected output. For example, if the file had 1 2 3 4 in it, my program is outputting -6438230 -293948 1 2 3 4.
Can somebody please tell me why I am getting these ridiculous values?
Your code outputs the array backwards, and also it increments i twice after it has finished reading all the values. This is why you see two garbage values at the start. I suspect you are misreporting your output and you actually saw -6438230 -293948 4 3 2 1.
You end up with the extra increments because your use of eof() is wrong. This is an amazingly common error for some reason. See here for further info. Write your loop like this instead:
while ( i < 50 && num >> array[i] )
++i;
Now i holds the number of valid items in the list. Assuming you do actually want to output them backwards:
while ( i-- > 0 )
cout << array[i] << "\n";
To output them forwards you'll need two variables (one to store the total number of items in the array, and one to do the iteration)
The check !num.eof() only tells you that the last thing you read was not eof. So, if your file was 1 2 3 4, the check will only kick in after the 5th num>>array[i] call. However, for that i, array[i] will be populated with a meaningless value. The only correct way to deal with eofs is to check for validity on every call to operator>>. In other words, the right condition is simply num>>array[i]. This works by exploiting this conversion to bool since C++11 and to void* pre-C++11.
----------------- EDIT -----------------------
Based on juanchopanza's comment : I edit the title
Based on jrok's comment : I'm using ofstream to write, and ifstream to read.
I'm writing 2 programs, first program do the following tasks :
Has a vector of integers
convert it into array of string
write it in a file
The code of the first program :
vector<int> v = {10, 200, 3000, 40000};
int i;
stringstream sw;
string stringword;
cout << "Original vector = ";
for (i=0;i<v.size();i++)
{
cout << v.at(i) << " " ;
}
cout << endl;
for (i=0;i<v.size();i++)
{
sw << v[i];
}
stringword = sw.str();
cout << "Vector in array of string : "<< stringword << endl;
ofstream myfile;
myfile.open ("writtentext");
myfile << stringword;
myfile.close();
The output of the first program :
Original vector : 10 200 3000 40000
Vector in string : 10200300040000
Writing to File .....
second program will do the following tasks :
read the file
convert the array of string back into original vector
----------------- EDIT -----------------------
Now the writing and reading is fine, thanks to Shark and Jrok,I am using a comma as a separator. The output of first program :
Vector in string : 10,200,3000,40000,
Then I wrote the rest of 2nd program :
string stringword;
ifstream myfile;
myfile.open ("writtentext");
getline (myfile,stringword);
cout << "Read From File = " << stringword << endl;
cout << "Convert back to vector = " ;
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
But it can only convert and push back the first element, the rest is erased. Here is the output :
Read From File = 10,200,3000,40000,
Convert back to vector = 10
What did I do wrong? Thanks
The easiest thing would be to insert a space character as a separator when you're writing, as that's the default separator for operator>>
sw << v[i] << ' ';
Now you can read back into an int variable directly, formatted stream input will do the conversion for you automatically. Use vector's push_back method to add values to it as you go.
Yes, this question is over a year old, and probably completely irrelevant to the original asker, but Google led me here so it might lead others here too.
When posting, please post a complete minimal working example, having to add #include and main and stuff is time better spent helping. It's also important because of your very problem.
Why your second code isn't working is all in this block
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
istringstream (stringword) >> value interprets the data up to the comma as an integer, the first value, which is then stored.
stringword.find(',') gets you the 0-indexed position of the comma. A return value of 0 means that the character is the first character in the string, it does not tell you whether there is a comma in the string. In that case, the return value would be string::npos.
stringword.erase deletes that many characters from the start of the string. In this case, it deletes 10, making stringword ,200,3000,40000. This means that in the next iteration stringword.find(',') returns 0.
if (stringword.find(',')) does not behave as wished. if(0) casts the integer to a bool, where 0 is false and everything else is true. Therefore, it never enters the if-block again, as the next iterations will keep checking against this unchanged string.
And besides all that there's this:
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
it uses i. That was declared in a for loop, in a different scope.
The code you gave simply doesn't compile, even with the added main and includes. Heck, v isn't even defined in the second program.
It is however not enough, as the for condition stringword.length() is recalculated every loop. In this specific instance it works, because your integers get an extra digit each time, but let's say your input file is 1,2,3,4,:
The loop executes normally three times
The fourth time, stringword is 4, stringword.length() returns 2, but i is already valued 3, so i<stringword.length() is invalid, and the loop exits.
If you want to use the string's length as a condition, but edit the string during processing, store the value before editing. Even if you don't edit the string, this means less calls to length().
If you save length beforehand, in this new scenario that would be 8. However, after 4 loops string is already empty, and it executes the for loop some more times with no effect.
Instead, as we are editing the string to become empty, check for that.
All this together makes for radically different code altogether to make this work:
while (!stringword.empty())
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(',')+1);
}
for (int i = 0; i < v.size(); i++)
{
cout << v.at(i) << " " ;
}
A different way to solve this would have been to not try to find from the start, but from index i onwards, leaving a string of commas. But why stick to messy stuff if you can just do this.
And that's about it.