I'm working on a random exercise from my C++ book because I'm "re-learning" C++, but I'm getting some odd output from a program I wrote. I'm fairly certain there are no errors in the logic of the program, but where the sum of the elements in the "scoreCount" array should be 26, the same as the length of the scores array, it is only 20. I can't figure out what happened to the other 6 elements. The description of the exercise is in the code below. Can anyone spot what I might have done wrong?
/* Exercise 09 - 04
Write a program that reads a file consisting of students' test scores
in the range 0-200. It should then determine the number of students having
scores in each of the following ranges: 0-24, 25-49, 50-74, 75-99,
100-124, 125-149, 150-174, and 175-200. Output the score ranges and the
number of students. (Run your program with the following input data:
76, 89, 150, 135, 200, 76, 12, 100, 150, 28, 178, 189, 167, 200, 175,
150, 87, 99, 129, 149, 176, 200, 87, 35, 157, 189.) */
#include <cstdio>
int main(int argc, char ** argv) {
int scores[] = {76, 89, 150, 135, 200, 76, 12, 100, 150, 28, 178, 189,
167, 200, 175, 150, 87, 99, 129, 149, 176, 200, 87,
35, 157, 189};
int size = sizeof(scores) / sizeof(scores[0]);
int scoreCount[] = {0, 0, 0, 0, 0, 0, 0, 0};
printf("Number of Scores: %d\n\n", size);
for(int i = 0; i < size; i++) {
scoreCount[((int)(scores[i]/25))] += 1;
printf("%d - scoreCount Index: %d\n", i, ((int)(scores[i]/25)));
}
printf("\n");
int low = 0;
int high = 24;
size = sizeof(scoreCount) / sizeof(scoreCount[0]);
for(int i = 0; i < size; i++) {
printf("Range %d-%d: %d\n", low, high, scoreCount[i]);
low += 25;
high += 25;
if(high == 199) high = 200;
}
int sum = 0;
for(int i = 0; i < size; i++) {
sum += scoreCount[i];
}
if(sum < 26) printf("\n%d: Wrong number of scores counted.\n", sum);
else printf("\nAll students accounted for.\n");
return 0;
}
Thanks for any help!
Here's proper C++ style. I know the question has already been answered, but here's a bonus:
See it live on http://ideone.com/rBTi42
#include <vector>
#include <map>
#include <iostream>
int main(int argc, char ** argv)
{
const std::vector<int> scores = {76, 89, 150, 135, 200, 76, 12, 100, 150, 28, 178, 189,
167, 200, 175, 150, 87, 99, 129, 149, 176, 200, 87,
35, 157, 189
};
std::map<int, int> scoreCount;
std::cout << "Number of Scores: " << scores.size() << "\n";
for(auto score : scores)
{
scoreCount[score/25] ++;
std::cout << score << " - scoreCount Index: " << score/25 << "\n";
}
for(auto const& slot : scoreCount)
{
auto low = slot.first*25;
auto high = low+24;
std::cout << "Range " << low << "-" << high << ": " << slot.second << "\n";
}
int sum = 0;
for(auto const& slot : scoreCount)
sum += slot.second;
if(sum < 26)
printf("\n%d: Wrong number of scores counted.\n", sum);
else
printf("\nAll students accounted for.\n");
}
scoreCount[((int)(scores[i]/25))] += 1;
This would produce 8 if score[i] is 200. And currently your code does not handle this.
200 / 25 = 8 and
scoreCount[8] does not exist.
You are generating an index out of bounds for scoreCount here:
scoreCount[((int)(scores[i]/25))] += 1;
The valid indexes for scoreCount are from 0 to 7 but with your current scores you will generate indexes up to 8. A solution would be to extend scoreCount by one element or to check if the index is 8 and map it to index 7 since it seems like the problem limits your ranges.
The number of elements should be 9 rather than 8 in the scoreCount array.
As 200/25 will be evaluated to 8 and it results in index out of bound
EDIT:
As suggested by Andrew_CS, the element having value as 200 shoud be added to the last group itself.
scoreCount[(scores[i]/25)==8?7:(scores[i]/25)] += 1;
I ran the code on my machine.
I got 23 out of 26.
The reason for this is that there are 3 values of 200.
When the value is 200 the it will be under 8.
You need to increase the number of elements in the scoreCount array because 200/25 gives 8 and scoreCount[8] does not exists .
200/25 = 8 is out of bounds for scoreCount - only has indexes 0 - 7.
I personally wouldn't increase the number of elements in scoreCount since there are only 8 groups of valid scores. I would instead check for this one case that produces 8 as an index.
for(int i = 0; i < size; i++){
int theIndex = (scores[i]/25);
if(theIndex == 8)
scoreCount[7] += 1;
else
scoreCount[theIndex] += 1;
printf("%d - scoreCount Index: %d\n", i, theIndex;
}
Related
I am working on a program which implements the inversion counting with merge sort algorithm.
When I test my program with given test cases. I experienced segmentation fault which I cannot find the reason.
One test case is shown in the following codes:
int inputArray[5] = {5,4,3,2,1};
inversionCount Inversion(inputArray, 5);
count = Inversion.totalinversionCount(0, 4);
The program gives the correct answer as 10.
Another test case is:
int inputArray[15] = {9, 12, 3, 1, 6, 8, 2, 5, 14, 13, 11, 7, 10, 4, 0};
inversionCount Inversion(inputArray, 15);
count = Inversion.totalinversionCount(0, 14);
The program gives an answer as 48, while the correct answer is 56. I tried to debug the program by printing the array[] elements in the class. It seems in the constructor the copied array[] is {9 12 3 1 6 8 2 5 14 13 11 7 10 4 0}. However, when the program steps into counting, the class member array[] changed to {0 12 3 1 6 8 2 5 14 13 11 7 10 4 0}. The first element changed to 0 from 9. I don't know why.
The last test case is:
int inputArray[100] = { 4, 80, 70, 23, 9, 60, 68, 27, 66, 78, 12, 40, 52, 53, 44, 8, 49, 28, 18, 46, 21, 39, 51, 7, 87, 99, 69, 62, 84, 6, 79, 67, 14, 98, 83, 0, 96, 5, 82, 10, 26, 48, 3, 2, 15, 92, 11, 55, 63, 97, 43, 45, 81, 42, 95, 20, 25, 74, 24, 72, 91, 35, 86, 19, 75, 58, 71, 47, 76, 59, 64, 93, 17, 50, 56, 94, 90, 89, 32, 37, 34, 65, 1, 73, 41, 36, 57, 77, 30, 22, 13, 29, 38, 16, 88, 61, 31, 85, 33, 54 };
inversionCount Inversion(inputArray, 100);
count = Inversion.totalinversionCount(0, 99);
The program runs into segmentation fault in the construction step. The debug shows the program pauses when copying Array[] to array[].
Signal received: SIGSEGV (Segmentation fault)
For program algorithm_design_i_week_1, pid 23,328
You may discard the signal or forward it and you may continue or pause the process
My program is given below. Please help me to find out the reason for segmentation fault. Thank you very much.
inversionCount.h
#ifndef INVERSIONCOUNT_H
#define INVERSIONCOUNT_H
#include <iostream>
using namespace std;
class inversionCount {
private:
int length;
int array[];
public:
inversionCount(int Array[], int Length);
int splitCount(int first, int mid, int last);
int totalinversionCount(int first, int last);
};
#endif /* INVERSIONCOUNT_H */
inversionCount.cpp
#include "inversionCount.h"
inversionCount::inversionCount(int Array[], int Length) {
length = Length;
for (int i = 0; i < length; i++)
array[i] = Array[i];
}
int inversionCount::splitCount(int first, int mid, int last) {
int first1 = first, last1 = mid;
int first2 = mid + 1, last2 = last;
int tempArray[length];
int i = first;
int totalSplitCount = 0;
while (i < last && first1 <= last1 && first2 <= last2) {
if (array[first1] < array[first2]) {
tempArray[i] = array[first1];
first1++;
i++;
}
else {
tempArray[i] = array[first2];
totalSplitCount += last1 + 1 - first1;
first2++;
i++;
}
}
while (first1 <= last1) {
tempArray[i] = array[first1];
first1++;
i++;
}
while (first2 <= last2) {
tempArray[i] = array[first2];
first2++;
i++;
}
for (int j = first; j < last + 1; j++)
array[j] = tempArray[j];
return totalSplitCount;
}
int inversionCount::totalinversionCount(int first, int last) {
int totalCount = 0;
if (first < last) {
int mid = (first + last) / 2;
totalCount = totalinversionCount(first, mid) + totalinversionCount(mid + 1, last) + splitCount(first, mid, last);
}
return totalCount;
}
countDriver.cpp
#include "inversionCount.h"
int main(int argc, char** argv) {
int inputArray[5] = {5,4,3,2,1};
inversionCount Inversion(inputArray, 5);
int count = 0;
count = Inversion.totalinversionCount(0, 4);
cout<<"The number of inversions is "<<count<<endl;
return 0;
}
int array[]; is not legal C++ as the definition of a member variable. Your compiler must allow it as an extension, but in that case it means "no space is allocated for the array, but we will do something like:
A* pA = static_cast<A*>(malloc(sizeof(A) + Length*sizeof(int));
You are not doing this, so when you write to the array, you overwrite some random bits of memory, so bad stuff happens.
The best bet is to use std::vector.
class inversionCount {
private:
std::vector<int> array;
public:
inversionCount(int Array[], int Length) : array(Array, Array+Length) {}
int splitCount(int first, int mid, int last);
int totalinversionCount(int first, int last);
};
One other comment: it is much better to use size_t as the type of lengths and offsets into arrays and containers - it is what the C++ library uses. size_t is an unsigned type so by using the same type as the library, you avoid difficult problems with 'signed/unsigned mismatch'. (The effects are often not what you would expect.)
I have two programs, compiled with g++ and executed on linux. Program 1 creates a 2D array and then measures how long it takes to access all of its elements 100000 times:
#include <time.h>
#include <iostream>
int main()
{
clock_t time;
int i, y, x;
int matrix[9][9]{{ 0, 1, 2, 3, 4, 5, 6, 7, 8},
{ 9, 10, 11, 12, 13, 14, 15, 16, 17},
{18, 19, 20, 21, 22, 23, 24, 25, 26},
{27, 28, 29, 30, 31, 32, 33, 34, 35},
{36, 37, 38, 39, 40, 41, 42, 43, 44},
{45, 46, 47, 48, 49, 50, 51, 52, 53},
{54, 55, 56, 57, 58, 59, 60, 61, 62},
{63, 64, 65, 66, 67, 68, 69, 70, 71},
{72, 73, 74, 75, 76, 77, 78, 79, 80}};
time = clock();
for (i = 0; i < 100000; i++)
{
for (x = 0; x < 9; x++)
{
for (y = 0; y < 9; y++)
{
matrix[x][y];
}
}
}
time = clock() - time;
std::cout << "Clicks: " << time << std::endl;
std::cout << "Time taken: " << (double) time / CLOCKS_PER_SEC << "s" << std::endl;
}
Program 2 creates a 1D array and also measures how long it takes to access all of its elements 100000 times:
#include <time.h>
#include <iostream>
int main()
{
clock_t time;
int i, j;
int vector[81] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62,
63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80};
time = clock();
for (i = 0; i < 100000; i++)
{
for (j = 0; j < 81; j++)
{
vector[j];
}
}
time = clock() - time;
std::cout << "Clicks: " << time << std::endl;
std::cout << "Time taken: " << (double) time / CLOCKS_PER_SEC << "s" << std::endl;
}
After executing program 1 my output is:
Clicks: 8106
Time taken: 0.008106s
After executing program 2 my output is:
Clicks: 15958
Time taken: 0.015958s
It is my understanding that a 1D array is stored in a continuous block of memory. Likewise the rows of a static 2D array are stored in contiguous blocks of memory. Conversely the rows of a dynamic 2d array might not be stored in contiguous blocks of memory. If this is true then program 2 should be at least similar in speed to program 1 therefore my question is why would program 1 be remarkably faster than program 2?
Here is what I found:
If you actually make use of the value then the run time is almost the same, for example, change matrix[x][y]; to matrix[x][y] += 1; and vector[j]; to vector[j] += 1;
> Clicks: 28519
> Time taken: 0.028519s
and
> Clicks: 29941
> Time taken: 0.029941s
Without the above changes, optimize while compiling, g++ -O3 <filename>.cpp, this results in same time, got the same following output for both programs:
$./a.out
> Clicks: 2
> Time taken: 2e-06s
So, what you are pointing out is compiler optimizations.
The loops are likely to be removed (kind of optimising) by compiler, because
You actually did nothing in loops.
The matrix can be treated as a const array.
program 1 is faster than program 2. ( :< )
To see whether the deletion happens to your code during compiling, you can increase the most outer loop by 100 times, and see whether the time needed for execution is increased significantly (not necessarily by exact 100 times).
If true, you can prevent this kind of optimising by doing some actual works in loop (calculate the sum, and don't forget printing it afterwards) and introduce some "unpredictable" changes to your matrix, for example:
srand(10);
for (int i=0; i<9; ++i) {
matrix[i][i] = rand()%100;
}
And further, compiler may conduct some other optimising to your code, for example, expand your loops, even the address of the element you are visiting (they are no longer calculated at run time), you can prevent this by making the executing times of loops "unpredictable" :
#include <chrono>
#include <iostream>
#include <cstdlib>
int array[100];
int array2[10][10];
int64_t Sum1D(int len) {
int64_t sum = 0;
for (int i=0; i<100000; ++i) {
for (int j=0; j<len; ++j) {
sum += array[j];
}
}
return sum;
}
int64_t Sum2D(int len1, int len2) {
int64_t sum = 0;
for (int i=0; i<100000; ++i) {
for (int j=0; j<len1; ++j) {
for (int k=0; k<len2; ++k)
sum += array2[j][k];
}
}
return sum;
}
int main()
{
for (int i=0; i<100; ++i) {
array[i] = rand();
array2[i%10][i/10] = rand();
}
auto time = std::chrono::steady_clock::now();
//int64_t sum = Sum1D(100);
int64_t sum = Sum2D(10,10);
auto duration = std::chrono::steady_clock::now()-time;
std::cout << sum << "!" << duration.count() << std::endl;
return 0;
}
which finally makes program1 slower than program2. ( :> )
#include <iostream>
using namespace std;
int f[33] = {3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54,
57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99};
int b[20] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85,
90, 95, 100};
int main (){
for (int x=100; x >= 1; x-- ){
if (x == f){
cout << "fizz" << endl;
} else {
if(x ==b){
cout << "buzz" << endl;
}else{
if(x==f & x==b){
cout << "fizzbuzz" << endl;
}else{
cout << x << endl;
}
}
}
}
}
I am still learning, so this may not be the best way to solve this problem. I just want to know wahts wrong with this code. Thanks
As others have pointed out, you've precomputed your multiples of 3 and 5 in arrays, but then doing direct comparisons between an int and these arrays - this will always fail (ISO C++ forbids comparison between pointer and integer). If you persist with precomputed arrays, you could use std::find or std::any_of to check if either array contains the current number.
However, you would likely gain more credibility if you also included knowledge of how to determine whether a number is divisible by 3 or 5 in your code, rather than pre-populate the multiples of 3 and 5. This is done with the modulo operator, %. Any number % x will return zero if it is naturally divisible by x.
There's another logical flaw in your code. In order to be divisible by both 3 and 5 (i.e. 15, since 3 and 5 are both primes), you will need to change the order of precedence of your checks such that the check for 15 is done first, otherwise you will never reach the fizbuzz branch (since the 3 and 5 branches would also be hit, instead).
Fizzbuzz is usually done incrementally from 1 to 100, but here's your original 'count down' fizzbuzz rewritten:
for (int x=100; x >= 1; x--){
bool isDiv3 = x % 3 == 0;
bool isDiv5 = x % 5 == 0;
if (isDiv3 && isDiv5){
cout << "fizzbuzz" << endl;
} else if (isDiv5) {
cout << "buzz" << endl;
} else if (isDiv3) {
cout << "fizz" << endl;
} else {
cout << x << endl;
}
}
It's also possible to eliminate one of the if branches, by running the printed fizz and buzz into eachother on a factor of 15, although this isn't necessarily as easy to read:
for (int x=100; x >= 1; x--){
bool isDiv3 = x % 3 == 0;
bool isDiv5 = x % 5 == 0;
if (isDiv3) {
cout << "fizz";
}
if (isDiv5) {
cout << "buzz";
}
if (!isDiv3 && !isDiv5)
cout << x;
}
cout << endl;
}
The error with your code is you can't compare integer and pointer , What you are trying to do is to find if x is in f or if x is in b or both .
But why do yo have to do that , you know the properties governing the sets f and b which are simply "%3==0" , "%5==0" .So you can do something pretty easy like
#include <iostream>
using namespace std;
int main (){
for (int x=100; x >= 1; x-- ){
if(x%3==0) cout<<"Fizz";
if(x%5==0) cout<<"Buzz";
else if(x%3 !=0) cout <<x;
cout<<endl;
}
}
x is an int, while f is an array. You cannot compare them this way:
if (x == f){
If your technique is to check whether x is in the array f, I suggest, you have to check for each value in f, like
if(x == f[i++]){
where i is an index used to traverse the f array.
Also, you might consider evaluating the condition of x in both f and b before their individual evaluation.
x is an integer whereas f and b are arrays of integers. If you want to test membership of the content of your variable x in the arrays f and b you probably want to define your own function to check it.
int is_in(int item, int[] list){
for(i = 0; i < sizeof(list) / sizeof(struct list); i++){
if(item==list[i]) return 1;
}
return 0;
}
And then change your conditions to if(is_in(x,b))
I'm currently coding a small heapify code that repeated runs bubble down but everytime it seems like nothing's happening. Not sure what's wrong here maybe I'm missing something?
template <class T>
void PriorityQueue<T>::heapify (int* arrs, int size){
int i = (size-1)/2;
while (i >= 0){
bubbleDown(arrs, i, (size));
i--;
}
}
template <class T>
void PriorityQueue<T>::bubbleDown (int* arrs, int i, int size)
{
//Each level node's are indexed at 2^(level) - 2 to 2^(level+2) - 2
//Children of these node's levels are indexed at 2i+1 and 2i+2
//The parent of node i, is indexed at (i-1)/2
int leftChildren = (2*i)+1;
int rightChildren = (2*i)+2;
int largest = i;
if (rightChildren < size)
{
if (arrs[leftChildren] < arrs[rightChildren]){
largest = rightChildren;
}
else{
largest = leftChildren;
}
if (arrs[i] > arrs[largest]){
largest = i;
}
}
else if (leftChildren < size)
{
if (arrs[i] < arrs[leftChildren]){
largest = leftChildren;
}
}
if (arrs[i] < arrs[largest])
{
int temp = arrs[i];
arrs[i] = arr[largest];
arrs[largest] = temp;
}
}
I'm calling it like this:
PriorityQueue<int> test;
int arr[] = {89, 29, 36, 48, 94, 13, 27, 70, 76, 37, 42, 58};
test.heapify(arr, 12);
for (int i = 0; i < 12; i++){
cout << arr[i] << endl;
}
Console prints out it the same way the array has been initialized.
UPDATED:
Still getting weird results
[89, -842150451, 36, 29, 94, 0, 27, 70, 48, 37, 42, 13]
The results I should be getting is
[94, 76, 89, 70, 48, 58, 13, 27, 36, 29, 37, 42, 23]
Basic typo error. Should really use more meaningful names
I am new to C++. I am trying to read through the array of numbers and count the amount of numbers in the array that are equal to the user entered number. I am not sure what to do next to get it to make number = number1 and count it. I hope this makes sense. Thanks.
#include <iostream>
using namespace std;
int main()
{
int number[20] = {80, 52, 25, 71, 56, 90, 87, 10, 32, 80, 2, 67, 73, 50, 52, 73, 72, 20, 86, 99};
int numberCount = 0;
int number1 = 0;
cout << "Enter a number between 0 and 100: ";
cin >> number1;
while(number1>100 || number1<0)
{
cout << "Invalid number,enter again" << endl;
cin >> number1;
}
for(i = 0; i < 20; i = i + 1)
{
}
system("pause");
return 0;
}
There's a function in the standard library for this, in the <algorithm> header:
int numberCount = std::count(number, number + 20, number1);
You just need to test whether number1 is equal to each value stored in the array. Using the variable i as an index, which you already have set up in the for loop, you can access the array's values one by one and compare with number1. If they match then you increment the counter variable.
for(i = 0; i < 20; i = i + 1)
{
// the next line tests whether the value of variable `number1` is equal
// to the value stored in the `number` array, at the index `i`
if(number1 == number[i])
{
numberCount += 1; // if there is a match, increment the counter
}
}
Compare each entry in the array 'number[]' against the number supplied by the user 'number1':
for (int i = 0; i < 20; i++)
{
if (number1 == number[i])
{
numberCount++;
}
}