array of scores - c

Given an array of scores where 60 is the highest and 36 is the passing. The function will return an array of all passing scores
#include <stdio.h>
#include <stdlib.h>
int* passingScores (int scores[], int size);
int main () {
int B[] = {55, 35, 60, 25, 10, 43}; //expect display 55,60,43
int size = 6;
int* C;
int i;
C = passingScores(B, size);
for (i=0; i<size; i++) {
printf ("%d\n", C[i]);
}
return 0;
}
code of function:
int* passingScores (int scores[], int size) {
int i;
int passingScore = 36;
int* pass;
pass = (int*)malloc(sizeof(int)*size);
if (pass != NULL) {
for (i=0; i<size; i++) {
if (scores[i] > passingScore){
pass[i] = scores[i];
}
}
}
return pass;
}
elements in the array in main are:
55, 35, 60, 25, 10, 43
the result after the function call would be:
55, 0, 60, 0, 0, 43
but I wanted to have a result like:
55, 60, 43
pls help :) thank you!

For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
You should not use magic numbers like in this declaration
int size = 6;
The size of the original array can be calculated.
The function passingScores does not change the original array. So its first parameter should be declared with the qualifier const like
const int scores[]
The user of the function need to know how many elements were passed the test. So it is better when the function returns the number of the passed scores and accepts the pointer to the potentially allocated array from the user by reference.
Instead of the magic number 36 declared within the function
int passingScore = 36;
it is better to pass such a number as a function argument. In this case the function will be more flexible.
You are allocating redundant memory in the function. You should at first count the number of the passed scores. The original array of scores can be very big but its elements that passed the test can be very few.
And for the array pointed to by the pointer pass you need to use a separate index to store selected values sequentially.
And do not forget to free the allocated memory.
Here is a demonstrative program that shows how the function can be implemented.
#include <stdio.h>
#include <stdlib.h>
size_t passingScores( const int scores[], size_t size, int passingScore, int **passed );
int main( void )
{
int scores[] = { 55, 35, 60, 25, 10, 43 };
const size_t SIZE = sizeof( scores ) / sizeof( *scores );
int passingScore = 36;
int *passed_scores = NULL;
size_t n = passingScores( scores, SIZE, passingScore, &passed_scores );
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", passed_scores[i] );
}
putchar( '\n' );
free( passed_scores );
return 0;
}
size_t passingScores( const int scores[], size_t size, int passingScore, int **passed )
{
size_t n = 0;
for ( size_t i = 0; i < size; i++ )
{
n += passingScore < scores[i];
}
if ( n != 0 )
{
*passed = malloc( n * sizeof( int ) );
if ( *passed != NULL )
{
for ( size_t i = 0, j = 0; i < size; i++ )
{
if ( passingScore < scores[i] ) ( *passed )[j++] = scores[i];
}
}
}
return n;
}
The program output is
55 60 43

