Sorting a vector of structs in C++ - c++

I have a problem. The statement says that the results at a contest are read from standard input and I have to print to the screen the final standings in decreasing order by the number of solved problems. Here is my code.
#include <cstdio>
#include <vector>
#include <cstdlib>
using namespace std;
struct results
{
unsigned int id; //id of the team
unsigned int m; //number of solved problems
};
int comparare(const void * i, const void * j) //compare function for qsort()
{
return -( *(unsigned int*)i - *(unsigned int*)j );
}
int main()
{
unsigned int n;
vector<results> standings; //initializing an array of structs
scanf("%u", &n); //the size of the vector
for(unsigned int i=0; i<n; ++i)
{
scanf("%u%u", &standings[i].id, &standings[i].m); //reading the elements
standings.push_back(results());
}
qsort(standings, n, sizeof(results), comparare); //sorting the array
for(unsigned int i=0; i<n; ++i)
printf("%u %u\n", standings[i].id, standings[i].m); //print the sorted array
return 0;
}
When I want to compile the code, the compiler finds the error
cannot convert 'std::vector' to 'void*' for argument '1' to 'void qsort(void*, size_t, size_t, __compar_fn_t)'
in the line qsort(standings, n, sizeof(results), comparare);
What I have to do to repair this?

If you absolutely must use qsort on a vector (and you don't. And shouldn't), then you have to pass it like this:
qsort(standings.data(), standings.size(), sizeof(results), comparare);
vector::data fetches a pointer to the array stored in the vector. Simply passing a pointer to the vector itself will not help.
Note that vector::data requires C++11; use &vector[0] if data is not available to you.
But really, just use std::sort:
std::sort(standings.begin(), standings.end(), [](const results &lhs, const results &rhs) {return lhs.id < rhs.id;});
Obviously the lambda requires C++11; feel free to use a namespace-declared struct for earlier C++ versions.

You're using C constructs, but should be using more C++ constructs. std::sort is faster than qsort generally and it's usage is much more intuitive. Here's how you can rewrite it without C++11.
#include <iostream>
#include <vector>
#include <algorithm>
struct results {
unsigned int id; //id of the team
unsigned int m; //number of solved problems
};
// I guess you're trying to sort on number of solved problems. If not, change `.m` to `.id`
bool comparare(const results lhs, const results rhs) {
return lhs.m > rhs.m;
}
int main() {
size_t n;
std::cout << "Enter number of results: " << std::endl;
std::cin >> n;
std::vector<results> standings(n); // Creates std::vector of results with n elements
// read in id and number of problems solved
for(size_t i=0; i < n; ++i) {
std::cin >> standings[i].id >> standings[i].m;
}
// sort the array
std::sort(standings.begin(), standings.end(), comparare);
// output the sorted array's id
for(size_t i = 0; i < standings.size(); ++i) {
std::cout << "In " << i+1 << " place: " << standings[i].id << " with " << standings[i].m << " problems solved." << std::endl;
}
return 0;
}
Here's the ideone with an example.

Your comparison function comparare is not appropriate if the values can exceed INT_MAX. For example comparing UINT_MAX and 0 will cause an overflow when returning UINT_MAX - 0 as an int. It is undefined behavior and on common platforms it will actually be negative.
Use this comparison function instead:
//compare function for qsort()
int comparare(const void *i, const void *j) {
unsigned int ni = *(unsigned int*)i;
unsigned int nj = *(unsigned int*)j;
return (ni > nj) - (ni < nj);
}
It returns -1, 0 or 1 if *i is respectively smaller than, equal to or greater than *j.
In C++ there are other more idiomatic ways to sort an array.

Related

Can we pass an array to any function in C++?

