Vector display iterator ends prematurely [duplicate] - c++

This question already has answers here:
sizeof() a vector
(6 answers)
Closed 2 years ago.
I'm currently working on a final project for one of my introductory classes in college, and I can't seem to find out why my output is cutting out prematurely. I'm trying to append the lines of a text file in the same directory into a vector and randomly select from the vector to get a name for an enemy in a text-based fighting game, but during testing it seems like the vector either only contains three items or the last for loop (the one before the comment blocks, I'm working on it in chunks) only displays three of the possible names. Here's the code:
#include <iostream>
#include <fstream>
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <ctype.h>
using namespace std;
int main() {
srand(time(0));
int userInput;
int player_health = 100;
int boss_health = 200;
int boss_index = rand() % 3;
ifstream boss_list;
string boss_name = "";
string boss_inputs[3] = {"MACHINE GUN", "BOMB ATTACK", "CANE SMACK"};
string user_inputs[3] = {"SWORD ATTACK", "BOMB ATTACK", "MAGIC ATTACK"};
vector<string> boss_list_holder = {};
unordered_map<string, int> attacks = {
{"SWORD ATTACK", rand() % 100},
{"BOMB ATTACK", rand() % 100},
{"MAGIC ATTACK", rand() % 100}
};
unordered_map<string, int> boss_attacks = {
{"MACHINE GUN", rand() % 75},
{"BOMB ATTACK", rand() % 80},
{"CANE SMACK", rand() % 50}
};
boss_list.open("names.txt", ios::in);
while(getline(boss_list, boss_name)) {
//cout << boss_name << endl;
boss_list_holder.push_back(boss_name);
}
for(int j=0; j<(sizeof(boss_list_holder)/sizeof(boss_list_holder[0])); j++) {
cout << boss_list_holder[j] << endl;
}
//cout << "BOSS FIGHT SIMULATOR\n\n";
/*
while(userInput > 3 || userInput < 1) {
cout << "Enter the attack you want to use!\n";
for(int i=0; i<sizeof(user_inputs)/sizeof(user_inputs[0]); i++) {
cout << i + 1 << ". " << user_inputs[i] << " ";
}
cout << "\n";
cin >> userInput;
};
*/
/*
cout << boss_inputs[boss_index] << " ";
cout << boss_attacks[boss_inputs[boss_index]];
*/
return 0;
}
Any and all help would be appreciated. Thank you!

sizeof(boss_list_holder)/sizeof(boss_list_holder[0])
This is a very old-fashioned way of deducing the length of an array, and indeed it only works for arrays.
It doesn't even work on pointers, which people often have instead of arrays without realising it, so std::size(boss_list_holder) is a better general solution.
In your case, simply boss_list_holder.size() is your best bet.
You should also be using unsigned int (or, ideally, std::size_t) for array or vector indices, and your compiler will warn you about unsafe signed/unsigned comparisons if you stick with int.
(Some people will go further and recommend std::vector<string>::size_type, though personally I think that's overkill.)

Your for loop over the boss_list_holder vector is wrong:
for(int j=0; j<(sizeof(boss_list_holder)/sizeof(boss_list_holder[0])); j++)
This sizeof trick only works for fixed-sized arrays (like your user_input), where the elements are stored directly in the allocated memory of the array itself.
This does not work for dynamic containers like std::vector, which boss_list_holder is an instance of. The elements of a std::vector are not stored in the allocated memory of the std::vector object itself (ie, sizeof(boss_list_holder) is not equal to sizeof(string) * NumberOfStrings). They are stored in an array that is allocated elsewhere in memory, and the std::vector object simply holds a pointer to that array (amonst other things).
You need to use the vector's size() method instead, that will return the number of elements that have been put into the std::vector's inner array:
for(size_t j = 0; j < boss_list_holder.size(); ++j)

Related

Trying push a string backwards into a vector

#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class thing{
public:
vector<unsigned short> vec;
thing(string);
};
int main(){
thing adam("12345");
for(int i = adam.vec.size() - 1;i >= 0;i--){
cout << adam.vec[i] << endl;
}
}
thing::thing(string str){
for(int i = str.size() - 1; i >= 0;i--){
cout << str[i] << endl;
vec.push_back(str[i]);
}
}
I'm trying to make a constructor that takes in a string and fills the vector with the string in reverse, but instead of filling the vector with the values 5,4,3,2,1, it fills it with 53,52,51,59,49. This happens when I call push_back() and I'm confused on why.
I'm trying to make a constructor that takes in a string and fills the vector with the string in reverse
You probably don't really want to do that. As #JesperJuhl suggests - you can always just access the string in reverse. Why the needless copy?
instead of filling the vector with the values 5,4,3,2,1, it fills it with 53,52,51,59,49
You're mistaking the characters '5', '4', '3' with their integer values. The values of string elements are numbers, but those numbers are indices into some character set. Without going into too much detail about - here's the relevant fragment of the character set in your case:
Indeed, the character '5' has index 53 (decimal) within the character set, '4' has 52 and so on.
for(int i = adam.vec.size() - 1;i >= 0;i--)
cout << adam.vec[i] << endl;
Your code to insert in reverse order is working just fine. But you are displaying the vector in reverse order also, so it goes back to previous order. To display in correct order, just use:
thing adam("12345");
for(size_t i = 0; i < adam.vec.size(); i++)
cout << adam.vec[i] << ' ';
cout << endl;
//or
for(const auto &element : adam.vec)
cout << element << ' ';
cout << endl;
Your method for(int i = str.size() - 1; i >= 0;i--){...} for iterating backward works in most cases, but casting size in to int can be a problem. The standard library offers other methods. Example:
thing::thing(string str)
{
std::copy(str.crbegin(), str.crend(), std::back_inserter(vec));
}
Or use iterators to traverse forward or backward.

