stuck in use of vector of structure - c++

This is my code. I'm Trying to find max element in this. The Data_Test file is a simple txt file that have 12 data. In my case, 12 number that list one by one below to each other : 122 135 148 156 178 189 256 114 125 136 630 360. compiler says that cannot convert 'main()::str' to 'int' in initialization. How can i convert it to int?
ifstream input("Data_Test.txt");
const int NUMstr = 4;
struct str{
string Data[NUMstr];
};
str vec;
vector<str> event;
int maxElementIndex = max_element(event.begin(), event.end()) - event.begin();
int maxElement = *max_element(event.begin(), event.end());
int minElementIndex = min_element(event.begin(), event.end()) - event.begin();
int minElement = *min_element(event.begin(), event.end());
cout << "maxElementIndex:" << maxElementIndex << ", maxElement:" << maxElement;
cout << "minElementIndex:" << minElementIndex << ", minElement:" << minElement;

The first strange thing is why you are using strings when you actually have integers.
The second strange thing is why you have (effectively) a vector of arrays.
struct str{
string Data[NUMstr];
};
This is an array wrapped inside a structure. And this vector<str> is a vector of structures, each of which wraps an array. I see no reason that you need this, in your problem description you just have a list of twelve numbers.
You're also a little confused about how iterators work.
So I suspect you are just getting confused and making things way more complicated than they need to be. This code works, it's a simple vector of integers, I suspect it is all that you need.
vector<int> event;
...
int maxElementIndex = max_element(event.begin(), event.end()) - event.begin();
int maxElement = event[maxElementIndex];

You need to know the logic how you want your str struct to be converted to int. You can convert std::string to int using std::stoi, e.g.:
const int i = std::stoi("123");

Related

Variable size array in C++

This is interesting. I want to make a 2D array where one of the dimensions is a variable. Here is my code:
int main(void) {
const int rows = numlines("health.txt");
float data[rows][5] = {0};
readIntoArray(data, 5, rows, "health.txt");
return 0;
}
Line 3 "rows" is underlined with an error. It says: "Expression must have a constant value." Apparently it works for other people to use const in these situations. But mine might work differently because my variable is defined by a function. Here is that function:
int numlines(string filename) {
int number_of_lines = 0;
ifstream fin(filename);
string line;
while (getline(fin, line)) {
++number_of_lines;
}
return number_of_lines;
}
I have tried following other suggestions and making my code follow this format:
(Replace lines 2 & 3 of the first code block with this.)
int rows = numlines("health.txt");
float **data;
data = new float*[rows]; //The height is defined by the function
for (int i = 0; i < rows; i++) {
data[i] = new float[5]; //The width is 5
}
But then that causes an error on "data" in line 4 of the first codeblock. The error is Argument of type "float**" is incompatible with parameter of type "float (*)[5]". Here is the first line of the relevant function:
void readIntoArray(float data[][MAXCOLUMNS], int arrayX, int arrayY, string filename)
MAXCOLUMNS is #defined as 5.
How do I pass the 2D array into the function without creating an error?
I am not the most experienced in c++, so I might be missing something obvious.
There is a difference between:
const int rows = numlines("health.txt");
and
const int rows = 20;
In both cases the value of the variable cannot modified once it is initialzed. The difference is that in the first case, the value won't be known until run time while in the second case, the value is known at compile time.
In C++, an array can be declared using a variable only if its value is known at compile time.
That explains why you cannot use:
const int rows = numlines("health.txt");
float data[rows][5] = {0};
but you can use:
const int rows = 20;
float data[rows][5] = {0};
You can easily get around that issue by using an std::vector of std::vectors.
const int rows = numlines("health.txt");
std::vector<std::vector<float>> data(rows, std::vector<float>(5));
Since you know the size of the inner array, you can also you std::array. It will make the declaration a little simpler.
std::vector<std::array<float, 5>> data(rows);
In C++,you can use "std::vector< T >" to save your data as a variable size array.
Just learn how to use STL,it would simplify your works.
You can use alloca to implement the equivalent of a variable length array:
float (*data)[5] = (float (*)[5]) _alloca(rows * 5 * sizeof(float));
This will allocate local (stack) space and set data to point to the first row (with 5 columns) of a matrix of floats. The 5 can be replaced with a constant. You can then use data like a normal local matrix, data[ i ][ j ] ... . Depending on the compiler, the name may be alloca() instead of _alloca(), and the cast (float (*)[5]) may not be needed.
Since this is a local allocation, it's automatically freed when the function exits.

