Cutting and reorganizing numbers in a file with C++ - c++

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

Related

Returning an Array of Structs (Partially working) C++

We are trying to return an array of structures to print the contents in the main. When debugging the code, we get to the line right before the return statement and it shows that it is holding the right contents which is an int and then a string (playerID and name). As soon as the return statement executes the array is returned to the main but only the playerID is held in the array. All of the values for name have been lost. Can someone explain why this would happen and a possible solution? If further clarification is needed please let me know.
#include<iostream>
#include<fstream>
#include<cstring>
#include<string>
#include<math.h>
using namespace std;
struct Player
{
int playerID;
string name;
};
Player *fillPlayers();
int main()
{
Player *myPlayerPointer;
myPlayerPointer = fillPlayers();
return 0;
}
Player * fillPlayers() {
ifstream file1;
Player * fullPlayerPointer = new Player[244];
Player ourPlayers[244];
file1.open("Players.txt");
if (file1.fail()) {
cerr << "file1 did not open";
}
if (file1.is_open()){
while (!file1.eof()){
string size;
getline(file1, size);
for(int i = 0; i < 244; i++){
file1 >> ourPlayers[i].playerID;
file1 >> ourPlayers[i].name;
}
}
file1.close();
}
fullPlayerPointer = &ourPlayers[0];
return fullPlayerPointer;
}
This code looks a lot like C code. In C++ we have fancy RAII containers like std::vector and std::array that will do exactly what you want.
As for the issue, you are not returning an array, instead you are returning a pointer to an int. You should check out What is array decaying?.
http://en.cppreference.com/w/cpp/container/vector
http://en.cppreference.com/w/cpp/container/array (C++ >= 11)
The generally correct answer is use a std::vector as it assists in managing ownership and the lifetime of storage as well as tracking the capacity and resizing itself as needed. But let's take a walk through fillPlayers to explain what is going wrong.
Player * fillPlayers()
{
ifstream file1;
Player * fullPlayerPointer = new Player[244];
Dynamically allocated 244 Players. Dynamic storage has manually controlled lifetime and will remain valid until such time as it is freed. Unfortunately this allocated storage is never used and not put away correctly later with delete[] This allocation will be "leaked". As dire as this sounds, this is the "right" way to allocate the storage, but as we will see, the function uses it incorrectly.
Player ourPlayers[244];
Statically allocated 244 Players as a temporary variable. This variable will only exist inside the innermost set of surrounding curly braces {}. Afterward it will be rendered invalid. This means that references to ourPlayers should not be returned from this function as ourPlayers will be rendered invalid at the return from the function and before the caller can make use of it.
file1.open("Players.txt");
if (file1.fail())
{
cerr << "file1 did not open";
}
Always test before using, so the above is almost right. It is rendered redundant by the next line performing a nearly identical test. This could be a good place to put an else, but the code is more easily read with if (file1.is_open()) followed by an else to print the error message if it is not open.
Why do I say this? Because the programmer's intent with is_open is much easier to discern than with the broader term fail.
if (file1.is_open())
{
while (!file1.eof())
Read Why is iostream::eof inside a loop condition considered wrong? for details on why this is almost always the wrong solution to looping through a file.
{
string size;
getline(file1, size);
Always test a read to ensure it succeeded. In addition, the file size was read and then not converted into an integer to use in the loop that follows.
for (int i = 0; i < 244; i++)
Regardless of how many entries there are in this file 244 will always be read. If the file does not have at least 244 entries, the read will fail and as the reads are not being checked for success, garbage will be stored in the array.
Also note that there is a loop iterating through 244 entries in the file that is surrounded by a loop that will attempt to read again until the EOF flag is set. Most likely you only want one such loop.
{
file1 >> ourPlayers[i].playerID;
file1 >> ourPlayers[i].name;
}
}
file1.close();
}
fullPlayerPointer = &ourPlayers[0];
The pointer to the dynamic allocation made earlier is overwritten by a pointer to the temporary allocation ourPlayers. A reference to long-term storage has been replaced by a reference to storage that is about to go out of scope and become invalid.
It is possible that OP intended this to copy the data in the short term storage to the long term storage, but unfortunately that's not what the compiler was told to do, and it's not really worth doing. It would be much more useful to directly read the file into the long term storage.
return fullPlayerPointer;
Returns from the function and gives an invalid array to the caller.
}
Lot to fix in there.
Here's a very simple approach that fixes all of the above problems but exposes a few more:
Player * fillPlayers()
{
ifstream file1("Players.txt");
Player * players = nullptr;
if (file1.is_open())
{
int size;
if (file1 >> size)
{
players = new Player[size];
int index = 0;
while (file1 >> players[index].playerID >> players[index].name
&& index < size)
{
}
// extra brains needed here to handle premature read failure.
}
file1.close();
}
else
{
cerr << "file1 did not open";
}
return players; // only a pointer to the array was returned. How big the
// array is and how many items are actually in it is lost
}
This is where std::vector really becomes awesome. It knows how big it is and how full it is. An array doesn't.
Now, assuming std::vector is not allowed, and Paul McKenzie has already covered what to do if it isn't, the smart thing to do is make a very simple wrapper around the array to get some modicum of the safety and ease of use vector provides.
class stupidvector
{
Player *players;
size_t capacity; // a typical vector implementation uses a pointer for
// this to make iteration easier
size_t size; // vector uses pointer here, too.
public:
stupidvector();
stupidvector(size_t size);
// correctly copy a stupid vector Rule of Three. In this case, don't
// allow it to be copied.
stupidvector(const stupidvector& src)=delete;
// correctly move a stupid vector Rule of Five
stupidvector(stupidvector && src);
// release storage
~stupidvector();
// add an item to the end
void push(const Player & player);
// how big is it?
size_t getcapacity();
// how full is it?
size_t getsize();
// make it act like an array
Player & operator[](size_t index);
// correctly assign. Rule of Three. again we don't want to copy these,
// but if we did, look at Copy and Swap Idiom for a neat solution
stupidvector& operator=(const stupidvector& src) = delete;
// correctly move
stupidvector& operator=(stupidvector && src);
};
Pay special attention to the Rules of Three and Five