How to take inputs from array and input it into an equation in C++?

My goal is to try and create a program that takes in grades in percents and multiply it with their weight value (either in decimal form or percent form). The equation is basically:
Overall grade = (grade1*weightInDecimal1)+(grade2*weightInDecimal2)+(grade3*weightInDecimal3)+...
or
Overall grade = (grade1*weight%1)+(grade2*weight%2)+(grade3*weight%3)+...
Is there a way to store the inputs and then recall it later in the code? Or possibly a more efficient way?
I also want to try and make a dynamic array. I want to make a program that asks the user for how many assignments they have and makes an array based on that. That way it's not stuck at 4 assignments
#include <string>
#include <iostream>
using namespace std;
int main() {
int numbers[4][2];
for(int i=0;i<4;i++)
{
cout<<"Grade #"<<i<<endl;
cin>>numbers[i][0];
cout<<"Weight for grade #"<<i<<":"<<endl;
cin>>numbers[i][1];
}
for (int i = 0; i<4; i++)
{
cout << "|" << numbers[i][0]*numbers[i][1]<< "|";
}
system ("PAUSE");
return 0;
}
This is what structs are for
#include <string>
#include <iostream>
#include <array>
using namespace std;
struct entry {
int grade;
int weight;
int gradeWeight; //grade*weight
};
int main() {
array<entry,4> numbers;
for(int i=0;i<numbers.max_size();i++)
{
cout<<"Grade #"<<i<<endl;
cin>>numbers[i].grade;
cout<<"Weight for grade #"<<i<<":"<<endl;
cin>>numbers[i].weight;
}
for (int i = 0; i<numbers.max_size(); i++)
{
numbers[i].gradeWeight = numbers[i].grade*numbers[i].weight;
cout << "|" << numbers[i].gradeWeight << "|";
}
system ("PAUSE");
return 0;
}
This way you can also increase the amount of numbers by just increasing the array size.
As pointed by others, if you ask the user for how many assignments they have, std::array is a wrong container because it's dimension is fixed at compile time.
As others, I discurage the use of direct memory allocation but the use of std::vector to manage it.
I just suggest the use of reserve() (method of std::vector), when you know how many assignments.
The following is a full example using, instead a couple of std::vector of int, a single std::vector of std::pair<int, int>
#include <utility>
#include <vector>
#include <iostream>
int main()
{
int valG, valW;
std::size_t dim;
std::vector<std::pair<int, int>> vec;
std::cout << "How many grade/weight couples? ";
std::cin >> dim;
vec.reserve(dim);
for ( auto i = 0U ; i < dim ; ++i )
{
std::cout << "Grade #" << i << "? " << std::endl;
std::cin >> valG;
std::cout << "Weight for grade #" << i << "? " << std::endl;
std::cin >> valW;
vec.emplace_back(valG, valW);
}
for ( auto const & p : vec )
std::cout << '|' << (p.first * p.second) << '|';
std::cout << std::endl;
return 0;
}
There are many reasons to avoid using arrays (dynamic or otherwise). See for example Stroustrup's FAQ entry What's wrong with arrays? As Greg suggests in the comments you will most likely write better quality code if you use a container like std::vector.
If you can calculate or input the size of your container before allocating it you can (if you wish) pass that size to the constructor ...
auto syze{ 0 };
auto initialValue{ 0 };
// calculate or input syze
. . .
// dynamically allocate an "array"
// of ints and an "array" of floats
std::vector<int> grades(syze, initialValue);
std::vector<float> weights(syze, initialValue);
On the other hand if you prefer to use a container that dynamically grows to hold data as it arrives you can do that too...
// dynamically allocate an empty "array"
// of ints and an empty "array" of floats
std::vector<int> grades;
std::vector<float> weights;
while (...condition...)
{
std::cin >> g; // input a grade ...
std::cin >> w; // ... and a weight
// grow the containers by adding
// one item at the end of each
grades.emplace_back(g);
weights.emplace_back(w);
}
Update
I should have pointed out how to calculate the result from the two vectors. You can calculate your overall grade with just one more line of code by using std::inner_product from the STL's <numeric> header. Note that in the code below the last argument is 0.0 (rather than just 0) so that std::inner_product returns a double rather than an int. That avoids any risk of float values being truncated to int (and avoids some pretty ugly warnings from the compiler).
auto overallGrade = std::inner_product(grades.begin(), grades.end(), weights.begin(), 0.0);