unexpected value return by array variable

I am trying to pass array to function (*getcreditcurve). I am expecting function (*getcreditcurve) to return an array. Main function is expected to send several such array to function (*getcreditcurve), pointer function is expected to return a array to main function for different array using the logic given in pointer function (*getcreditcurve). I am not getting error but I don’t get correct value. I expect I+1 to be 3 * 0.0039 = 0.0117 and I+2 to be 4 *0.0060 = 0.0024 however I get following in excel output
'00D4F844 00D4F84C'
Even if I change the print statement to
'print << *(I1+1) << '\t' << *(I2+2) << endl;'
I get following excel out put
-9.26E+61 -9.26E+61
Can somebody help in trouble shooting please? Sorry I went through other post/question in this site but not able to get simplest way to solve this issue. I am going to use this logic to build other projects so simplified the question just to resolve main issue.
#include<iostream>
#include<cmath>
#include<fstream>
typedef double S1[5];
using namespace std;
double *getcreditcurve(double *);
int main()
{
S1 C1 = { 0.0029, 0.0039, 0.0046, 0.0052, 0.0057 };
S1 C2 = { 0.0020, 0.0050, 0.0060, 0.0070, 0.0080 };
typedef double *issuer;
issuer I1 = getcreditcurve(C1);
issuer I2 = getcreditcurve(C2);
ofstream print;
print.open("result1.xls");
print << (I1+1) << '\t' << (I2+2) << endl;
print.close();
return 0;
}
double *getcreditcurve(S1 ptr)
{
const int cp = 5;
typedef double curve[cp];
curve h;
h[0] = 2 * ptr[0];
h[1] = 3 * ptr[1];
h[2] = 4 * ptr[2];
h[3] = 5 * ptr[3];
h[4] = 6 * ptr[4];
return h;
}
If you want getcreditcurve to return an array, then try this:
const int cp = 5;
typedef double curve[cp];
curve getcreditcurve(S1 ptr) {
But that gives an error error: ‘foo’ declared as function returning an array. Functions can't return C arrays. But the good news is that if you fully embrace C++ you can return std::array instead.
#include<array>
const int cp = 5;
typedef curve std::array<double,cp>;
curve getcreditcurve(S1 ptr) {
But really, std::vector is probably much better as you have more flexibility about the size.
#include<vector>
std::vector<double> getcreditcurve(std::vector<double> ptr)
{
std::vector<double> h;
h.push_back(2 * ptr.at(0));
h.push_back(3 * ptr.at(1));
h.push_back(4 * ptr.at(2));
h.push_back(5 * ptr.at(3));
h.push_back(6 * ptr.at(4));
return h;
}
In fact, pretty much all problems with C arrays can be solved by std::vector. Then, in special situations, you can use std::array. But focus on std::vector for now.
It's not possible to return a C array from a function. There are other things you can return, such as std::vector or std::array. You should consider redesigning your application around those two instead.
But if you really need to use C arrays in C++, I suggest that instead of trying to return an array from getcreditcurve, you pass an extra array into getcreditcurve which will be used to store the result. This is called an output parameter.
void getcreditcurve(double*, double *);
This would solve the "scope" problem. The caller (main) would then create the array before calling getcreditcurve and would then pass that to getcreditcurve. As a result, getcreditcurve does not have to take responsibility for creating (or destroying) any object.
double I1[5];
getcreditcurve(I1, C1); // will store its result on `I1`.
This might be the easiest option if you really really need to get this working as soon as possible.
If you are willing to make some further changes, you can make a much safer program. The short term goal is to abolish all uses of * (except to use it for multiplication).
C arrays cannot be passed by value, in particular they cannot be returned. There are other funky things you can do (passing special pointers), but the best thing to do with C arrays is to pass them by reference. In C++, reference-passing behaviour is quite consistent and works well.
// http://stackoverflow.com/questions/31362360/unexpected-value-return-by-array-variable
#include<iostream>
#include<cmath>
#include<fstream>
typedef double S1[5];
using namespace std;
/* In the following declaration, the two parameters
* are taken by reference (note the '&').
* This is almost always the best way to pass arrays.
*
* Also, this is a template where N is automatically
* set to the correct number of parameters. This nice
* automatic behaviour is possible only because the
* array is taken by reference.
*
* Finally, note that the second reference, for 'input',
* has 'const'. This is to emphasize that 'input' is for input,
* that getcreditcurve will not be allowed to modify the input argument.
*/
template<size_t N>
void getcreditcurve(double (&output)[N],const double (&input)[N]);
int main()
{
/* S1 is the type - array of five doubles */
/* Here declare and initialize C1 and C2 as two variables
* of this type */
S1 C1 = { 0.0029, 0.0039, 0.0046, 0.0052, 0.0057 };
S1 C2 = { 0.0020, 0.0050, 0.0060, 0.0070, 0.0080 };
// create the two output arrays first, within main
S1 I1;
S1 I2;
// call getcreditcurve, passing in the output and input arrays
getcreditcurve(I1,C1);
getcreditcurve(I2,C2);
ofstream print;
/* you can't create Excel(.xls) files in C++ easily
* Better to just create a .csv file instead
* csv = comma-separated values
*/
print.open("result1.csv");
print << I1[0] << ',' << I2[3] << endl;
print.close();
return 0;
}
template<size_t N>
void getcreditcurve(double (&output)[N],const double (&input)[N])
{
output[0] = 2 * input[0];
output[1] = 3 * input[1];
output[2] = 4 * input[2];
output[3] = 5 * input[3];
output[4] = 6 * input[4];
}
But seriously, you really should just ditch C arrays entirely. This is C++, not C. Use std::vector<double> instead.

Pointer to type int doesn't cooperate properly in C++

I've googled a lot now, and I still can't find any solution to this... The thing is, that I'm trying to make a program that stores different points in a coordinate system, and displays them on the screen (it will later turn into a type of graph, but I'm not quite there yet). But unfortunately, I've had some issues with this...
I've decided to store all the the points in addresses after each other, of type string, like this:
string p;
string * pointer = &p;
p = "5, 3";
*(&p+1) = "6, 4";
*(&p+2) = "7, 5";
cout << *pointer << *(pointer+1) << *(pointer+2);
Or this:
string p;
string * pointer = &p;
p = "5, 3";
*(pointer+1) = "6, 4";
*(pointer+2) = "7, 5";
cout << *pointer << *(pointer+1) << *(pointer+2);
But whenever I get to line 4 or 5, I get an error on this row in the memcpy assembly:
mov [edi],al ;U - write second byte to destination
So apparently this doesn't work...
I'm starting to suspect that it has something to do with the fact that the pointer points to an address of type string, which consists of char arrays, but I'm not sure why nor how... If it now is like this, why would it even be possible to use string pointers?
Regardless, any solution/explaination is appreciated, really. I haven't really used pointers that much in the past, so excuse me if I'm missing something obvious. But as said, I've tried searching for this, and I can't find anything.
Your first code will not even compile.
Your second code attempts to store values into std::string objects presumably located after p in memory. But there are no std::string objects after p in memory. Any attempts to "store" anything into those non-existing objects leads to undefined behavior.
If you declared your p as an array
string p[3];
string * pointer = p;
*pointer = "5, 3"; // same as `p[0] = "5, 3"`
*(pointer+1) = "6, 4"; // same as `p[1] = "6, 4"`
*(pointer+2) = "7, 5"; // same as `p[2] = "7, 5"`
cout << *pointer << *(pointer+1) << *(pointer+2);
then the second version of the code would safely store the strings into consecutive elements of that array.
But what you have now just doesn't make sense. And it is not immediately clear what you are trying to do.
Don't use pointers, they are difficult, and you have some serious (and strange) misunderstanding about how they work. Just use a vector.
#include <vector>
struct Point
{
Point(int xx, int yy) : x(xx), y(yy) {}
int x;
int y;
};
std::vector<Point> p;
p.push_back(Point(5,3));
p.push_back(Point(6,4));
p.push_back(Point(7,5));
I've defined a simple Point class because that also seems sensible if you are writing a program about points. But if you really want to store your points as strings then replace std::vector<Point> with std::vector<std::string>.
Why don't you simply do this:
string p1 = "5, 3";
string p2 = "6, 4";
string p3 = "7, 5";
cout << p1 << p2 << p3;
If you have more points, you could use a vector like that:
vector<string> points;
points.push_back("5, 3");
points.push_back("6, 4");
points.push_back("7, 5");
cout << points[0] << points[1] << points[2];
By the way, why do you want to store coordinates in a string instead of a float array for example ?
First of all, you take the address of a std::string object and you increment it - std::string is not (w)char[]. It does store its data contiguously but it also stores some meta-data in an implementation defined manner. So you're overwriting something that just happens to be in the memory - and you're overwriting it with something that mismatches its type, therefore it won't even compile.
When manipulating std::strings, you can use the operator[] that will give you access to the actual data of the string.
That said, I am pretty sure you do NOT want to store random pointers to string. Ideally, make a class Point<T> with T x, y; data members to store the coordinates.

Having trouble creating linked list

I have an array of strings that I'm supposed to create a linked list with. The problem is I can only use arrays. Everything I've looked up says to use struct and nodes, and I'm not sure where to go from here. I know my code isn't right, I have the pointers pointing to one element of the array each, so they aren't really linked. If anyone can point me in the right direction that would be amazing
Here is what I have so far
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string names [4] = {"Dick", "Harry", "Sam", "Tom", " "};
string *nameptr[4];
for(int x = 0; x < 4; x++)
{
nameptr[x] = &names[x];
cout << *nameptr[x] << " is at position " << x << " and points to ";
cout << &nameptr[x] << endl;
}
return 0;
}
Here is a tutorial for linked lists in c++:
http://www.dreamincode.net/forums/topic/31357-c-linked-lists-custom-linked-lists-part-1/
You should search and have a go first in future, then when you ask people here will be able to better help you with your question. In fact read this as well:
http://mattgemmell.com/2008/12/08/what-have-you-tried/
Actually if using arrays, you only need a pointer to the first element, and you can access the rest of the array by pointer arithmetic.
However, if you want a real link list. then you could do something like this:
struct mydata{
std::string data;
struct mydata* next;
}
mydata names[4] = {{"Dick",NULL}, {"Harry",NULL}, {"Sam",NULL}, {"Tom",NULL}, {" ",NULL}};
//here you establish the link
names[0].next = &names[1];
names[1].next = &names[2];
names[2].next = &names[3];
names[3].next = &names[4];
//here is the pointer to the head;
mydata* nameptr = names;
while(nameptr)
{
cout << nameptr->data;
nameptr = nameptr->next;
}
What do you mean by "I can only use arrays"? You only know how to use arrays, or you are limited to only using arrays, or ??
You've looked up some stuff that's told you to use structs - have you tried doing this? It isn't in your code here.
Unrelated to your actual question, but you've declared an array of 4 strings (string names [4]), then you're trying to initialise that array with 5 items.
My advice is similar to what you've seen: use structures, and I'll add that you're going to need to use the heap as well (malloc in c, new in c++). The structure will need a link pointer to the next list element, and somewhere to store the data itself, in this case probably just a char pointer.

