I'm trying to write a function called func1 that can shuffle a given deck of cards (an array) uniquely, given two other decks, the starting deck and the resulting deck. For example, a deck of cards [1, 2, 3, 4, 5] is shuffled and produces another deck of cards [4, 5, 2, 1, 3]. I want to complete this same shuffle (putting the card in slot 0 into slot 3, the card in slot 1 into slot 2, etc), but this time on another deck of cards [2, 3, 1, 5, 4]. It should print out [5, 4, 3, 2, 1] if I wrote the code correctly. Although it runs the program, it only prints the first "card" correctly, and the rest are really big numbers. What did I do wrong? Am I using the correct approach, or should I rethink my design?
#include <iostream>
using namespace std;
int * func1(int *deck) // A unique shuffle given two decks, a starting and ending deck (in this case, "start" and "shuff1")
{
int start[5] = { 1,2,3,4,5 }; // Starting deck
int shuff1[5] = { 4,5,2,1,3 }; // Resulting deck after shuffle. This is the specific type of shuffle that we are copying
int finish[5] = {}; // The deck that we are returning
for (int i = 0; i < 5; i++) // Looks at a specific spot (i) in the start deck...
{
for (int j = 0; j < 5; j++) // Looks through all the spots (j) in the shuff1 deck...
{
if (start[i] == shuff1[j]) // And if the cards themselves are identical, then it takes the ith card
{ // in the given deck and puts it in the jth spot in the finish deck
int temp = deck[i];
finish[j] = temp;
j = 5;
}
}
}
return finish;
}
int main()
{
int test[5] = { 2,3,1,5,4 }; // Given deck
int* shuff2 = func1(test); // Calls a specifc shuffle and sets it equal to a deck called shuff2
for (int i = 0; i < 5; i++)
{
cout << shuff2[i] << endl; // Prints shuff2
}
return 0;
}
Your func1 returns a pointer to finish, which is a variable local to the function. When control passes out of the function, that variable passes out of scope-- you could say it expires. So the pointer points to a spot in the wilderness of invalid memory, and dereferencing the pointer (e.g. by shuff2[i]) causes undefined behavior, which means strange numbers if you're lucky.
One solution is to have func1 construct finish on the heap. Another is to have the function accept a pointer to the array which it should fill with shuffled values; the calling code (e.g. main) would be responsible for providing a pointer to a valid array.
Your main problem is that you are returning a pointer to a variable allocated on the stack, which you can't do. Pass a pointer to "finish" as a second argument instead.
I'm not sure if I am following the way you described the proposed algorithm very well, but I think you would want to create an array of offsets, like this:
void func1(int *deck, int *finish) {
int offsets[5] = {3, 1, 2, -3, -3};
for (int i = 0; i < 5; ++i) {
finish[i + offsets[i]] = deck[i];
}
}
or put the actual destination indexes into the array:
void func1(int *deck, int *finish) {
int desti[5] = {3, 2, 4, 0, 1};
for (int i = 0; i < 5; ++i) {
finish[desti[i]] = deck[i];
}
}
Though you did specifically say "using two for loops" so maybe I'm misunderstanding the way you described the algorithm.
Related
I don't have any idea about this syntax int *count = new int[sizeof(int)* (size - 2)]
What kind of array that will create.
I thought they are trying to create map like structure. But how does it work?
#include <bits/stdc++.h>
using namespace std;
void printRepeating(int arr[], int size)
{
int *count = new int[sizeof(int)*(size - 2)];
int i;
cout << " Repeating elements are ";
for(i = 0; i < size; i++)
{
if(count[arr[i]] == 1)
cout << arr[i] << " ";
else
count[arr[i]]++;
}
}
// Driver code
int main()
{
int arr[] = {4, 2, 4, 5, 2, 3, 1};
int arr_size = sizeof(arr)/sizeof(arr[0]);
printRepeating(arr, arr_size);
return 0;
}
// This is code is contributed by rathbhupendra
Finding duplications in an array is of course a solved problem. IMHO a very simple solution is:
sort the array use std::sort()
use a loop to check if an element is equal to it's successor, ie. for(int i = 1; i < num_elements; i++){ if(arr[i-1]==arr[i]){...duplicate!...}}
This requires O(n) memory and O(n*log(n)) time, so it's quite ok. You can also use a hashmap, but that's pretty much the same.
Anyways, to your question(s):
int *count = new int[sizeof(int)* (size - 2)];
This is incorrect. I assume it used to be this C code:
int num_elements = size-2; // we want size-2 elements (not sure why)
int total_bytes = sizeof(int) * num_elements;
int *count = calloc(total_bytes); // reserve space, and set to 0
Which one could translate to this C++ code:
int num_elements = size-2;
int * count = new int[num_elements]{0}; // alloc and set to zero
So the person who did the port misunderstands fundamentals about C++.
Let's dig further.
For the sake of it, the problem formulation appears to be:
You are given an array of n+2 elements. All elements of the array
are in range 1 to n. And all elements occur once except two
numbers which occur twice. Find the two repeating numbers
I have made tiny changes to make the solution less crazy, and I've added annotations.
// #include <bits/stdc++.h> is a bad choice.
// This includes _EVERYTHING_ in C++,
// but it only works in GCC afaik. For this particular
// case we just need cout, so:
#include <iostream>
// using the std namespace like this spills function calls like crazy in the global namespace.
// it is both, conventient and "not too bad" (imho) in cpp files,
// but never ever do this in .h files where it affects multiple cpp files.
using namespace std;
void printRepeating(int arr[], int size)
{
// create a new array of size-2 and set to zero
int *count = new int[(size - 2)]{0};
int i;
cout << " Repeating elements are ";
// loop all elements
for(i = 0; i < size; i++)
{
int value = arr[i];
// increase the count for `value`
// note that if value<=0 or value>size-2,
// then the program will crash!
// the problem description is contrived, but it does
// state that all values need to be >0 and <=size-2,
// so this next array access is fine!
count[value-1]++;
// we still have to subtract 1, because C arrays start
// at index 0, but our problem description says we start at 1.
// we could also create an array of size-1 and
// "ignore" the first position in count[0] (it would never get used!)
// if the element appears the second time...
if(count[value-1] == 2){
// then print it
cout << value << " ";
// btw: if you check with count[value-1]==2, then only
// the first duplicate is printed.
// you could compare with count[value-1]>=2 then all
// repeating elements are printed repeatetly.
}
}
// free up the memory. we allocated with `new[]`
// so we also have to use `delete[]`
delete [] count;
}
// Driver code
int main()
{
int arr[] = {4, 2, 4, 5, 2, 3, 1};
// next line is a standard trick.
// a single int consumes 4bytes (typically),
// the array will have size 7*4=28 bytes, so sizeof(arr)=28
// the first element is an int, so sizeof(arr[0]) = 4
// so sizeof(arr)/sizeof(arr[0]) = 7
// c and c++ don't have arr.length like java,etc., that's
// why under certain circumstances this "trick" is used.
int arr_size = sizeof(arr)/sizeof(arr[0]);
// call the function
printRepeating(arr, arr_size);
return 0;
}
// This is code is contributed by rathbhupendra.
// Maybe fixed and annotated by hansi:)
I hope this helps you and answers some questions. Good luck with your C++ adventures!
I have a simple program to add an element to an array:
void printArray(int inp[], int size)
{
cout << "[";
for (int i = 0; i < size - 1; i++)
{
cout << inp[i] << ", ";
}
cout << inp[size - 1] << "]" << endl;
}
int addElement(int inputArray[], int inputSize, int element, int atIndex)
{
int cur = inputSize;
while (cur >= 0)
{
if (cur == atIndex)
{
inputArray[cur] = element;
return inputSize + 1;
}
inputArray[cur] = inputArray[cur - 1];
cur--;
}
return inputSize + 1;
}
int arr1[] = {1, 5, 9, 2};
int arr2[] = {1, 5, 9, 2};
int main()
{
int arraySize = sizeof(arr1) / sizeof(arr1[0]);
addElement(arr1, arraySize, 7, 0);
printArray(arr1, arraySize + 1);
printArray(arr2, arraySize);
return 0;
}
This outputs:
[7, 1, 5, 9, 2] [2, 5, 9, 2]
Even though I haven't touched arr2 it is modified. I think because arr1 and arr2 are allocated contiguously in memory, and naively adding an element to arr1 overwrites arr2[0].
How should I handle this case and add only if the next space is unused, otherwise move the entire array to another location?
You can achieve this easily by using std::vector.
It has a method called insert, where you just pass a position and a number as arguments and it will handle the reallocation by itself.
For example: if you write:
vector<int> vec = { 1, 2, 3, 4, 5 };
vec.insert(vec.begin() + 2, 100);
Now elements in your vector are 1, 2, 100, 3, 4, 5.
I don't know if this will help you, but you can also add multiple elements at once:
vector<int> vec = { 1, 2, 3, 4, 5 };
vec.insert(vec.begin() + 3, { 100, 101 });
Now elements in your vector are: 1, 2, 3, 100, 101, 4, 5.
As you can see, the first argument is the position of the first inserted element and the second one is element or list of elements that you want to insert.
You can read more about std::vector here and about std::vector::insert here
Hope this helps.
As what the comments mentioned by #StoryTeller, you can use a std::vector.
But you have to pick on which function of the container you wanna use, there are 2 types.
::insert, which inserts data on the specific location in the
container. This is iterator based.
::push_back, which inserts at the back/last of the container
You can use any of them, depending on your purpose, just be sure of ::insert that you are pointing to the correct position(iterator wise).
Also, as of C++11 you can use ::emplace and ::emplace_back, which constructs and inserts data. You can find more at,
http://www.cplusplus.com/reference/vector/vector/
Hope this helps.
I have a simple program to add an element to an array:
Impossible. An array's size is fixed at compile time. In other words,
int arr1[] = {1, 5, 9, 2};
is a lot like:
int arr1_1 = 1;
int arr1_2 = 5;
int arr1_3 = 9;
int arr1_4 = 2;
I think it is helpful, for learning purposes, to view an array like this, and not like a container which can shrink and grow while the program is running. Adding an element to an array at runtime would be like asking to add a variable at runtime. C++ arrays don't work like that.
You can use new[] to set an array's initial size at runtime, but even then you cannot "add" anything. In fact, don't use new[], ever.
Go to cppreference.com, learn about std::vector and relearn everything from scratch. Start with the example code at the bottom of the page.
I'm writing class that manages dynamic array of objects. Right now I got stuck on method that should insert element at given index, but before it checks if that index isnt bigger than array capacity. Then it should resize array first.
template <class T>
void MyVector<T>::insertAt(int index, const T &m_element) {
if(p_size == p_capacity) extendArray();
if(index >= p_capacity) extendArray(index);
p_size++;
p_array[index] = m_element;
}
template <class T>
void MyVector<T>::extendArray(int new_capacity) {
std::unique_ptr<T[]> temp_array = std::make_unique<T[]>(new_capacity);
for (int i = 0; i <= p_size; i++) {
temp_array[i] = p_array[i];
}
p_array.reset();
p_array = std::make_unique<T[]>(new_capacity);
for (int i = 0; i <= p_size; i++) {
p_array[i] = temp_array[i];
}
}
extendArray()just extends array capacity 2 times, extendArray(int) extends array capacity to the number given by the index. First method works fine, second not so really.
int main(){
MyVector<int> test;
test.insertAt(0, 5);
test.insertAt(1, 3);
test.insertAt(2, 1);
test.insertAt(6, 11);
cout <<"Size " << test.getSize() << "\n";
for(int i = 0; i < test.getCapacity(); i++) {
cout << test.get(i) << ", ";
}
}
Id expect something like 5, 3, 1, 0, 0, 0, 11, 0
But I get just 5, 3, 1, 0 so it never extends array but it increases size (number of elements).
You did not post your extendArray() function but even though you say it's a copy of extendArray(int) first seems to be updating p_capacity when the latter you provided doesn't.
Fixing that would gain you couple of extra zeros in the output 5, 3, 1, 0, 0, 0 since you extending only to the index, not to the index+1. Furthermore, in insertAt(int index, const T &m_element) you are incrementing the p_size, instead of assigning it to index+1
Extending to p_size+1 and fixing the p_size assignment, prints 5, 3, 1, 0, 0, 0, 11 and I am not quite sure how you came to the conclusion that it should have an extra trailing 0 as p_capacity ends up being 7, regardless if the initial value is 1, 2 or 4 as in the code snippet I put a link to.
I also noticed couple of bugs I without looking too close: your loops shouldn't go to the p_size, but rather to p_size-1, so instead for (size_t i = 0; i <= p_size; i++) it should be for (size_t i = 0; i < p_size; i++)
I would also suggest using unsigned int (or size_t) instead of int for indexing as that allows to get compiler warnings when you do something which potentially can result in a negative index.
Lastly, you should be able to use unique_ptr::swap to avoid two allocations in extendArray(..).
Good luck with learning!
Suppose I have an array: int list[] = {1, 2, 4, 5, 6};
and I want to shift the array from the middle to the right and place 3 in the place of 4 so it would look like: {1, 2, 3, 4, 5, 6}.
How would I do it?
If you can use the C++ Standard Library, then std::vector is a replacement for arrays. It has a dedicated method insert to do what you want:
std::vector<int> v;
... // add elements 1, 2, 4, 5, 6 to it
v.insert(v.begin() + 2, 3); // insert 3 at position 2
This is good if you know where to insert your new element. However, it seems that your list should always be sorted, and you want to insert the new element so it remains sorted. If so, you better use std::multiset:
std::multiset<int> v;
... // add elements 1, 2, 4, 5, 6 to it
v.insert(3); // insert 3
Here, you don't need to tell where to insert the new element.
If you cannot use vector, one solution is:
Create an array with a lot of space (with a few empty positions at the end);
int * array = malloc(sizeof(int) * array_size);
Use two variables one to save the size of the array (lets called size) another to count the number of elements already added (lets called number_of_elements_in_the_array)
When you added an element at the position 'x', you do the following (with x < size of the array):
int tmp = array[x]; // save the current value
array[x] = new_value; // update with the new value
int tmp2;
number_of_elements_in_the_array++;
// we reach the limited
if(number_of_elements_in_the_array == size)
{
size = 2 * size; //lets double that size
int *new_array = malloc(sizeof(int) * size);
// copy the first elements
for(int i = 0; i <= x; i++)
new_array[i] = array[i];
new_array[x+1] = tmp;
// copy the last elements
for(int i = x+1; i < number_of_elements_in_the_array; i++)
new_array[i+1] = array[i];
free(array) // free the old space
array = new_array; // update the new pointer
}
else
{
// shift the remaining elements
for(int i = x+1; i < number_of_elements_in_the_array; i++)
{
tmp2 = array[i];
array[i] = tmp;
tmp = tmp2;
}
}
when you reach the limited, create a new array with more memory, copy from the old array to the new one, and update the variables number_of_elements_in_the_array and size accordingly.
Disclaimer : I didn't tested, thus it might be some minor erros, but the overall ideia is there.
I'm teaching myself C++ and doing a problem from a textbook. So far I have covered the basics such as data types, declarations, displays, assignment, interactive input, selection (if-else), and repetition (for/while loops...), functions and arrays. I have NOT done anything with pointers, but I know what they are...
I came across this problem:
The answers to a true-false test are as follows: T T F F T. Given a two-dimensional answer array, in which each row corresponds to the answers provided on one test, write a function that accepts the two-dimensional array and number of tests as parameters and returns a one-dimensional array containing the grades for each test. (Each question is worth 5 points so that the maximum possible grade is 25.) Test your function with the following data:
My understanding is that C++ functions cannot return arrays--At least this is what I read on other posts on this forum. Is this correct? If so, how are they expecting you to do this problems because I haven't covered pointers yet. The only other way I thought MIGHT be possible is by passing in the array by reference.... but the question stem only says there are 2 arguments to the function so I thought maybe that method was ruled out. That method would require a third argument which is the array your modifying so its implicitly returned.
I have some code, but its not correct (only my calcgrade function needs work) and I'm not sure how to move forward.Could someone please advise? Thank you!!
#include<iostream>
// Globals
const int NROW = 6, NCOL = 5;
bool answers[NCOL] = {1, 1, 0, 0, 1};
bool tests[][NCOL] = {1, 0, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 0, 0, 1,
0, 1, 0, 0, 0,
0, 0, 0, 0, 0,
1, 1, 0, 1, 0};
int grade[NROW] = {0};
// Function Proto-Types
void display1(bool []);
void display2(bool [][NCOL]);
int calcgrade(bool [][NCOL], int NROW);
int main()
{
calcgrade(tests, NROW);
display2(tests);
return 0;
}
// Prints a 1D array
void display1(bool answers[])
{
// Display array of NCOL
for(int i = 0; i < NCOL; i++)
std::cout << std::boolalpha << answers[i] << std::endl;
return;
}
// Print 2d Array
void display2(bool answers[][NCOL])
{
// Display matrix: 6x5
for(int i = 0; i < NROW; i++)
{
for(int j= 0; j < NCOL; j++)
{
std::cout << std::boolalpha << answers[i][j] << std::endl;
}
std::cout << std::endl;
}
return;
}
int calcgrade(bool tests[][NCOL], int NROW)
{
for(int i = 0; i < NROW; i++)
{
for(int j = 0; j < NROW; j++)
{
if(tests[i][j]==answers[j])
grade[i] += 5;
}
printf("grade[%i] = %i", i, grade[i]);
}
return grade;
}
Try to use std::vector.
Vectors are sequence containers representing arrays that can change in size.
You can do so:
vector<bool> function()
{
vector<bool> vec;
vec.push_back(true);
vec.push_back(false);
vec.push_back(true);
return vec;
}
If you're passing the number of tests as the second parameter, it means you actually know the number of tests, so you don't need to use a vector. You can return an dynamically allocated array (either using new or malloc).
The code would look like this:
int* calcgrade(bool tests[][NCOL], int NROW){
int* array = new int[NROW];
for(int i=0;i<NROW;i++)
array[i] = calculatedGrade;
return array;
}
You can:
as you said, return pointer to dynamically allocated array,
you can make structure type with word struct that includes static array, read more on C++ Reference and return/take as argument structure of your type.
Another way of doing this would be to create the Answer array in your main function, then pass it along with the T/F array to your grading function. Then, your grading function could operate on the Answer array, and wouldn't even need to return anything.
Essentially, when you pass arrays in functions, you're actually passing pointers to the arrays, and thus you can operate on them as if they were passed by reference (which they were).
semi-pseudocode ex:
void getGrades( const int answerVector, int gradeVector ) {
// code that computes grades and stores them in gradeVector
}