C++: reading a string, converting to dynamic int array

I am writing a program that asks the user to type in a very large int (much larger than the type int can handle). When receive this int from the user, it is stored in a string. Then, I want to convert this string into an int array (I am using a dynamic int array). After compiling and running the program, I get values that don't make sense. The values of my int array seem to be random gibberish. I don't see why this is so - it doesn't look like my loops are out of bound in the converting process. Please help. The purpose of creating an int array is to then come up with ways to add, subtract, multiply, and compare very large int values. To make it clear what I am intending to do: say the user types in "12345". I want to store this string value into an int array that would have a length of 5, each element corresponding to the next number in the int.
largeIntegers.h
#ifndef H_largeIntegers
#define H_largeIntegers
#include <iostream>
#include <string>
class largeIntegers
{
private:
void readInteger();
// reads integer
public:
std::string s_integer;
int* integer;
int length;
largeIntegers();
// default constructor
void outputInteger();
// outputs integer
};
#endif
largeIntegers.cpp
#include <iostream>
#include <string>
#include "largeIntegers.h"
using namespace std;
largeIntegers::largeIntegers()
{
readInteger();
}
void largeIntegers::readInteger()
{
int i = 0,j = 0, k;
cout << "Enter large integer: ";
cin >> s_integer;
for (; s_integer[i] != '\0'; i++);
length = i;
int* integer = new int[i];
k = 0;
for (j = i - 1; j >= 0; j--)
integer[j] = s_integer[k++] - 48;
}
void largeIntegers::outputInteger()
{
for (int i = length - 1; i >= 0; i--)
cout << integer[i];
}
User.cpp
#include <iostream>
#include <string>
#include "largeIntegers.h"
using namespace std;
int main()
{
largeIntegers a;
cout << a.length << endl << endl;
cout << a.integer[0] << endl << a.integer[1] << endl;
a.outputInteger();
cout << endl << endl;
return 0;
}
I intentionally made the variables in the header public for debugging purposes. My output on the console after compiling is:
Enter large integer: 111
3
952402760
1096565083
10966961571096565083952402760
This is the problem
int* integer = new int[i];
change to
integer = new int[i];
Your version declares a local variable that just happens to have the same name as your class variable. Easy mistake to make.
also, using standards facilities like std::vector and std::getline would make your code much cleaner in addition to avoid the problem you had, and resolve memory leaks you have now if you call readInterger twice:
void largeIntegers::readInteger()
{
cout << "Enter large integer: ";
std::getline(std::cin, s_integer);
integer = std::vector(s_integer.size());
//your last loop to fill the array probably can be replaced by std::transform
}