Array Function. Would appreciate a little clarification

I have a question regarding a school lab assignment and I was hoping someone could clarify this a little for me. I'm not looking for an answer, just an approach. I've been unable to fully understand the books explanations.
Question: In a program, write a function that accepts three arguments: an array, the size of the array, and a number n.
Assume that the array contains integers. The function should display
all of the numbers in the array that are greater than the number n .
This is what I have right now:
/*
Programmer: Reilly Parker
Program Name: Lab14_LargerThanN.cpp
Date: 10/28/2016
Description: Displays values of a static array that are greater than a user inputted value.
Version: 1.0
*/
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
void arrayFunction(int[], int, int); // Prototype for arrayFunction. int[] = array, int = size, int = n
int main()
{
int n; // Initialize user inputted value "n"
cout << "Enter Value:" << endl;
cin >> n;
const int size = 20; // Constant array size of 20 integers.
int arrayNumbers[size] = {5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; // 20 assigned values for the array
arrayFunction(arrayNumbers, size, n); // Call function
return 0;
}
/* Description of code below:
The For statement scans each variable, if the array values are greater than the
variable "n" inputted by the user the output is only those values greater than "n."
*/
void arrayFunction(int arrayN[], int arrayS, int number) // Function Definiton
{
for (int i=0; i<arrayS; i++)
{
if (arrayN[i] > number)
{
cout << arrayN[i] << " ";
cout << endl;
}
}
}
For my whole answer I assume that this:
Question: In a program, write a function that accepts three arguments: an array, the size of the array, and a number n. Assume that the array contains integers. The function should display all of the numbers in the array that are greater than the number n .
is the whole assignment.
void arrayFunction(int[], int, int); is probably the only thing you could write. Note however that int[] is in fact int*.
As others pointed out don't bother with receiving input. Use something along this line: int numbers[] = {2,4,8,5,7,45,8,26,5,94,6,5,8};. It will create static array for you;
You have parameter int n but you never use it.
You are trying to send variable to the function arrayFunction but I can't see definition of this variable!
Use something called rubber duck debugging (google for it :) ). It will really help you.
If you have some more precise question, ask them.
As a side note: there are better ways of sending an array to the function, but your assignment forces you to use this old and not-so-good solution.
Would you use an if else statement? I've edited my original post with the updated code.
You have updated question, then I update my answer.
First and foremost of all: do indent your code properly!!!
If you do that, your code will be much cleaner, much more readable, and it will be much easier understandable not only for us, but primairly for you.
Next thing: do not omit braces even if they are not required in some context. Even experienced programmers only rarely omit them, so as a beginner you should never do so (as for example with your for loop).
Regarding if-else statement the short answer is: it depends.
Sometimes I would use if (note: in your case else is useless). But other times I would use ternary operator: condition ? value_if_true : value_if_false; or even a lambda expression.
In this case you should probably settle for an if, as it will be easier and more intuitive for you.
Aside from the C++ aspect, think about the steps you need to do to figure out if a number is greater than a certain value. Then do that for all the numbers in the array, and print out the number if it's greater than n. Since you have a 'for' loop, it looks like you already know how to do a loop and compare numbers in C++.
Also, it looks like in your arrayFunction you are trying to input values? You can't input a whole array's worth of values in a single statement like you appear to be trying (also, 'values' is not the name of any variable in arrayFunction, so that would not be recognized when you try to compile it).