How to read a character or string and automatically convert to a number (C/C++)?

Suppose I am working on a card game, and I am using the numbers 0 to 3 to represent the suits internally, as it's easier to work with numbers. So:
0 is equivalent to hearts
1 is equivalent to clubs
2 is equivalent to spades
3 is equivalent to diamonds
When I need to output the suits as strings, though, I can easily use an array of strings to convert them, like this one:
char *suits[] = {"heats","clubs","spades","diamonds"};
So that I can type:
cout << suits[card.suit]
and the output would be the exact string of the suit.
What if I want to do this the other way around though? That is, I'll be reading the suits from a file as strings, and I want to convert them to their respective numerical value (0 to 3) on the fly. How can I do it?
My initial idea was to create a very small hash table (i.e., 4 elements in this case), then hash the strings as I read them and get their respective numerical value from the hash table.
Is there an easier way I am missing (specifically in C or C++)?
std::map<std::string, int> assoc;
assoc["hears"] = 0;
assoc["clubs"] = 1;
...
char *suits[] = {"heats","clubs","spades","diamonds"};
for (char *data : suits)
{
std::cout << assoc[data];
}
Like Joachim said, I would recommend a std::map<std::string, int>.
You can then do stuff like.
std::cout << map["heart"];
I would recommend to check out the std::map class as it is quite a nice tool, but also holds some gotchas.
If you want to use it in both directions, you could also use a boost::bimap.
std::map<std::string, int id> cardsToIdMap;
int stringToCardId(std::string s) {
return cardsToIdMap[s];
}
A map is hugely overkill here:
#define SIZE(x) (sizeof (x)/sizeof(*(x)))
const char *suits[] = {"heats","clubs","spades","diamonds"};
int suit_to_int(char *s)
{
for(int x=0; x<SIZE(suits);x++)
if(strcmp(s, suits[x])==0)
return x;
return SUIT_ERR;
}
char* suit;
if (*suit == 'h') {
return 0;
} else if ...