This question already has answers here:
Returning an array using C
(8 answers)
Closed 6 months ago.
I wrote a simple c++ program where i am getting a simple float Array from a function. Then I call a function where the generated Array is a parameter of. I print the first value of the Array through the function. It works! BUT when i am declaring another array in the function before i print the value from the first array, the printed value is not the expected one. MAGIC!
CODE THAT DOESN'T WORK:
#include <iostream>;
float* getArray() {
float Array[] = { 4 };
return Array;
}
void compute(float* Array) {
bool newArray[1];
float content = Array[0]; //breakpoint: content will be -107374176.
std::cout << content;
}
int main() {
float* Array = getArray();
compute(Array);
}
OUTPUT: -1.07374e+08
When removing the line "bool newArray[1];" (line 10) the code starts to work.
OUTPUT: 4
Test it your self! Can someone explain me why this happens?
Your main function has a bug. It passes a pointer to Array to compute, which dereferences it. But Array is out of scope at this point since its scope ends when getArray ends. So you are trying to access an object that no longer exists. That is undefined behavior and produces completely unpredictable results.
Arguably, getArray also has a bug since it always returns a pointer to an object that no longer exists. So there is no way to use it. Whether or not that's a bug depends on what the caller is supposed to be able to do with the returned value which cannot be determined due to the lack of comments.
I have the following code
#include<iostream>
#include<cmath>
#include<string>
using namespace std;
#include<fstream>
#include<iomanip>
#include<cstdio>
int main() {
//Here the code that creates the file benchmarks_cleaned.dat
int ncol = 16; //number of data per row
double datos[ncol];
char aux2;
double aux3;
int icol;
ifstream benchmarks2;
ofstream out_benchmarks2;
benchmarks2.open("benchmarks_cleaned.dat");
out_benchmarks2.open("benchmarks_final.dat");
if (benchmarks2.is_open()) {//second if
for (icol = 0; icol < ncol; icol++) {
benchmarks2>>datos[icol];
out_benchmarks2<<datos[icol]<<" ";
};
out_benchmarks2<<"\n";
benchmarks2.get(aux2);
while (aux2 != 'X') {
benchmarks2.unget();
benchmarks2>>aux3;
if (aux3 != datos[0]) {
benchmarks2.get(aux2);
} else {
out_benchmarks2<<datos[0]<<" ";
for (icol = 1; icol < ncol; icol++) {
benchmarks2>>datos[icol];
out_benchmarks2<<datos[icol]<<" ";
};
out_benchmarks2<<"\n";
benchmarks2.get(aux2);
};
};
} else {
cout<<"ERROR: unable to open the file"<<endl;
};//end of second if
out_benchmarks2<<"X";
out_benchmarks2.close();
out_benchmarks2.close();
benchmarks2.close();
return 0;
}; //end of main
The data file dummyValues.dat is:
{5.12, 0.1, 0.25} {{0.10, 4, 3, 2, 1, 1.44, 10.2}} {11.1, 12.2, 13.3, 14.4, 15.5, 16.6} 1000 2000 {{{{ 5.12, 0.1} {17.7, 18.08, 19.0, 020.0} {1.115, 2.0, 3.01, 4.65, 5, 6, 7, 8, 9, 10.0}, 3000 4000 { 5.12, 0.1} {117.7, 118.08, 119.0, 0120.0} {11.115, 21.0, 31.01, 41.65, 51, 61, 71, 81, 91, 110.0} 5000 6000 X
In benchmarks_cleaned.dat you reduce this file to just numbers separated by a blank space. The idea now is to write benchmarks_final.dat where in each row you have only 16 values and they must start by the same number 5.12 = datos[0] that you can check is repeated along dummyValues.dat
Nonetheless, while benchmarks_cleaned.dat is indeed created as desired (see below), benchmarks_final.dat does never start. I've checked that the programme runs but it does not write anything in benchmarks_final.dat. Where is the mistake?
benchmarks_cleaned.dat is:
5.12 0.1 0.25 0.1 4 3 2 1 1.44 10.2 11.1 12.2 13.3 14.4 15.5 16.6 1000 2000 5.12 0.1 17.7 18.08 19 20 1.115 2 3.01 4.65 5 6 7 8 9 10 3000 4000 5.12 0.1 117.7 118.08 119 120 11.115 21 31.01 41.65 51 61 71 81 91 110 5000 6000 X
Your calls to get(...) are catching blank spaces and missing the 'X'.
There's no need for get. Get rid of aux2 and change the while loop to:
while(benchmarks2 >> aux3)
So, the answer is given. It is good, correct. It is upvoted and accepted. Very good.
Just as an additional information, I will show a C++ solution, using more modern language elements. This solution skips the intermediate file (Can be generated by an one-liner) and also has no need to use the 'X' (Could also be added very simply).
With using the STL, we can come up with a solution, from the original source file to the final destination file in net 5 lines of code.
Please see:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>
#include <iterator>
#include <algorithm>
std::regex reFloat{ R"([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)" };
using SVector = std::vector<std::string>;
using SVectorIter = SVector::iterator;
int main() {
// Open source file and check, if it coud be opened
if (std::ifstream sourceFileStream{ "r:\\dummyValues.dat" }; sourceFileStream) {
// Open destination file and check, if it could be opened
if (std::ofstream finalFileStream("r:\\benchmarks_final.dat"); finalFileStream) {
// Algorithm start ----------------------------------------------------------
// Define a string variable and initialize it with the contents of the file
std::string completeFile(std::istreambuf_iterator<char>(sourceFileStream), {});
// Define vector and initialize it with all float values from the file
SVector values(std::sregex_token_iterator(completeFile.begin(), completeFile.end(), reFloat), {});
// Iterate over the vector and find the next value equal to first-value
for (SVectorIter svi{ values.begin() }; (svi = std::find(svi, values.end(), values[0])) != values.end(); ++svi) {
// Copy 16 value to the final file
std::copy_n(svi, std::min(16, std::distance(svi, values.end())), std::ostream_iterator<std::string>(finalFileStream, " "));
finalFileStream << '\n';
}
// Algorithm end ----------------------------------------------------------
}
else {
std::cerr << "\n*** Error: Could not open final file\n";
}
}
else {
std::cerr << "\n*** Error: Could not open source file\n";
}
}
I guess not, but if you should have interest in understanding that, then I will explain to you. Please ask, I am happy to help.
EDIT You are interested in further explanations. That is OK, but I can of course not give a whole tutorial here.
Then let us start with some important feature that we are using here. The so called constructor. This you should know already. It is a special function of a class and basically used to "initialize" the data of a class. If you have a class like
struct MyClass {
int a;
// Constructor. Very simplified
MyClass(int value) { a = value; }
};
And if you want to define a variable of this type (create an instance of this type), the you can write:
MyClass test(3);
This will call the constructor and assign 3 to the class member a. You should basically know this already. If you look for classes in the C++ Reference, then you will always find a constructor for the defined classes.
Ok, then let's start now. First, we want to open a file for input. For this, we will use the STL class std::ifstream. And we will use one of it's constructors. Please look at the reference. The constructor 2 takes a filename as a const char* and opens the file. It implicitely calls open (see description in the link). The destructor, which will be called automatically, when the variable falls out of scope (After the next matching }. The destructor will automatically close the file for you. That is very good, and avoids mistakes.
So, you can write:
// Some previous code here
// . . .
{
// Some previous code here
// . . .
// Open the file
std::ifstream sourceFileStream{ "r:\\dummyValues.dat" };
// more code
// . . .
} // Now the scope is closed. The Variable "sourceFileStream" will fall out of scope
// and the file will be close automatically.
Cool.
Now a very important recommendation. You should always check, if an IO operation was successful. How to do that. For that, you should know, that std::stream have a kind of error state. And you can and should check this. You can read about those "states" here. If, you open a file, and it does not work. the the failbit will be set. This you can read here. So, you can check the failbit with the statement:
if (sourceFileStream.rdstate() == std::ios_base::failbit)
But that is somehow complicated. So, the designers of the IO-stream classes have defined a bool operator for the class. And, as you can read in the description, it checks whether the stream has no errors. An if statement needs a boolean condition. And if you write
if (sourceFileStream) {
then the boolean operator of this variable is returned and shows, if there is an error or not. That is very helpful.
Next, in C++17, a new syntax for the if statement has been introduced. Now you can define and initialize a variable within the if statement. For example
if (int inner = 0; x < y) { . . . }
Still the condition is x < y. Additionally, the variable "inner" will be defined and the advantage is that this variable is only visible in the inner scope of the if statement. After the closing bracket } of the if block, the variable will be gone.
And now, we can put all peices together:
if (std::ifstream sourceFileStream{ "r:\\dummyValues.dat" }; sourceFileStream) {
The first part of this if statement defines a variable "sourceFileStream" and calls its constructor with the filename. And so, it opens the file. The second part of the if statement is the condition, and calls the bool operator of the "sourceFileStream", to check, if the file could be opened. And the good thing is, the the variable "sourceFileStream", is only vidible within the if block. There is no need to have it available outside of this block, because, if the file could not be opened, then what would you do with it. And, additionally. After the if block is finished with "}", then the file will be automatically closed, because the variable falls out of scope, which will call the destructor.
Wow, that was a big explanation for one line of code.
Next line:
std::string completeFile(std::istreambuf_iterator<char>(sourceFileStream), {});
Uh, oh. What is that?
Obviously, we define a variable with the name "completeFile" with the data type std::string. Ok, that is still understandable. And then we have a (...), so calling the std::strings constructor. Please read here about the constructor number 6. It says:
Constructs the string with the contents of the range [first, last).
So, it takes a iterator to the first item of the range and an iterator to after the last item of the range. And then, it copies all characters in this range to the variable "completeFile". So it will fill out std::string with characters given by the 2 iterators.
So, nect part: std::istreambuf_iterator<char>(sourceFileStream). This is the begin iterator of the range. Please read here, that
std::istreambuf_iterator is a single-pass input iterator that reads successive characters from the std::basic_streambuf object for which it was constructed.
So, this thing reads successive characters from our "sourceFileStream". It will read character aftr character from the source file and copies them in our string variable. It does this until the end iterator, so until {}. Hm, whats that? This is the empty braced default initializer and it will simply call the default constructor. And if you look into the description of the std::istreambuf_iterators constructor number 1, then you see that it will be the "end-of-stream iterator". And, with that, all characters from thesource file, from the firts character to the last character, will be read and copied into our std::string variable "completeFile".
Cool, right? Defining a avriable and reading the complete source file at the same time.
Next line:
std::vector<std::string> values(std::sregex_token_iterator(completeFile.begin(), completeFile.end(), reFloat), {});
This is maybe too complicated for here and I can therefore only explain the basics. So, first, we will define a varaible with the name "values" of the type std::vector`````ofstd::strings. So, we want to store manystd::stringsin astd::vector````. That is understandable. And guess what, we will initialize this variable by using its constructor. And we will use again the range constructor, here constructor number 5. And this
Constructs the container with the contents of the range [first, last).
So basically the same as with the std::string above. It copies all strings, pointed to by the iterators, from first to last, into our vector. The begin iterator is the std::sregex_token_iterator. I cannot explain the regex theory here, but simply said, it will iterate over a pattern of similar items, defined by a regex in a "meta-language" and return them, so that they can be copyied into our vector.
And the pattern is that of a float value. If you look at a float value, then you can detect a pattern. It consists of optional +- signs, then some digits, maybe a period and more digits. That is always the same. And this pattern, we describe with the regex [-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?. You can copy and paste that into here and play with it. Then you may get a first understanding.
Back to the iterator. So, it will only return strings, that match with the patterns. So, it will only return float-value-strings. It will not return any other characters. Just those, that you need.
And similar as above, it starts with the first pattern in the given string and stops at {}. Same as above, the default constructor no 1 "Constructs the end-of-sequence iterator."
If you are interested in more, please comment, and I will explain the rest
This question already has answers here:
when do we need to pass the size of array as a parameter
(8 answers)
Closed 6 years ago.
I'm currently working on a project where I want to convert the entries of a CSV file into a vector of Objects. Therefore I have written a function, which converts an array of structs in a vector. The problem is that right now my function only works if the user enters the right size of the array as an additional parameter but if he enters a higher number an exception is thrown because the function is trying to read from an array entry that doesn't exist. Now I want to know if there is anyway that I can determine the size of the array of structs in my function. I have already tried sizeof(array)/sizeof(array[0]) but that doesn't work.
Here is the function I'm talking about:
BANKMANAGEMENT_API int initAccounts(ACCOUNT accArray_[], const int numOfAcc_)
{
BankmanagementClass *myBankmanagement = BankmanagementClass::createBankmanagementClass();
for (int i = 0; i < numOfAcc_; i++)
{
ACCOUNT acc = accArray_[i];
Account* newaccount = Account::accountStruct2Obj(&acc);
myBankmanagement->setNextAccountId(myBankmanagement->determineNextId(newaccount->getAccountId(), myBankmanagement->getNextAccountId()));
myBankmanagement->addAccount(newaccount);
}
LogInfo("Account Vector was initialized with data from Csv File.");
return 0;
}
I want to get rid of the numOfAcc_ parameter so that the user can't enter the wrong size.
It's for a dll with C interface.
There is no way to determinate the size of the array. If you have under control how accArray is filled you could use an end marker and check this condition in the for loop.
This question already has answers here:
returning a local variable from function in C [duplicate]
(4 answers)
Closed 8 years ago.
I guess its a storage/definition difference but still I cant find a straight explanation of the behaviour. I have a function that returns a locally defined char* in two ways:
//Try 1:
char* printSomething()
{
char arr[100];
sprintf(arr, "The data %u", 100);
return arr;
}
//Try 2:
char* printSomething()
{
return "The data 100";
}
When I print the result of the first function It displays nothing (C) or garbage (C++) while on the second it prints the correct data.
I know I should store the data on the heap in cases like this or define static variable but still, how come the first doesnt work while the second does? and also, can I count on the second way to always work?
The first is just undefined behavior because arr is released when the function ends, so you're left with a dangling pointer.
The second works because "The data 100" is a string literal with static storage duration, which means it persists throught the lifetime of the program.
The implicit conversion to char* is deprecated though, and changing the contents will result in undefined behavior. I suggest you return const char* or std::string.
In both cases you returning char*
The first you return a pointer to a local array variable, located on the stack, which no longer exists after you exit the function. and may be rewritten.
In the second you returning pointer to a const string, located on the code segment, and it exist as long as the program is running.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
This program works but prints garbage values at the beginning (ch=2) and prints the same output twice.
I am using this for my project.It contains more data and there i used a single object instead of array of objects.It didnt work.Each object of array stores a set of data.
#include<iostream>
#include<fstream>
using namespace std;
class rw //a class containing some data
{
public:
int n;
char a;
};
int main()
{
int i;
rw r[2]; //an array of objects
int ch;
fstream f1;
f1.open("file1.txt",ios::in|ios::out|ios::ate);
cout<<"1-read,2-write";
cin>>ch;
f1.seekp(0,ios::beg);
if(ch==1)//for saving
{
r[0].n=1;
r[0].a='a';
f1.write((char*) &r[0],sizeof(r[0]));
r[1].n=2;
r[1].a='b';
f1.write((char*)&r[1],sizeof(r[1]));
}
if(ch==2)//for reading
{
f1.seekg(0,ios::beg);
while(!f1.eof())
{
i=0;
cout<<r[i].n<<r[i].a;
cout<<"\n";
f1.read((char*)&r[i],sizeof(r[i]));
i++;
}
}
system("pause");
return 0;
}
Change following code
cout<<r[i].n<<r[i].a;
cout<<"\n";
f1.read((char*)&r[i],sizeof(r[i]));
to
f1.read((char*)&r[i],sizeof(r[i])); // Moved before printing
cout<<r[i].n<<r[i].a;
cout<<"\n";
You are outputting data then reading from the file, instead you should read and then print. Printing before reading is the reason for getting garbage in first run of loop. I think you moved the reading below to avoid double printing of last record. Continue reading to understand how to avoid double reading.
You should avoid using while (!f1.eof()), as it will print last data twice.
Better use while(f1.read((char*)&r[i],sizeof(r[i])));
Unrolling the eof version of loop for 2 inputs
while(!eof) // true
read first data
print first data
while(!eof) // true
read second data // read all, but was succesful and eof not set
print second data
while(!eof) // true
Try to read // Could not read, eof set
print data // Reprinting second data
while(!eof) // false
Don't use while (!f1.eof()), it will not work as you expect it to, because the eofbit flag isn't set until after you try to read from beyond the file. Instead do e.g. while (f1.read(...)).
Also be careful with a loop like this without bounds checking. If the file is not correct you might write out of bounds of the array r.