How to Use A Pointer to Modify a Vector

So this is my main method:
#include <iostream>
#include "TextFileToArray.h"
#include <vector>
using namespace std;
int main()
{
cout << "Hello world!" << endl;
TextFileToArray myobject("C:/bunz.txt");
vector<string> v[10];
myobject.vectorfiller(*v);
for(int i =0; i<10; i++){
cout << v;
}
}
It calls upon an object known as myobject and it calls upon a method/function. Here is the method/function:
int TextFileToArray::vectorfiller(vector<string>& givenpointer) {
vector<string> *innervec = &givenpointer;
const char * constantcharversion = path.c_str();
ifstream filler(constantcharversion);
string bunz;
string lineoutliner = "Line ";
string equalssign = " = ";
int numbercounter = 1;
while (!filler.eof()) {
std::getline(filler, bunz, ';');
if (bunz.empty()) {
lineoutliner = "";
numbercounter = 0;
equalssign = "";
}
cout << lineoutliner << numbercounter << equalssign << bunz <<endl;
cout << "" << endl;
innervec->push_back(bunz);
numbercounter++;
}
filler.close();
return 0;
}
So far it displays the text from the textfile, but for some reason it pushes memory addresses into the vector, so when main() displays the vector, it shows memory locations:
vector<string> v[10]; creates an array of 10 vectors, which is probably not what you want.
Create a single vector, pass that as parameter, and output its contents:
vector<string> v;
myobject.vectorfiller(v);
for(int i =0; i < v.size(); i++){
cout << v[i];
}
Agree, size should not be 10, should be size(), and count<
The problem is that you're printing the array of vectors, not the elements in the first vector. Instead, you want this in your main:
for (int i = 0; i < v[0].size(); i++) {
cout << v[0][i] << endl;
}
PS: As Luchian said, you are creating 10 vectors, not one vector with 10 slots. To get just one vector do this:
vector<string> v;
You also don't need to mention 10; vectors grow when you push elements on them. If you happen to know how much space you want to be reserved ahead of time, you can use the reserve member function like so:
vector<string> v;
v.reserve(some_number);
reserve doesn't change the size of v; it only makes the vector ready to accept that many elements, so that it doesn't have to reallocate memory, and copy things around as much. It is purely an optimization; if you were to simply comment out reserve calls in your program, it will behave exactly the same. The only thing that might change is performance, and memory usage.

Segmentation fault on creating matrices