I have passed an array of size 10 to a funtion to sort the array reversely, but it's going wrong after rightly sorting first five elements of the array.
I want to sort the array 'std' reversely here,
# include <iostream>
using namespace std;
int reverse(int a[]); //funtion prototype
int main()
{
int std[10] = {0,1,2,3,4,5,6,7,8,9};
reverse(std);
}
int reverse(int a[]) //funtion defination
{
int index = 0;
for (int i = 9; i >= 0; i--)
{
a[index] = a[i]; //swaping values of the array
cout << a[index] << " ";
index++;
}
}
There's basically three things wrong with your code.
You aren't swapping anything
You have to swap the first half of the array with the second half, not swap the whole array. If you do that then everything gets swapped twice, so that nothing changes
You should print the reversed array after you have finished the reverse, not while you are doing the reverse.
Here's some code that fixes all these problems
# include <iostream>
# include <utility>
void reverse(int a[]);
int main()
{
int std[10] = {0,1,2,3,4,5,6,7,8,9};
reverse(std);
// print the array after reversing it
for (int i = 0; i < 10; ++i)
std::cout << std[i] << ' ';
std::cout << '\n';
}
void reverse(int a[])
{
for (int i = 0; i < 5; ++i) // swap the first half of the array with the second half
{
std::swap(a[i], a[9 - i]); // real swap
}
}
Yes you can.
I usually don't use "C" style arrays anymore (they can still be useful, but the don't behave like objects). When passing "C" style arrays to functions you kind of always have to manuall pass the size of the array as well (or make assumptions). Those can lead to bugs. (not to mention pointer decay)
Here is an example :
#include <array>
#include <iostream>
// using namespace std; NO unlearn trhis
template<std::size_t N>
void reverse(std::array<int, N>& values)
{
int index = 0;
// you only should run until the middle of the array (size/2)
// or you start swapping back values.
for (int i = values.size() / 2; i >= 0; i--, index++)
{
// for swapping objects/values C++ has std::swap
// using functions like this shows WHAT you are doing by giving it a name
std::swap(values[index], values[i]);
}
}
int main()
{
std::array<int,10> values{ 0,1,2,3,4,5,6,7,8,9 };
reverse(values);
for (const int value : values)
{
std::cout << value << " ";
}
return 0;
}

Initialize all elements in matrix with variable dimensions to zero