The following code includes several suggestions, including adding an additional index to keep track of only passing scores, and using calloc instead of malloc to initialize the array. (see other comments and suggested changes below.)
int* passingScores (int scores[], int size);
int main (void) // Or use: int main(int argc, char *argv[]){...}
{ //But never: int main(){...}
int B[] = {55, 35, 60, 25, 10, 43}; //expect display 55,60,43
//int size = 6;//do not use magic numbers
int size = sizeof(B)/sizeof(B[0]);//yields number of elements in array B
int* C;
int i;
C = passingScores(B, size);
if(C)//test before using
{
for (i=0; i<size; i++) {
if(C[i] != 0) printf ("%d\n", C[i]); //include only passing scores
//(excluding zeros)
}
free(C);//free memory when done.
}
return 0;
}
int* passingScores (int scores[], int size) {
int i, j = 0;//additional index j to track passing scores.
int passingScore = 36;
int* pass;
//pass = (int*)malloc(sizeof(int)*size);//allocates un-initialized memory
pass = calloc(size, sizeof(int));//calloc initializes memory to zero
if (pass != NULL) {
for (i=0; i<size; i++) {
if (scores[i] > passingScore){
pass[j] = scores[i];
j++;//indexed only when passing score
}
}
}
return pass;
}
Some notes on using calloc/malloc...
For your purposes, the contents of memory allocated using malloc is provided as is, including whatever contents happened to occupy that space before your process was granted ownership. On my machine and using malloc, the space is occupied with:
pass[0] == 0xBAADFOOD (-1163005939)
pass[1] == 0xBAADFOOD
pass[2] == 0xBAADFOOD
pass[3] == 0xBAADFOOD
pass[4] == 0xBAADFOOD
pass[5] == 0xBAADFOOD
So, the way in which you are selectively writing to some elements of that memory would leave that original content in some of the other areas of that memory block, causing problems when outputting the results.
When using malloc in this way it is recommended to initialize the memory before using:
pass = malloc(size * sizeof(int));
if(pass)
{
memset(pass, 0, size*sizeof(int));
...
Resulting in:
pass[0] == 0x00000000
pass[1] == 0x00000000
pass[2] == 0x00000000
pass[3] == 0x00000000
pass[4] == 0x00000000
pass[5] == 0x00000000
Using calloc allocates the memory just as malloc does, but then clears it before returning, saving the need for you to clear it with memset.
Note also it is not necessary, or recommended to cast the return of [m][c]alloc.

The problems lies with this statement:
pass[i] = scores[i];
You don't want to copy the score into the element with the same index; you want to copy it into the first "free" slot. You'll need to keep track of how elements of pass are being used.
There's a second problem: You output size numbers, even if there are fewer passing grades.
In this case, rather than having to communicate the number of elements in the returned array to the caller, we could simply place a 0 at the end to indicate the end. But we have to be careful of the case where all the grades are passing grades!
A minor third problem: You are considering a grade of 36 to be a failing grade! Let this be a lesson in testing: Whenever you do testing, always test at and around the limits (so you'd test with scores of 35, 36 and 37 in this case).
Finally, you dynamically allocate an array, but you never free it. It's not critical that you free it because you'd do so just before exiting the program, but that's a bad habit to get into. (One possible consequence is that it would cause the output of tools such as valgrind to become very noisy if you decide to use it to help resolve a crash.)
#include <stdio.h>
#include <stdlib.h>
int* getPassingScores(const int* scores, int num_scores) {
const int passingScore = 36;
// calloc is like malloc, but the memory will
// be efficiently initialized to 0. This means
// we don't need to do pass[j] = -1; later.
// Need to make sure we have enough space
// when all the grades are passing grades!
int* pass = calloc(num_scores, sizeof(int));
if (!pass)
return NULL;
for (int i=0, j=0; i<num_scores; ++i) {
if (scores[i] >= passingScore) {
pass[j++] = scores[i];
}
}
return pass;
}
int main(void) {
int scores[] = {55, 35, 60, 25, 10, 43};
int num_scores = sizeof(scores)/sizeof(*scores);
int* passingScores = getPassingScores(scores, num_scores);
for (int i=0; passingScores[i]>0; ++i) {
printf("%d\n", passingScores[i]);
}
free(passingScores);
return 0;
}
Of course, the following would suffice:
#include <stdio.h>
int main(void) {
int scores[] = {55, 35, 60, 25, 10, 43};
int num_scores = sizeof(scores)/sizeof(*scores);
const int passingScore = 36;
for (int i=0; i<num_scores; ++i)
if (scores[i] >= passingScore)
printf("%d\n", scores[i]);
}

Related

multi pointers in function in c

i'm not good at english.
i declare array and two pointers.
the maxPtr pointer should have array arr's maximum number adress.
and minPtr pointer should have array arr's minimum number adress.
so i declare the function and this has two double-pointer to give maxPtr and minPtr proper adress.
but whenever i run this code, the program is not fully run.
it doesn't output the result( printf("%d",*maxPtr) ,printf("%d", *minPtr, printf("Hi");
this program is run at vscode in mac.
what make it error?
#include <stdio.h>
void MaxAndMin(int* str,int** max, int** min)
{
int i;
int maxnum=0,minnum=0;
for(i=0; i<5; i++)
{
if(maxnum< str[i])
{
maxnum =str[i];
*max = &str[i];
}
if(minnum > str[i])
{
minnum = str[i];
*min = &str[i];
}
}
}
int main(void)
{
int i,len;
int* maxPtr;
int* minPtr;
int arr[5]={};
for(i=0; i<5; i++)
{
printf("%d번째 정수입력 입니다.",i+1);
scanf("%d", &arr[i]);
}
MaxAndMin(arr,&maxPtr,&minPtr);
printf("%d",*maxPtr);
printf("%d",*minPtr);
printf("Hi");
return 0;
}
the result is
> Executing task: ./test <
1번째 정수입력 입니다.1
2번째 정수입력 입니다.2
3번째 정수입력 입니다.3
4번째 정수입력 입니다.4
5번째 정수입력 입니다.5
Terminal will be reused by tasks, press any key to close it.
For starters this initialization of an array
int arr[5]={};
is incorrect in C. You have to write
int arr[5]={ 0 };
Secondly using the magic number 5 within the function makes the function useless in general. You need to pass to the function the size of the array.
The initial value 0
int maxnum=0,minnum=0;
of these variables makes the function even more less useful. In general the array can contain either all elements positive or all elements negative.
And you need to flush the output buffer using for example the new line character '\n' in calls of printf.
The function can be declared and defined the following way as it is shown in the demonstration program below.
#include <stdio.h>
void MaxAndMin( const int a[], size_t n, int **max, int **min )
{
*max = ( int * )a;
*min = ( int * )a;
for ( size_t i = 1; i < n; i++ )
{
if ( **max < a[i] )
{
*max = ( int *)( a + i );
}
else if ( a[i] < **min )
{
*min = ( int * )( a + i );
}
}
}
int main( void )
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const size_t N = sizeof( a ) / sizeof( *a );
int *maxPtr = NULL;
int *minPtr = NULL;
MaxAndMin( a, N, &maxPtr, &minPtr );
printf( "The maximum value is %d at position %tu\n",
*maxPtr, maxPtr - a );
printf( "The minimum value is %d at position %tu\n",
*minPtr, minPtr - a );
}
The program output is
The maximum value is 9 at position 9
The minimum value is 0 at position 0
Pay attention to that the first parameter of the function should have the qualifier const because passed arrays to the function are not changed within the function.
The main issue is that the minnum is set at zero, which would only work if array had a negative value.
Setting minimum = star[0] also would not work!!! Because in the case of str[0] having negative value, *min never gets changed.
Also, I recommend to always initialize all variables in the declaration, especially pointers (because they may theoretically cause accidental access to memory).
Full solution:
#include <stdio.h>
int MaxAndMin(int* str, int** max, int** min)
{
int i;
int maxnum = 0;
int minnum = str[0] + 1;
for(i=0; i<5; i++)
{
if(maxnum < str[i])
{
maxnum = str[i];
*max = &str[i];
}
if(minnum > str[i])
{
minnum = str[i];
*min = &str[i];
}
}
return 0;
}
int main(void)
{
int i = 0;
int len = 0;
int* maxPtr = NULL;
int* minPtr = NULL;
int arr[5]={};
for(i=0; i<5; i++)
{
printf("Enter number %d: ",i+1);
scanf("%d", &arr[i]);
}
MaxAndMin(arr, &maxPtr, &minPtr);
printf("%d",*maxPtr);
printf("%d",*minPtr);
printf("Hi");
return 0;
}

how can I use less variables in my program?

I had to make a program that have an array of numbers, and then I need to make a function that get the arr[0] and the length of the array, and then it will print all the numbers without the duplicate ones.
I made this program and it worked good but I feel like I used too much variables for this program. (I started to learned in the last few weeks so its not looks very good)
#include <stdio.h>
#define N 10
void print_set(int *arr, int n) {
int i = 1;
int duplicate_num, check_num, count;
printf(" %d", *arr); //printing the first number (arr[0]).
//starting to check the other number. if they new I'll print them. (start from arr[1]).
arr++;
while (i < n) {
if (*arr != duplicate_num) {
printf(" %d", *arr);
check_num = *arr;
// becouse I found new number, I change it no be equal to the first duplicate_num. (if there are more like him, I change them too).
while (i < n) {
if (*arr == check_num) {
*arr = duplicate_num;
}
arr++;
i++;
count++;
}
i = i - count;
arr = arr - count;
count = 0;
}
arr++;
i++;
}
}
int main() {
int arr[N] = {4, 6, 9, 8, 6, 9, 6, 1, 6, 6};
print_set(&arr[0], N);
return 0;
}
output for this program: 4 6 9 8 1
I'll be happy to see good method to make this program less messy.
For starters the function has undefined behavior. The user can pass 0 as the second argument. It means that the array is empty and has no elements. In this case the expression *arr is undefined.
The second problem is using the uninitialized variable duplicate_num in this if statement
if (*arr != duplicate_num) {
and the uninitialized variable count
count++;
Another problem is that the function changes the array
if (*arr == check_num) {
*arr = duplicate_num;
}
If you need only to output unique values in an array then the source array shall not be changed.
The function can be defined for example the following way
void print_set( const int *a, size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
size_t j = 0;
while ( j != i && a[i] != a[j] ) ++j;
if ( j == i ) printf( "%d ", a[i] );
}
putchar( '\n' );
}

Why is there only one strange element in array in heap memory in C but other are ok?

I made a program to separate one main array with integers into two dynamically allocated arrays with odd and even integers.
Everything is good except one element in both of the odd and even arrays, which you can see in the output picture. I hope you understand what I mean. Also any tips on improving the code are very welcomed. Thanks in advance :)
Code:
#include <stdio.h>
#include <stdlib.h>
void printArr(int * arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n\n");
}
int main() {
int arr[] = { 7689, 6534, 456, 67, 7652, 879, 544, 12, 4345, 867, 44, 23545, 8, 6787, 34, 26, 56, 3, 41, 6 };
int size = sizeof(arr) / sizeof(arr[0]);
int *arrPtr = arr;
int *oddArr = malloc(sizeof(int));
if (oddArr == NULL) {
return 1;
}
int oddArrSize = 0;
int *evenArr = malloc(sizeof(int));
if (evenArr == NULL) {
return 1;
}
int evenArrSize = 0;
for (int i = 0; i < size; i++) {
if (arr[i] % 2 == 0) {
oddArr = realloc(oddArr, sizeof(oddArr) + sizeof(int));
if (oddArr == NULL) {
return 1;
}
oddArr[oddArrSize] = arr[i];
oddArrSize++;
}
else {
evenArr = realloc(evenArr, sizeof(evenArr) + sizeof(int));
if (evenArr == NULL) {
return 1;
}
evenArr[evenArrSize] = arr[i];
evenArrSize++;
}
}
printf("Main arr: \n");
printArr(arrPtr, size);
printf("Odd arr: \n");
printArr(oddArr, oddArrSize);
printf("Even arr: \n");
printArr(evenArr, evenArrSize);
free(oddArr);
free(evenArr);
}
Output:
Output
You're not growing the arrays correctly with realloc().
oddArr = realloc(oddArr, sizeof(oddArr) + sizeof(int));
sizeof(oddArr) is the size of the pointer, not the size of the array it points to. So every time you call realloc() you're allocating the same size array, not increasing the size.
That needs to be:
oddArr = realloc(oddArr, (oddArraySize + 1) * sizeof(int));
And you have to do the same thing for the even array.
evenArr = realloc(evenArr, sizeof(evenArr) + sizeof(int)); is incorrect, as that is always allocating the same size, since sizeof(evenArr) is constant. You want:
evenArr = realloc(evenArr, evenArrSize * sizeof *evenArr);
and you'll need to increment evenArrSize correctly, as well. As in, you need to increment it before you call realloc, not after. Although it is a bit atypical to increment by one and realloc for every datapoint. A common pattern is to double the size only when needed, or increment by a chunk size larger than 1.