I was practicing on c++ on some tutorials and I encountered on a tutorial that creates matrices, I wanted something more from it and I modified it, I dont know matrices at all cuz I didnt learn them yet at school but this code below sometimes works sometimes not.
When it doesn't work I usually get: Segmentation fault.
why does this happen ?
before it happened everytime but after i gave a 0 value to variable line and member on the beginning it doesnt happen anymore, but still if I type exc
Line: 10
Member: 9
it gives:
1 1 1 1 1 1 1 1 1
1 2 3 4 5 1 7 8 9
Segmentation fault
and stopes.
Can anyone explain me this ?
thank you !
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int line=0,member=0;
int i,j,matrice[line][member];
cout << "\nLine: ";
cin >> line;
cout << "Member: ";
cin >> member;
cout << "\nCreated Matrice: \n" << endl;
for (i=0;i<line;i++)
{
for (j=0;j<member;j++)
{
matrice[i][j]=i*j+1;
cout << setw(5) << matrice[i][j];
}
cout << "\n\n";
}
return 0;
}
int line=0,member=0;
int i,j,matrice[line][member];
This line shouldn't compile. In standard C++,
arrays of 0 size are not allowed
array sizes must be constant expressions
It appears that your compiler allows these as extensions. In any case when you later input line and member your array size doesn't change. You should define your array after you've input these numbers. But the array must be dynamically allocated (better yet, use vectors)
#include <vector>
//...
int line, member;
cin >> line >> member;
vector<vector<int> > matrix(line, vector<int>(member));
or if you don't want to use vector for educational purposes, do this:
int line, member;
int ** matrix;
cin >> line >> member;
matrix = new int*[line];
for(int i = 0; i < line; ++i)
matrix[i] = new int[member];
Don't forget to free the matrix.
for(int i = 0; i < line; ++i)
delete [] matrix[i];
delete [] matrix;
I suggest that you should read a good C++ book
HTH
The matrice array is initialized with a size of [0][0], which are the values of line and member. Since you override the values with the inputted values, the bounds used in the for loops are invalid.
i.e. You are accessing items out of the array's bounds.
You may want to use new to dynamically create arrays, or just use std::vector which resizes itself.
Also, it is not standard, but if your compiler supports it, you can use variable-length arrays. They behave like regular arrays but are allocated using a runtime-computed value :
int line=0,member=0;
int i,j;
cout << "\nLine: ";
cin >> line;
cout << "Member: ";
cin >> member;
int matrice[line][member];
You should also check for the inputted values, since C++ does not allows zero-size arrays (And it wouldn't make sense in your program anyway.)
You are using dynamic array without allocating memory using malloc or similar. That is in your line int i,j,matrice[line][member]; is not an array with constant size thus memory should be dynamically allocated. Or use a constant matix size as poster above suggested.
I agree with other comments that using vectors is a much safer way to solve your problem: using arrays directly is definitely error-prone. Of course, if your exercise requires using arrays, then you should use arrays.
Regarding the performance, I have written a small test using g++ on Ubuntu 10.04. Running
g++ --version
I get
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
My test program creates a 100x100 matrix and sets each element to some value. It first has a few declarations:
#include <vector>
#include <iostream>
#include "util.h" // Timer utilities.
#define LINE_COUNT (100) // The number of lines.
#define COL_COUNT (100) // The number of columns.
#define REPETITIONS (100000) // Number of repetitions for each test.
using namespace std;
Then I have the test using vectors:
void use_vectors()
{
int line = LINE_COUNT;
int member = COL_COUNT;
vector<vector<int> > matrix(line, vector<int>(member));
// Set data.
for (int i = 0; i < line; i++)
{
for (int j = 0; j < member; j++)
{
matrix[i][j] = -5;
}
}
}
Then I have a function to perform the same test (create matrix and set values) using arrays:
void use_arrays()
{
int line = LINE_COUNT;
int member = COL_COUNT;
int **matrix;
matrix = new int * [line];
for (int i = 0; i < line; i++)
{
matrix[i] = new int[member];
}
// Set data.
for (int i = 0; i < line; i++)
{
for (int j = 0; j < member; j++)
{
matrix[i][j] = -5;
}
}
for (int i = 0; i < line; ++i)
{
delete [] matrix[i];
}
delete [] matrix;
}
The main program repeats both tests, and records the time needed for each of them. Here is the main program:
main()
{
long int es = 0;
long int eu = 0;
start_timer();
for (int i = 0; i < REPETITIONS; i++)
{
use_vectors();
}
stop_timer();
es = elapsed_sec();
eu = elapsed_usec();
cout << "Vectors needed: " << es << " sec, " << eu << " usec" << endl;
start_timer();
for (int i = 0; i < REPETITIONS; i++)
{
use_arrays();
}
stop_timer();
es = elapsed_sec();
eu = elapsed_usec();
cout << "Arrays needed: " << es << " sec, " << eu << " usec" << endl;
}
The timer functions are based on the library function gettimeofday() (see e.g. http://linux.die.net/man/2/gettimeofday).
The result is the following:
Vectors needed: 24 sec, 624416 usec
Arrays needed: 10 sec, 16970 usec
So it seems that vectors do have some overhead wrt to arrays. Or can I do something to improve the performance of vectors? I checked my benchmark code a few times and it seems to me I got it right.
Anyway, I would by no means advise using arrays just to gain performance unless it really makes a big difference in your application.
You want to allocate memory dynamically.
Then, Use Dynamic allocation like this:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int line=0,member=0;
int i,j;
int **matrice; //Define matrice as a 2D array(a Matrix)
cout << "\nLine: ";
cin >> line;
cout << "Member: ";
cin >> member;
//start of dynamic allocation
matrice=new int*[line];
for (i=0;i<line;i++)
matrice[i]=new int[member];
//End of dynamic allocation
cout << "\nCreated Matrice: \n" << endl;
for (i=0;i<line;i++)
{
for (j=0;j<member;j++)
{
matrice[i][j]=i*j+1;
cout << setw(5) << matrice[i][j];
}
cout << "\n\n";
}
delete[] matrice; //Releasing allocated memory
return 0;
}