The compiler complains with "Error: stray '\240' in program"

It is wanted of me to implement the following function:
void calc ( double* a, double* b, int r, int c, double (*f) (double) )
Parameters a, r, c and f are input and b is output. “a” and “b” are two-dimensional matrices with “r” rows and “c”
columns. “f” is a function pointer which can point to any function of the following type:
double function‐name ( double x ) {
…
}
Function calc converts every element in matrix a, i.e., aij, to bij=f(aij) in matrix b.
I implement the calc function as follows, and put it in a program to test it:
#include <stdlib.h>
#include <iostream>
using namespace std;
double f1(double x){
return x * 1.7;
}
void calc (double* a, double* b, int r, int c, double (*f) (double))
{
double input;
double output;
for(int i=0; i<r*c; i++)
{
input = a[i];
output = (*f)(input);
b[i] = output;
}
}
int main()
{
// Input array:
int r=3;
int c=4;
double* a = new double[r*c];
double* b = new double[r*c];
// Fill "a" with test data
//...
for (int i=0; i<r*c; i++)
{
a[i] = i;
}
// Transform a to b
calc(a, b, r, c, f1);
// Print to test if the results are OK
//...
for (int i=0; i<r*c; i++)
{
b[i] = i;
}
return 0;
}
The problem is, I can't compile it. This is the output of DevC++ when I click on Compile and Execute button:
What's wrong?
I appreciate any comment to make the implementation more efficient.
As mentioned in a previous reply, this generally comes when compiling copy pasted code. If you have a Bash shell, the following command generally works:
iconv -f utf-8 -t ascii//translit input.c > output.c
It appears you have illegal characters in your source. I cannot figure out what character \240 should be but apparently it is around the start of line 10
In the code you posted, the issue does not exist: Live On Coliru
The /240 error is due to illegal spaces before every code of line.
eg.
Do
printf("Anything");
instead of
printf("Anything");
This error is common when you copied and pasted the code in the IDE.
Your program has invalid/invisible characters in it.
You most likely would have picked up these invisible characters when you copy and paste code from another website or sometimes a document. Copying the code from the site into another text document and then copying and pasting into your code editor may work, but depending on how long your code is you should just go with typing it out word for word.
I got the same error when I just copied the complete line but when I rewrite the code again i.e. instead of copy-paste, writing it completely then the error was no longer present.
Conclusion: There might be some unacceptable words to the language got copied giving rise to this error.
Solution: Delete that line of code (if you copied it from another source document) and type it yourself.
Error: stray '\240' in program is simply a character encoding error message.
From my experience, it is just a matter of character encoding. For example, if you copy a piece of code from a web page or you first write it in a text editor before copying and pasting in an IDE, it can come with the character encoding of the source document or editor.
I faced the same problem due to illegal spaces in my entire code.
I fixed it by selecting one of these spaces and use find and replace to replace all matches with regular spaces.
i did the following to solve the issue:
Paste the corrupted code into a txt file.
Open the code file with some hexadecimal editor.
Replace every occurrence of "C2A0" hexadecimal chain that you find in the document with an empty string.
Save it.
Now you should be able to copy the text code without any issue.

Is it okay to return vector in main

