Unsure of the condition for this loop (Pointer arithmetic) - c++

So I'm supposed to edit a bunch of code via requirements in the comments. I've gotten most of it but one part in particular has me stuck. It loops through as the original did, but I can't figure out what the condition of the loop should be and whatever I put just ends up crashing. I think it's something with sizeof? but nothing I try works. Any help would be appreciated!
Original:
int main()
{
const string ID_BASE = "56-123-";
// CHANGE STATIC ARRAY INTO DYNAMIC ARRAY.
const int NUM_PRODUCTS = 5;
Product products[NUM_PRODUCTS];
int i;
//cout << "Enter number of toys: ";
//cin >> numProducts;
....Code to fill products...
//ALTER LOOP TO USE ONLY POINTER OPERATIONS
// (NO SUBSCRIPTS).
for (i = 0; i < numProducts; i++)
{
show(products[i]);
}
My changes:
int main()
{
const string ID_BASE = "56-123-";
// CHANGE STATIC ARRAY INTO DYNAMIC ARRAY.
int numProducts;
Product *products;
int i;
cout << "Enter number of toys: ";
cin >> numProducts;
products = new Product[numProducts];
...Code to fill products...
//ALTER LOOP TO USE ONLY POINTER OPERATIONS
// (NO SUBSCRIPTS).
for (Product *prodP = products; ; *prodP++)
{
show(*prodP);
}

Condition:
prodP !=products+numProducts;

Do it iterator style:
auto begin = products;
auto end = products + numProducts;
for( auto itr=begin; itr!=end; ++itr )
{
show(*itr);
}

Maybe I am missing something here, but when does the modified loop end??
for (Product *prodP = products; ; *prodP++)
{
show(*prodP);
}
there are only finite elements, and I think you are over-running the array.
Profile with valgrind for these kind of errors/suspected errors.

Related

Output numbers in reverse (C++) w/ vectors

I'm stuck for the first time on a lab for this class. Please help!
The prompt is:
Write a program that reads a list of integers, and outputs those integers in reverse. The input begins with an integer indicating the number of integers that follow. For coding simplicity, follow each output integer by a comma, including the last one.
Ex: If the input is:
5 2 4 6 8 10
the output is:
10,8,6,4,2,
2 questions: (1) Why does the vector not take user input unless the const int is included? (2) Why does the code not work in general? It seems to properly output, but with an error, and does not include the end line?
#include <iostream>
#include <vector>
using namespace std;
int main() {
const int MAX_ELEMENTS = 20;
vector<int> userInts(MAX_ELEMENTS);
unsigned int i;
int numInts;
cin >> numInts;
for (i = 0; i < numInts; ++i) {
cin >> userInts.at(i);
}
for (i = (numInts - 1); i >= 0; --i) {
cout << userInts.at(i) << ",";
}
cout << endl;
return 0;
}
Firstly, you need to specify the size because you are not using the vector's push_back functionality. Since you are only using at, you must specify the size ahead of time. Now, there's a few ways to do this.
Example 1:
cin >> numInts;
vector<int> userInts(numInts); // set the size AFTER the user specifies it
for (i = 0; i < numInts; ++i) {
cin >> userInts.at(i);
}
Alternatively, using push_back you can do:
vector<int> userInts; // set the size AFTER the user specifies it
for (i = 0; i < numInts; ++i) {
int t;
cin >> t;
userInts.push_back(t);
}
As for looping backwards, i >= 0 will always be true for unsigned numbers. Instead, you can use iterators.
for ( auto itr = userInts.rbegin(); itr != userInts.rend(); ++itr ) {
cout << *itr;
}
If you need to use indexes for the reverse loop, you can do:
for ( i = numInts - 1; i != ~0; --i ) { // ~0 means "not 0", and is the maximum value, I believe this requires c++17 or 20 though
cout << userInts.at(i);
}
with unsigned int i; the condition i >= 0 is always true. Eventually you will access an out-of-range element, which will throw std::out_of_range.
To answer your other question
std::vector userInts;
create a vector with no entries
userInts.at(i)
tries to access the (non existnat) ith entry.
You have 2 choices
create vector with a lot of empty etries
ask the vector to dynamically grow
The first one is what you did
const int MAX_ELEMENTS = 20;
vector<int> userInts(MAX_ELEMENTS);
Or you can do
userInts.push_back(x);
this will make sure there is enough space in the vector and add the new element to the end.

vector not producing expected output c++

I am creating an idea bank to hold ideas inputted from a keyboard or from a txt file.
the idea follows the following pattern
ID:
Proposer:
keywords:
content:
i am then implementing an indexing algorithm for the idea bank using reverted index using the following struct
struct Index {
string key;
vector<int> idList;
};
where key represents a keyword in an idea and idList represent the ID for the idea.
I am then storing the index in an AVL tree.
here is my code to to create the inverted index.
void IdeaBank::AVLTreeIndexing(){
vector<string> kwords_vec;
vector<int> relevantIDs;
int foundIdIn;
string kword;
Index input;
for (int loop = 0; loop < newIdea.size(); loop++){
kwords_vec = newIdea[loop].getKeyword();
for (int i = 0; i < kwords_vec.size(); i++){
// goes through all ideas
for (int j = 0; j < newIdea.size(); j++){
if (newIdea[j].foundWordInBoth(kwords_vec[i])){
input.key = kwords_vec[i];
input.idList.push_back(newIdea[j].getID());
tree.AVL_Insert(input);
relevantIDs.push_back(input.idList[j]);
}// end of lookfor
}
}// end of kwords.size loop
}
}
my logic behind the above function is the following:
1) go through all the ideas and get the keyword
2) check if an idea contains the keyword
3) store the word as a key in my struct and store the ID in my vector in the struct
4) insert the struct into my avl tree
i am then trying to create a search function to print all the ideas that contain the word in their keyword. and this is where i believe i am having problems.
here is the code
void IdeaBank::searchQueryFromBank(string word){
Index index;
vector <int> test;
if (tree.AVL_Retrieve(word, index)){
cout << "found in tree"<<endl;
cout << "Relevant idea ID's for "
<< word << ":" << endl;
for (int i = 0; i < index.idList.size(); i++){
cout << index.idList[i] << endl;
test.push_back(index.idList[i]);
}
}
else
{
cout << "No relevant ideas found for " << word << endl;
}
cout << endl;
cout << "displaying the following Ideas"<<endl;
for (int i=0;i<test.size();i++)
{
displayIdeaByID(test[i]);
}
}
the problem i am having:
my ID list vector is being populated with numbers that dont contain the keyword.
for example say i have the two following ideas
ID: 1
Proposer: bob
keywords: computer,laptop
content: computer with built in microphone
ID: 2
Proposer: bob
keywords: smartphone
content: smartphone with built in microphone
if i was to search for the keyword "smartphone"
my result would print the following ID's
ID 0...
ID 0...
ID 1...
in my indexing function, the function foundWordInBoth is defined as
bool Idea::foundWordInBoth(string word){
if (find(keyword.begin(), keyword.end(), word) != keyword.end()){
return true;
}
size_t pos;
pos = content.find(word);
if (pos != string::npos)
{
return true;
}
return false;
the above function checks to see if a word is found in either the keyword or in the contents of the idea.
overall, i am unsure why it is printing out Ideas that do not contain a certain keyword
I would guess that the problem is here
void IdeaBank::AVLTreeIndexing(){
vector<string> kwords_vec;
vector<int> relevantIDs;
int foundIdIn;
string kword;
Index input;
for (int loop = 0; loop < newIdea.size(); loop++){
kwords_vec = newIdea[loop].getKeyword();
for (int i = 0; i < kwords_vec.size(); i++){
// goes through all ideas
for (int j = 0; j < newIdea.size(); j++){
if (newIdea[j].foundWordInBoth(kwords_vec[i])){
input.key = kwords_vec[i];
input.idList.push_back(newIdea[j].getID());
tree.AVL_Insert(input);
relevantIDs.push_back(input.idList[j]);
}// end of lookfor
}
}// end of kwords.size loop
}
}
You only declare one Index object, which you then push back IDs to for the entire execution of the function. So the list of IDs just builds and builds.
I'm finding the logic a little hard to follow because you only ever seem to have one ID for each key but clearly you need to move the declaration of input to some narrower scope.
Maybe it should look something like this (but really I'm guessing)
void IdeaBank::AVLTreeIndexing() {
for (int loop = 0; loop < newIdea.size(); loop++) {
vector<string> kwords_vec = newIdea[loop].getKeyword();
for (int i = 0; i < kwords_vec.size(); i++) {
Index input;
input.key = kwords_vec[i];
// goes through all ideas
for (int j = 0; j < newIdea.size(); j++) {
if (newIdea[j].foundWordInBoth(kwords_vec[i])) {
input.idList.push_back(newIdea[j].getID());
}// end of lookfor
}
tree.AVL_Insert(input);
}// end of kwords.size loop
}
}
In general get used to declaring variables where you need them, instead of declaring them all at the beginning of a function.

How to reduce the execution time further?

I'm trying a problem for a contest.The requirement is as below.
Problem:
Input_format:
Output_expected:
My C++ code is:-
#include <iostream>
using namespace std;
int main() {
long long n,i,j,k=0,p,q;
cin>>n;//takes size of string//
char s[n];
cin>>s;
cin>>p;//Number of test cases//
for(i=0;i<p;i++)
{
cin>>q;//takes index to check till//
for(j=0;j<q-1;j++)
{
if(s[j]==s[q-1])//checks if characters are equal//
{
k++;//if yes then counts it//
}
}
cout<<k<<endl;
k=0;//makes cout 0 for next iteration//
}
return 0;
}
So it seems the code works for most of the cases but there's this time constraint that seems exceeding for some cases.What more can be done to reduce the time.Thanks in advance for taking time to read this.
Let's say we have an array cnt which stores the number of occurrences of each letter in the before the ith character of the string, for some i. We can easily update this array to include the ith character by simply incrementing the relevant element. So we'll iterate through the string updating this array, and at the ith iteration the cnt array will contain counts of every letter before index i.
Now, at the ith iteration, the information in the cnt array which would be useful for answering queries is cnt[s[i]], since that contains the number of occurrences of the character at index i in the part of the string preceding index i. We'll store this information in a[i], where a is some other array. So now a[i] is the number of occurrences of the letter at index i in all positions before i, which is exactly what we want for a query at index i. Therefore, we can now answer queries using the array.
Possible implementation:
#include <iostream>
#include <string>
#include <vector>
int main()
{
//read input
int n;
std::string s;
std::cin >> n >> s;
//iterate through string maintaining cnt array and adding relevant values to array a
int cnt[26] = { 0 };
std::vector<int> a;
a.reserve(n);
for (int i = 0; i < n; i++)
{
int c = s[i] - 'a';
a.push_back(cnt[c]);
cnt[c]++;
}
//answer queries
int q;
std::cin >> q;
for (int i = 0; i < q; i++)
{
int p;
std::cin >> p;
p--;
std::cout << a[p] << '\n';
}
}
First, this declaration:
long long n
cin>>n;//takes size of string//
char s[n];
Is non-standard. g++ supports it, but I don't believe variable sized arrays have made it into the C++ standard as it has for C. And I doubt you need long long as your index type unless you are scaling beyond 2 billion items.
Better:
int n;
cin>>n; //takes size of string
vector<char> s(n);
s is effectively the same as an array as for as accessing it at index locations with the [] operation.
Back to the solution:
Use a hash table that maps between a character and the number of occurrences of that character as you scan the s array once. Then use another array to keep track of how many times the character at that index was seen up to that point.
std::vector<int> positionCount(n);
std::unordered_map<char, int> table;
Insert your characters from s into the table and positionCount table as follows
for (int i = 0; i < n; i++)
{
char c = s[i];
// table[c] is the number of occurrences that "c" was seen in the input array so far
table[c]++;
// since table[c] is getting updated as we iterate,
// Keep track of the count of the char at position i in a separate array
positionCount[i] = table[c];
};
Then for each test case:
for(i=0;i<p;i++)
{
cin>>q; //takes index to check till
q--; // off by 1 fix since the array is described as 1..N
long result = positionCount[q];
result--; // off by 1 fix again since the output is the preceeding count and doesn't include the character at position q.
cout << result << endl;
}
All of the above is intuitively faster since there's no inner for loop. Hash table insertion and lookup is O(1) as is each array lookup.
And if you are into the whole brevity thing, you can simplify the above into this:
for (int i = 0; i < n; i++)
{
positionTable[i] = table[s[i]]++;
}
for(i=0;i<p;i++)
{
cin >> q;
cout << positionTable[q-1] << endl;
}

Zeros when printing out an array which is declared on the heap. C++

I want to make a program that lets the user insert some numbers to the array and the print it out afterwards. Problem is when I try to do that (lets say the size of my array is 100) then:
What it should do: Inserted- 1,2,3,4,5 -> should print 1,2,3,4,5
But instead it prints -> 1,2,3,4,5,0,0,0,0,0,0, .... up to the size of my array.
Is there any way I can get rid of those zeros?
Code:
int SIZE = 100;
int main()
{
int *numbers;
numbers = new int[SIZE];
int numOfElements = 0;
int i = 0;
cout << "Insert some numbers (! to end): ";
while((numbers[i] != '!') && (i < SIZE)){
cin >> numbers[i];
numOfElements++;
i++;
}
for(int i = 0; i < numOfElements; i++){
cout << numbers[i] << " ";
}
delete [] numbers;
return 0;
}
You increase numOfElements no matter what the user types. Simply do this instead:
if(isdigit(numbers[i]))
{
numOfElements++;
}
This will count digits, not characters. It may of course still be too crude if you want the user to input numbers with multiple digits.
Get numOfElements entered from user beforehand. For example
int main() {
int n;
cin >> n;
int * a = new int[n];
for (int i = 0; i < n; ++i)
cin >> a[i];
for (int i = 0; i < n; ++i)
cout << a[i] << endl;
delete[] a;
}
Input
4
10 20 30 40
Output
10 20 30 40
Since you declared array size, all indices will be zeros.
User input changes only the first x indices from zero to the value entered (left to right).
All other indices remains 0.
If you want to output only integers different from 0 (user input) you can do something like that:
for(auto x : numbers){
if(x!=0)cout<<x<<" ";
}
You can use vector and push_back the values from user input to get exactly the
size you need without zeros, then you can use this simple code:
for(auto x : vectorName)cout<<x<<" ";
Previous solutions using a counter is fine.
otherwise you can (in a while... or similar)
read values in a "temp" var
add if temp non zero
exit loop if counter >= SIZE-1 (you reach max slots)
increment counter
when You will print, form 0 to counter, you will get only non zero values.

Bug in selection sort loop

I need to make a program that will accept a input file of numbers(integer.txt) which will be sorted one number per line, into a vector, then use a selection sort algorithm to sort the numbers in descending order and write them to the output file (sorted.txt). I'm quite sure something is wrong in my selectionSort() function that is causing the loop not to get the right values, because after tested with cout I get vastly improper output. I'm sure it's a beginning programmer's goof.
vector<string> getNumbers()
{
vector<string> numberList;
ifstream inputFile ("integer.txt");
string pushToVector;
while (inputFile >> pushToVector)
{
numberList.push_back(pushToVector);
}
return numberList;
}
vector<string> selectionSort()
{
vector<string> showNumbers = getNumbers();
int vectorMax = showNumbers.size();
int vectorRange = (showNumbers.size() - 1);
int i, j, iMin;
for (j = 0; j < vectorMax; j++)
{
iMin = j;
for( i = j; i < vectorMax; i++)
{
if(showNumbers[i] < showNumbers[iMin])
{
iMin = i;
}
}
if (iMin != j)
{
showNumbers[j] = showNumbers [iMin];
}
}
return showNumbers;
}
void vectorToFile()
{
vector<string> sortedVector = selectionSort();
int vectorSize = sortedVector.size();
ofstream writeTo;
writeTo.open("sorted.txt");
int i = 0;
while (writeTo.is_open())
{
while (i < vectorSize)
{
writeTo << sortedVector[i] << endl;
i += 1;
}
writeTo.close();
}
return;
}
int main()
{
vectorToFile();
}
vectorRange defined but not used.
In your selectionSort(), the only command that changes the vector is:
showNumbers[j] = showNumbers [iMin];
Every time control reaches that line, you overwrite an element of the vector.
You must learn to swap two values, before you even think about sorting a vector.
Also, your functions are over-coupled. If all you want to fix is selectionSort, then you should be able to post that plus a main that calls it with some test data and displays the result, but no, your functions all call each other. Learn to decouple.
Also your variable names are awful.