I'm trying to initialize an int matrix in C++, with user-inputted dimensions, with every element set to zero. I know there are some elegant ways to do that with a one-dimensional array so I was wondering if there are any similar ways to do it with a two-dimensional array without using for loops and iterating through every element.
I found a source that gave several different ways, including std::fill (I've modified the code so that the dimensions are read with cin):
#include <iostream>
using namespace std;
int main() {
int x;
cin >> x;
int matrix[x][x];
fill(*matrix, *matrix + x * 3, 0);
for (int i = 0; i < x; i++) {
for (int j = 0; j < 3; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
}
But why does this work, and why would the pointer to the matrix in the arguments for fill be necessary if it's not necessary for a one-dimensional array? That source said it was because matrixes in C++ are treated like one-dimensional arrays, which would make sense, but that is why I don't understand why the pointer is needed.
I don't know if this is relevant, but in case it can help, I've described my previous attempts below.
At first I thought I could initialize all elements to zero like in a one-dimensional array. For the matrix, this worked fine when the side lengths were not read with cin (i.e. when I declared the matrix as int matrix[3][3] = {{}}; as answered here) but when I tried getting the side lengths from cin I started getting errors.
This was my code:
#include <iostream>
using namespace std;
int main() {
int x;
cin >> x;
int matrix[x][x] = {{}};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
}
And when I tried to compile it, it threw this error:
matrix_test.cpp:7:14: error: variable-sized object may not be initialized
int matrix[x][x] = {{}};
^
1 error generated.
Why you're getting the error
c-style arrays (such as int matrix[3][3]) must have size specified at the point you declare it. They can't vary in size in C++.
What you could do instead.
If you use std::vector, there's a really elegant way to do it:
#include <vector>
#include <iostream>
int main() {
using namespace std;
int x;
cin >> x;
auto matrix = vector<vector<int>>(x, vector<int>(x, 0));
// This is how we can print it
for(auto& row : matrix) {
for(auto& elem : row) {
cout << elem << ' ';
}
cout << '\n';
}
}
In C++17, you can shorten this even further:
auto matrix = vector(x, vector(x, 0));
What vector(number, thing) means is "Create a vector of number, where each element is thing".
The second dimension of two-dimension array must be a compile time constant, but in your code x is not.
Actually if you write a function with a two-dimension parameter, the second dimension must also be a compile time constant. That's because the array is stored linearly in the memory and the compiler must know the second dimension to calculate the offset correctly.

How to sort an array of structures according to the value of an included pointer

my aim is to sort an array of structures. The structure contains the index of a customer {1,..., number} and a pointer to a value of an other sturcture,
e.g,
for (int i = 1; i < no_orders+1; i++){
sorting_array[i].index_order = i;
sorting_array[i].some_vaule = &order_data[i].some_value;
}
Here, order_data is an array of structures contains all customer data which allows for directly accessing variable data a customer the index. The array sorting_array is the one to sort according to a value in order_data; therefore the pointer in DATA_TO_SORT in order to avoid copying effort since this function is called millions of times (same indices, changed values).
The actual problem appears with the sorting function. If I do not use the pointer but the real value (int some_value, including copying effort however), sorting works as it should.
Defining some_value as pointer, std::sort terminates after some seconds without any feedback the whole program. The actual question is why and what may I change.
struct DATA_TO_SORT {
int index_order;
int *some_value;
};
bool compare_by_val( DATA_TO_SORT &a, DATA_TO_SORT &b) {
return *a.some_value > *b.some_value;
}
void sort_acc_release() {
std::sort(sorting_array.begin() + 1, sorting_array.end(), compare_by_val);
}
Also tried the following from a related topic, however, the depicted error statement occurs - besides several similar error statements.
std::sort(sorting_array.begin() + 1, sorting_array.end(), [&](size_t a, size_t b) {return *sorting_array[a].some_value > *sorting_array[b].some_value; });
<lambda_0a6c4bdbc69eba5706031ee8a4b875c6>::operator ()(::size_t,::size_t) const" : Konvertierung von Argument 1 von "DATA_TO_SORT" in "::size_t" nicht möglich Algorithm ...\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\xutility 1017
Minimum Example which WORKS.
#include <iostream>
#include <cstdlib> //rand
#include <algorithm> //swap etc
#include <array> //array
struct OTHER_DATA {
int other_data;
};
struct DATA_TO_SORT {
int index_order;
int *some_value;
};
bool compare_by_val(DATA_TO_SORT &a, DATA_TO_SORT &b) {
return *a.some_value > *b.some_value;
}
int main() {
const int max_no = 10;
std::array<OTHER_DATA, max_no> some_other_values;
std::array<DATA_TO_SORT, 10> sorting_array;
for (int i = 0; i < some_other_values.size(); i++)
{
some_other_values[i].other_data = i * 5;
sorting_array[i].index_order = i;
sorting_array[i].some_value = &some_other_values[i].other_data;
}
for (int i = 0; i < sorting_array.size(); i++)
{
std::cout << "\n" << sorting_array[i].index_order << "\t" << *sorting_array[i].some_value;
}
std::sort(sorting_array.begin(), sorting_array.end(), compare_by_val);
for (int i = 0; i < sorting_array.size(); i++)
{
std::cout << "\n" << sorting_array[i].index_order << "\t" << *sorting_array[i].some_value;
}
system("pause");
return 0;
}
Thank you in advance for your problem-related and well-intentioned answers!

Finding minimum and maximum in a array c++

I have to find the minimum and maximum value of elements in a array using divide and conquer. I have written a code but it is not working for more then 6 elements in array. I don't know whats the problem
#include<iostream>
using namespace std;
int minimum=999,maximum,mi,ma;
void result(int mi,int ma)
{
if(maximum<ma)
{
maximum=ma;
}
if(minimum>mi)
{
minimum=mi;
}
}
void maxmin(int arr[],int i,int j)
{
cout<<" i ="<<i<<" j= "<<j<<endl;
if(i==j)
{
mi=ma=arr[i];
result(mi,ma);
}
else if(i==j-1)
{
if(arr[i]>arr[j])
{
ma=arr[i];
mi=arr[j];
}
else
{
mi=arr[i];
ma=arr[j];
}
result(mi,ma);
}
else
{
int mid=i+j/2;
maxmin(arr,i,mid);
maxmin(arr,mid+1,j);
}
}
int main()
{
int arr[10],n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>arr[i];
}
maxmin(arr,0,n-1);
cout<<" max "<<maximum<<" min "<<minimum<<endl;
return 0;
}
Your code has a few mistakes
Your code reads n from the user input, but you provided only 10 sized array, and user can try to input 10+ numbers, so we will have an undefined behavior in that case.
You write it very bad and unreadable. If you want somebody else to read your code, check in the your favourite book or in the internet information about how to write beautiful and readable code.
You implemented that algorithm yourself. It is a bad habit, use the standard library algorithms and you will not encounter such mistake.
.
#include <iostream> // std::cin, std::cout
#include <cstddef> // std::size_t
#include <algorithm> // std::min_element, std::max_element
int main ()
{
std::size_t array_size;
std::cin >> array_size;
int *some_array = new int[array_size]; // Allocate memory dynamically
for(std::size_t i = 0; i < array_size; ++i)
{
std::cin >> some_array[i];
}
/* Standard library operate on iterators, they are special classes
* that have interface that is similar in many cases to pointers (so we can use pointers as iterators).
* std::min/max_element needs one iterator for the sequence beginning
* and one iterator after the end. It returns iterator to a found element.
*/
int min = *std::min_element(some_array, some_array + array_size);
int max = *std::max_element(some_array, some_array + array_size);
delete[] some_array;
std::cout << "Min = " << min << std::endl << "Max = " << max;
std::cout << std::endl;
}
Code isn't well written and first dry run your code, you will find the problem easily.
Change
else
{
int mid=i+j/2;
maxmin(arr,i,mid);
maxmin(arr,mid+1,j);
}
To
else
{
int mid=(i+j)/2; /*** Adding brackets ***/
maxmin(arr,i,mid);
maxmin(arr,mid+1,j);
}
And check the logic for calling the result function (because according to your logic the two subsets are individually calculating MIN and MAX in itself not in whole array)

C++ Program Apparently Printing Memory Address instead of Array

#include <iostream>
using namespace std;
int main(){
int findMax(int *);
const int MAX = 100;
int values[MAX];
char ivals[256];
// Get the space-separated values from user input.
cin.getline(ivals, 256, '0');
char *helper;
// Clean input array and transfer it to values.
for(int i = 0; i < (MAX) && ivals[i] != 0; i++){
helper = ivals[i * 2];
values[i] = atoi(helper);
}
int mval = findMax(values);
cout << values << endl << mval;
return 0;
}
//Function to find the maximum value in the array
int findMax(int arr[]){
int localmax = 0;
for(int i = 0; i < (sizeof(arr)/sizeof(int)); i++){
if(arr[i] > localmax){
localmax = arr[i];
}
}
return localmax;
}
The purpose of this program is for the user to input a space-separated series of values ended by a 0. That array is then to be analyzed to find the max. I figured out how to convert what is originally a char[] into an int[] so that I can use the findMax() function on it without error but the sorting loop seems to have a problem of its own and when "cout << values << endl << mval;" is called, it returns only a memory address instead of what should be a non-spaced sequence of ints. Can anybody explain what I am doing wrong? It seems that I may have made some mistake using the pointers but I cannot figure out what.
Printing values won't print the contents of the array as you expect, it will print the memory location of the first element of the array.
Try something like this instead:
#include <iterator>
#include <algorithm>
// ...
copy(&values[0], &values[MAX], ostream_iterator(cout, " "));
Sorry I can't post actual working code, but your original post is a mess with many syntax and syntactic errors.
EDIT: In the interest of being more complete and more approachable & understandable to beginners, I've written a small program that illustrates 4 ways to accomplish this.
Method 1 uses copy with an ostream_iterator as I've done above.
Method 2 below is probably the most basic & easiest to understand.
Method 3 is a C++0x method. I know the question is tagged C++, but I thought it might be educational to add this.
Method 4 is a C++ approach using a vector and for_each. I've implemented a functor that does the dumping.
Share & Enjoy
#include <iostream>
#include <iterator>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
struct dump_val : public unary_function<int,void>
{
void operator()(int val)
{
cout << val << " ";
}
};
int main(){
int vals[5] = {1,2,3,4,5};
// version 1, using std::copy and ostream_iterator
copy(&vals[0], &vals[5], ostream_iterator<int>(cout, " "));
cout << endl;
// version 2, using a simple hand-written loop
for( size_t i = 0; i < 5; ++i )
cout << vals[i] << " ";
cout << endl;
// version 3, using C++0x lambdas
for_each(&vals[0], &vals[5], [](int val)
{
cout << val << " ";
}
);
cout << endl;
// version 4, with elements in a vector and calling a functor from for_each
vector<int> vals_vec;
vals_vec.push_back(1);
vals_vec.push_back(2);
vals_vec.push_back(3);
vals_vec.push_back(4);
vals_vec.push_back(5);
for_each( vals_vec.begin(), vals_vec.end(), dump_val() );
cout << endl;
}
When you pass around an array of X it's really a pointer to an array of X that you're passing around. So when you pass values to cout it only has the pointer to print out.
You really should look into using some of the standard algorithms to make your life simpler.
For example to print all the elements in an array you can just write
std::copy(values, values+MAX, std::ostream_iterator<int>(std::cout, "\n"));
To find the max element you could just write
int mval = *std::max_element(values, values+MAX);
So your code becomes
#include <iostream>
using namespace std;
int main(){
const int MAX = 100;
int values[MAX];
char ivals[256];
// Get the space-separated values from user input.
cin.getline(ivals, 256, '0');
char *helper;
// Clean input array and transfer it to values.
for(int i = 0; i < (MAX) && ivals[i] != 0; i++){
helper = ivals[i * 2];
values[i] = atoi(helper);
}
copy(values, values+MAX, ostream_iterator<int>(cout, "\n"));
cout << *std::max_element(values, values+MAX);
return 0;
}
Doing this removes the need for your findMax method altogether.
I'd also re-write your code so that you use a vector instead of an array. This makes your code even shorter. And you can use stringstream to convert strings to numbers.
Something like this should work and is a lot less code than the original.
int main(){
vector<int> values;
char ivals[256];
// Get the space-separated values from user input.
cin.getline(ivals, 256, '0');
int temp = 0;
stringstream ss(ivals);
//read the next int out of the stream and put it in temp
while(ss >> temp) {
//add temp to the vector of ints
values.push_back(temp);
}
copy(values.begin(), values.end(), ostream_iterator<int>(cout, "\n"));
cout << *std::max_element(values.begin(), values.end());
return 0;
}
Array of int is promoted to a pointer to int when passed to a function. There is no operator << taking ordinary array. If you want to use operator << this way, you need to use std::vector instead.
Note: it is possible technically to distinguish array when passed to a function using template, but this is not implemented for standard operator <<.
for(int i = 0; i < (sizeof(arr)/sizeof(int)); i++){
sizeof(arr) here is the size of the pointer to the array. C++ will not pass the actual array, that would be grossly inefficient. You'd typically only get one pass through the loop. Declare your function like this:
int findMax(int* arr, size_t elements) {
//...
}
But, really, use a vector.
Oh, hang on, the question. Loop through the array and print each individual element.