I am wondering is it okay to return a vector in main()? For example,
aSpecialVectorType main()
{
aSpecialVectorType xxx(vector::zero);
// do something here;
return xxx;
}
Do I need to forward declare "class aSpecialVectorType;" before main()?
And btw, is it legal to use another name other than "main" in c++?
Thanks
Edit1:
If not, what is the best way that it can output a vector?
My friend ask me to give him a blackbox that can serve as "vector in and vector out", he will use his matlab code to call my code. That's why I am asking.
I know how to vector in, but not sure if there is an easy way to output a vector.
Thanks
Edit2:
I am surprised why C++ has such an standard, any explanation? :)
In C++, main needs to return an int:
C++ standard, 3.6.1.2:
An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementation-defined.
.
If not, what is the best way that it can output a vector?
To output a vector, you need to copy it to a file or an output stream:
ostream_iterator<int> out_it(cout, ", ");
copy(myvector.begin(), myvector.end(), out_it);
The code fragment above writes the content of vector<int> to the standard output.
No. main must be declared in one of these two ways:
int main()
or
int main(int argc, char*[] argv)
Anything outside of this is not standard.
No.
According to the standard main() must return an int and only that.
No.
main must return int.
Other functions are free to have other names and return anything they want.
To expand on dashblinkenlight's answer, here is how two programs can communicate. Not by one capturing the return value of the other, but by a process called "piping", directing the standard output of one program to the standard input of another. Here, I'll print out a list of strings in one program, then the other program will expect a list of strings on its standard input, then I'll show you how to use the two together:
// Output program
#include <vector>
#include <string>
#include <iostream>
int main()
{
using namespace std;
vector<string> v;
v.push_back("one");
v.push_back("two");
v.push_back("three");
for (int i=0; i<v.size(); ++i)
cout << v[i] << '\n';
}
// input program
#include <iostream>
#include <vector>
#include <string>
int main()
{
using namespace std;
vector<string> v;
for (string tmp; cin >> tmp; )
v.push_back(tmp);
// print the strings in reverse order
for (int i=v.size()-1; i>=0; --i)
cout << v[i] << '\n';
}
If you run the first program by itself, it will just print the 3 strings out. If you run the second program by itself, it will prompt the user for strings until he uses the termination command. But on all of the most widely used operating systems, you can chain the two together. Then the output of the first will become the input of the second. On Unix-like systems, you do it like this:
./output_program | ./input_program
On Windows, I think it's the same, or very similar. Not sure though.
The answer to your first question is no.
The answer to your second question is yes, but you need to specify the name of your entry point to your executable (via linker settings ... may not be available on all linker tools).
Below statement is wrong
See Ben's comment below. Useful info that.
Be aware that though the name of the entry-point can change, it MUST conform to the standard parameter and return types.

Large Dynamic MultiDimensional Array Not Working

