1

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!

alinsoar
  • 15,386
  • 4
  • 57
  • 74
  • Count how many that passed, allocate accordingly, then copy only those values. – Lundin Jan 29 '20 at 13:51
  • You want that result to be printed or stored? – EUS Jan 29 '20 at 13:51
  • (1) count the passing scores (2) allocate an array large enough to hold only those (3) make a second pass over the array, copying only the passing scores. You need two different indices, one for the input array and one for the array of passing scores. Also, change `> passingScore` to `>= passingScore`, otherwise you'll reject scores with value 36 as you do now. – Tom Karzes Jan 29 '20 at 13:55
  • Suggestion: Change `int size = 6;` to `int size = sizeof(B)/sizeof(B[0]);`. And `pass = (int*)malloc(sizeof(int)*size);` to `pass = malloc(sizeof(int)*size);`. ( [casting return of malloc is not recommended in C](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) ) – ryyker Jan 29 '20 at 14:02
  • 1
    Are you allowed to modify the prototype (return type and parameters) of `passingScores`, or is it not to be modified? The current prototype provides no means for the caller to determine the length of the returned array unless some special value (such as `-1`) is added to the end of the array. – Ian Abbott Jan 29 '20 at 14:17
  • OT: regarding: `pass = (int*)malloc(sizeof(int)*size);` 1) the returned type is `void*` which can be assigned to any pointer. Casting just clutters the code (and is error prone) 2) the parameter to `malloc()` is expected to be all of type `size_t` (I.E. unsigned long)` so this statement will cause the compiler to output a warning about the implicit conversion. 3) When `pass` is NULL, then should output to `stderr` an error message and when the error is from a C library function, should also output to `stderr`, the text reason the system thinks the error occurred. Suggest `perror()` – user3629249 Jan 30 '20 at 09:06

3 Answers3

1

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
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

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.

ryyker
  • 22,849
  • 3
  • 43
  • 87
-1

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]);
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 1
    Do you think it is appropriate to do someone else's homework? – Paul Ogilvie Jan 29 '20 at 14:40
  • 1
    @PaulOgilvi, Never! Which is why I simply provided tiny fixes (`i`⇒`j++`, `size`⇒`size+1`, `>`⇒`>=`, `for`⇒`while`, added `free`) to an already-written program, along with explanations for the changes. That's the entire point of this site. Of course it's part of someone's work (home or business), but I didn't do it for them. I just made tiny corrections. – ikegami Jan 30 '20 at 04:24
  • @PaulOgilvie - Totally irrelevant question. And, by the way, asked where there is a conflict of interest because you also have a stake in this question. Who cares if this is a student, a teacher, fireman, inmate, or engineer. The information presented in this answer, not only answers the question, but is well organized, point by point. By far the most instructive answer in the set. But you failed to say anything about that. IMO it deserves your up-click, not your dig. – ryyker Jan 30 '20 at 15:48
  • @ryyker, the answer is excellent and complete, which I would expect from a 291K user. The point is that doing someone's homework _does not let them learn_. It should have been limited to giving hints and maybe code snippets, but not complete solutions. – Paul Ogilvie Jan 30 '20 at 15:51
  • 1
    @PaulOgilvie Yet you provided a complete solution to one of the problems you identified. – ikegami Jan 30 '20 at 15:52
  • Hmm...according to me I left out a lot, which I gave as hints in the text. Maybe we should have a code of conduct at Stack Overflow of how to handle homework? – Paul Ogilvie Jan 30 '20 at 15:55
  • With respect, Lots of different learning styles are being recognized out there since you and I were in school @Paul Ogilvie. And neither of us can possibly know which learning style OP is. I personally learn tons from seeing good examples. It does not mean I will fail to gain a concept by observing a well done complete example of code. All of that aside, asking this particular question in the same post where you also helped OP to do homework (although to a smaller scale,) appears self-serving. – ryyker Jan 30 '20 at 16:01