C-Array Sum using Pointers?

I made this program to find the sum of an array using pointer, but it crashes when I run it. Why is this happening and what did I do wrong?
int GetValue(int *p[], int size)
{
int i, sum = 0;
for(i = 0 ; i < size ; i++)
{
sum += *p[i];
}
return sum;
}
int main()
{
int Array[6] = { 20, 30, 40, 50, 60, 70 };
int Array_Sum;
Array_Sum = GetValue(&Array[6], 6);
printf("Array Sum= %d", Array_Sum);
return 0;
}
This ...
int Array[6] = { 20, 30, 40, 50, 60, 70 };
declares 'Array' as an array of 6 int. Note well that the declared name is 'Array', not 'Array[6]'. The latter expression, outside the context of a declaration, would designate the element at index 6 in that array if the array were long enough, but the array is not long enough, having only 6 elements, at indices 0 - 5.
If, again, the array were long enough, &Array[6] would evaluate to the address of the seventh element of Array (at index 6), but you presumably want to pass the address of the first element (at index 0). The expression &Array[0] would be one way to write that, but most people would instead simply write Array, which is completely equivalent. That is, you should call your function like so:
Array_Sum = GetValue(Array, 6);
You furthermore have a problem with your GetValue() function:
int GetValue(int *p[], int size) {
[...]
Parameter p is declared as a pointer to pointer to int. That is, the function signature is exactly equivalent to
int GetValue(int **p, int size) {
But what you're actually passing (and indeed what you want to pass) is an int *. You can write that either like this ...
int GetValue(int *p, int size) {
... or if you prefer, like this ...
int GetValue(int p[], int size) {
. Having done so, inside the function you should access the array elements as p[i], not *p[i].
Correction needed is here:
p[i] means *(p+i)
so,
*p[i] means **(p+i)
corrected function:
int GetValue(int *p, int size) //*p[] is for passing a 2D array ,pass 1D only as your need
{
int i, sum = 0;
for(i = 0 ; i < size ; i++)
{
sum += p[i]; //correction here that's why it crashes
}
return sum;
}
as p already is a pointer no need to derefence it.
live demo here http://ideone.com/kI1hXA
Thanks #JohnBollinger for pointing its 2D argument in getValuefunction in question.
I changed some things in your code
int GetValue(int *p, int size)
{
int i, sum = 0;
for(i = 0 ; i < size ; i++)
{
sum += p[i];
}
return sum;
}
int main()
{
int Array[6] = { 20, 30, 40, 50, 60, 70 };
int Array_Sum;
Array_Sum = GetValue(&Array[0], 6);
printf("Array Sum= %d", Array_Sum);
return 0;
}
The code is to be changed to -
int GetValue(int p[], int size)
{
int i, sum = 0;
for(i = 0 ; i < size ; i++)
{
sum += p[i];
}
return sum;
}
int main()
{
int Array[6] = { 20, 30, 40, 50, 60, 70 };
int Array_Sum;
Array_Sum = GetValue(Array, 6);
printf("Array Sum= %d", Array_Sum);
return 0;
}

Strange output from Counting Sort in C

I have the following Counting Sort function
/*
*File: countingSort.c
*Description: A counting sort subroutine. Takes as input an array of integers.
* an array length and a range. All values in the input array must fall within [0, range].
* Takes O(range + arrayLen) time and O(range + arrayLen) extra space
*
*/
#include "countingSort.h"
int* countingSort(int unsorted[], int arrayLen, int range) {
int store[range + 1];
int sorted[arrayLen];
for ( int i = 0; i <= range; i++ ) {
store[i] = 0;
}
for ( int i = 0; i < arrayLen; i++ ) {
sorted[i] = 0;
}
for ( int j = 0; j < arrayLen; j++ ) {
store[unsorted[j]] ++;
}
for ( int i = 1; i <= range; i++ ) {
store[i] += store[i-1];
}
for( int j = arrayLen - 1; j >= 0; j-- ) {
sorted[store[unsorted[j]]] = unsorted[j];
store[unsorted[j]] --;
}
return sorted;
}
The function is giving me really strange output. The output is nothing like the input most of the times but sometimes it just works.
Why is this happening?
I am calling it from another file called cSortTest.c.
That file looks like this
/*
*File: cSortTest.c
*Description: Tests countingSort.c
*
*/
#include <stdio.h>
#include "countingSort.h"
int main() {
int data[8] = { 2, 1, 9, 4, 4, 56, 90, 3 };
int* p;
p = countingSort(data, 8, 90);
for ( int i = 0; i < 8; i++ ) {
printf("%d Element: %d\n", i, *(p+i) );
}
}
You are returning a local array variable. This variable is destroyed when the function exits, making the address to it no longer safe or valid to access. In fact accessing it will give you what is called undefined behavior, which explains why it sometimes appears to "work".
This is a classic beginner's mistake in C. You must either have the caller pass in the desired destination array, or use malloc() to allocate "persistent" heap memory and return that:
int* countingSort(int unsorted[], int arrayLen, int range) {
int *sorted = malloc(arrayLen * sizeof *sorted );
if (sorted== NULL)
return NULL;
/* rest of sorting */
return sorted;
}
The arrayLen * sizeof *sorted expression computes the number of bytes required for the allocation. There's no need to use calloc() which clears the memory; you're going to overwrite each element so clearing it is just wasted effort.

Resources