My code that I have is quite large and complicated so I won't waste your time reading it, but you're going to have to make certain assumtions about variables in it as a result. I will tell you the values of the variables which I have confirmed in the debugger so you know with certainty. Know that I have omitted a lot of unrelated code in here so what you see isn't everything but I have included everything that is relevant.
// This is defined in a class:
char**** m_DataKeys;
// This is in a member function of the same class:
m_DataKeys = new char*** [m_iNumOfHeroes]; // m_iNumOfHeroes = 2
while ( pkvHero )
{
// iHeroNum = 0 and then 1 #define NUM_OF_ABILITIES 4
m_DataKeys[iHeroNum] = new char** [NUM_OF_ABILITIES];
for (int ability = 0; ability < NUM_OF_ABILITIES; ability++)
{
if (pkvExtraData) // only is true when iHeroNum == 1 and ability == 0
{
// iNumOfExtraData == 2
m_DataKeys[iHeroNum][ability] = new char* [iNumOfExtraData];
while ( pkvSubKey )
{
// iCurExtraDataNum increments from 0 to 2
m_DataKeys[iHeroNum][ability][iCurExtraDataNum] = new char [50];
I put a break point on the line
m_DataKeys[iHeroNum] = new char** [NUM_OF_ABILITIES];
Before the line is called and when iHeroNum == 0 the m_DataKeys array looks like:
m_DataKeys | 0x02072a60
pointer | 0xffeeffee
Error : expression cannot be evaluated
Which is expected. After the line gets called it looks like:
m_DataKeys | 0x02072a60
pointer | 0x02496b00
pointer | 0xffeeffee
Error : expression cannot be evaluated
Which seems to look correct. However, since I set a breakpoint there, I hit play and had it hit it on the next loop around, where iHeroNum == 1 now and ran the line and m_DataKeys then looked like this:
m_DataKeys | 0x02072a60
pointer | 0x02496b00
pointer | 0xffeeffee
Error : expression cannot be evaluated
Which is the exact same as before! The line didn't change the array.... At all!
For clarification, m_DataKeys is a 3 dimensional array of character pointers to character arrays of size 50.
I can't figure out why this is happening, it looks like my code is correct. Is it possible that the garbage collector is screwing me over here? Or maybe the new allocator?
Edit: A Symptom of a Larger Problem
Let me elaborate a little more on the structure of my code, because really, this is just a cheap solution to a bigger problem.
I already have structs as one of you wisely suggested:
struct HeroData
{
// Lots o data here
// ...
// .
//
AbilityData* Abilities[NUM_OF_ABILITIES];
}
struct AbilityData
{
// More data here
// ...
// .
CUtlMap<char*,int> ExtraData [MAX_ABILITY_LEVELS];
}
Now when it got complicated and I had to do this DataKeys arrays of pointers to arrays of pointers crap is only when the need arose to be loading in some data to a dynamic structure, where both the keys, the values, and the numbers of data are completely dynamic. So I thought to use a map of char arrays to ints, but the only problem is that I can't store the actual char array in my map, I have to use a char *. I tried defining the map as:
CUtlMap<char[50],int> ExtraData [MAX_ABILITY_LEVELS];
But that really didn't work and it seems sort of strange to me anyway. So, I had to find some place to stick all these ExtraDataKeys and for some reason I thought it cool to do it like this. How can I store char arrays in objects like arrays or maps?
Since you are using pointers as class members, my best guess is that you are violating The Rule Of Three. That is, you did not provide a copy constructor and a copy assignment operator for your class. That usually leads to strange data loss when passing objects of your class around.
Note that no sane C++ programmer would use char****. Here is my best attempt to fix your problem using vectors and strings, but there is probably a much better design for your specific problem:
#include <string>
#include <vector>
class Foo
{
int m_iNumOfHeroes;
std::vector<std::vector<std::vector<std::string> > > m_DataKeys;
enum { NUM_OF_ABILITIES = 4, iNumOfExtraData = 2 };
public:
explicit Foo(int iNumOfHeroes)
: m_iNumOfHeroes(iNumOfHeroes)
, m_DataKeys(m_iNumOfHeroes, std::vector<std::vector<std::string> >
(NUM_OF_ABILITIES, std::vector<std::string>(iNumOfExtraData)))
{
}
};
int main()
{
Foo x(2);
}
In case you have never seen that colon syntax in the constructor before, that is a member initializer list.
I really wish C++ had array bounds checking
std::vector and std::string do have bounds checking if you use the foo.at(i) syntax instead of foo[i]. In Debug mode, even foo[i] has bounds checking enabled in Visual C++, IIRC.
Though the code might be correct, I personally find that working with something like a char **** can get pretty confusing pretty fast.
This is just my personal preference, but I always try to organize things in the most clear and unambiguous way I can, so what I would do in your situation would be something like
struct Ability
{
char extraData[NUM_OF_EXTRA_DATA][50];
};
struct HeroData
{
Ability abilities[NUM_OF_ABILITIES];
};
class Foo
{
// here you can choose a
HeroData *heroArray;
// and then you would alloc it with "heroArray = new HeroData[m_iNumOfHeroes];"
// or you can more simply go with a
std::vector<HeroData> heroVector;
};
I think this makes things more clear, making it easier for you and other programmers working on that code to keep track of what is what inside your arrays.
I think you expect the wrong thing to happen (that the visual display in the debugger would change), even though your code seems correct.
Your debugger displays m_DataKeys, *m_DataKeys and **m_DataKeys, which is the same as m_DataKeys, m_DataKeys[0] and m_DataKeys[0][0]. When you change m_DataKeys[1], you are not going to notice it in your debugger output.
The following might help you: in my debugger (MS Visual Studio 2005), if you enter e.g. m_DataKeys,5 as your watch expression, you will see the first 5 elements of the array, that is, m_DataKeys[0], m_DataKeys[1], ..., m_DataKeys[4] - arranged in a neat table. If this syntax (with the ,5) doesn't work for you, just add m_DataKeys[1] into the debugger's watch window.
Not sure why this didn't occur to me last night, but I was pretty tired. Heres what I decided to do:
struct AbilityData
{
// Stuff
CUtlMap<char*,int> ExtraData [MAX_ABILITY_LEVELS];
char **DataKeys;
}
Thats what my abilityData struct now looks like, and it now works, but now I want to reorganize it to be like:
struct AbilityData
{
// Stuff
CUtlMap<char*,int[MAX_ABILITY_LEVELS]> ExtraData;
char **DataKeys;
}
Because it makes more sense that way, but then I run into the same problem that I had before with the char array. It almost seems like to me it might just be best to ditch the whole map idea and make it like:
struct AbilityData
{
// Stuff
int *ExtraData;
char **DataKeys;
}
Where ExtraData is now also a dynamically allocated array.
The only problem with that is that I now have to get my data via a function which will loop through all the DataKeys, find a matching key for my input string, then return the ExtraData associated with it.